Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix: if reading from the socket closed by peer, the next read from… #43

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ set_property(SOURCE ${lthread_files} PROPERTY COMPILE_FLAGS "-O2")
install(TARGETS lthread DESTINATION lib)
install(FILES src/lthread.h DESTINATION include)

set(UNIT_TEST_PATH ${CMAKE_SOURCE_DIR}/tests)
set(UNIT_TEST_PATH ${CMAKE_BINARY_DIR}/tests)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${UNIT_TEST_PATH})
include_directories(src)

Expand All @@ -31,6 +31,14 @@ target_link_libraries(lthread_io lthread pthread)
add_executable(lthread_join tests/lthread_join.c)
target_link_libraries(lthread_join lthread pthread)

add_executable(lthread_fdeof_read tests/lthread_fdeof_read.c)
target_link_libraries(lthread_fdeof_read lthread pthread)

add_executable(lthread_fdeof_write tests/lthread_fdeof_write.c)
target_link_libraries(lthread_fdeof_write lthread pthread)

enable_testing()
add_test(lthread_sleep ${UNIT_TEST_PATH}/lthread_sleep)
add_test(lthread_join ${UNIT_TEST_PATH}/lthread_join)
add_test(lthread_fdeof_read ${UNIT_TEST_PATH}/lthread_fdeof_read)
add_test(lthread_fdeof_write ${UNIT_TEST_PATH}/lthread_fdeof_write)
3 changes: 3 additions & 0 deletions src/lthread_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ fn \
x { \
ssize_t ret = 0; \
struct lthread *lt = lthread_get_sched()->current_lthread; \
\
lt->state &= CLEARBIT(LT_ST_FDEOF); \
while (1) { \
if (lt->state & BIT(LT_ST_FDEOF)) \
return (-1); \
Expand All @@ -88,6 +90,7 @@ x { \
ssize_t recvd = 0; \
struct lthread *lt = lthread_get_sched()->current_lthread; \
\
lt->state &= CLEARBIT(LT_ST_FDEOF); \
while (recvd != length) { \
if (lt->state & BIT(LT_ST_FDEOF)) \
return (-1); \
Expand Down
67 changes: 67 additions & 0 deletions tests/lthread_fdeof_read.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "lthread.h"
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>

/*
* test made after the bug was found:
* lthread reads from the fd that was closed by the other side,
* then next read from an alive fd will be a guaranteed failure
*/


bool PASSED = false;
const char * const PHRASE = "Hello world!";

void
write_pipe(void *arg)
{
int *pipes = arg;
printf("closing fd of 1 %d\n", pipes[1]);
lthread_close(pipes[1]); /* first read must fail */
printf("fd of 3 is %d\n", pipes[3]);
lthread_write(pipes[3], PHRASE, strlen(PHRASE) + 1); /* second read must succeed */
lthread_close(pipes[3]);
}

void
read_pipe(void *arg)
{
int *pipes = arg;
char buf[100];
int ret;

for (int i = 0; i <= 2; i += 2) {
ret = lthread_read(pipes[i], buf, sizeof(buf), 0);
lthread_close(pipes[i]);
if (ret) {
printf("fd %d, read '%s' [%d]\n", pipes[i], buf, ret);
} else {
printf("read from fd %d failed %d\n", pipes[i], ret);
continue;
}

if (strcmp(buf, PHRASE) == 0)
PASSED = true;
}
}

int
main(int argc, char **argv)
{
lthread_t *lt = NULL;
int pipes[4];
assert(lthread_pipe(pipes) == 0);
assert(lthread_pipe(pipes + 2) == 0);

lthread_create(&lt, read_pipe, pipes);
lthread_create(&lt, write_pipe, pipes);
lthread_run();

return PASSED != true;
}
73 changes: 73 additions & 0 deletions tests/lthread_fdeof_write.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "lthread.h"
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>

/*
* this test is analogous to lthread_fdeof_read.c, but for write function
* even though the error is encountered only for read-calls, write test was made
* just in case
*/


bool PASSED = false;
const char * const PHRASE = "Hello world!";

void
write_pipe(void *arg)
{
int *pipes = arg;
int ret;

for (int i = 1; i <= 3; i += 2) {
ret = lthread_write(pipes[i], PHRASE, strlen(PHRASE) + 1);
printf("fd of %d is %d, written %d %s\n", i, pipes[i], ret, ret < 0 ? strerror(errno) : "");
}
}

void
read_pipe(void *arg)
{
int *pipes = arg;
char buf[100];
int ret;

printf("closing fd of 0 %d\n", pipes[0]); /* first write must fail */
lthread_close(pipes[0]);
ret = lthread_read(pipes[2], buf, sizeof(buf), 0); /* second write must succeed */
lthread_close(pipes[2]);
if (ret) {
printf("fd %d, read '%s' [%d]\n", pipes[2], buf, ret);
} else {
printf("read from fd %d failed %d\n", pipes[2], ret);
}

if (strcmp(buf, PHRASE) == 0)
PASSED = true;
}

int
main(int argc, char **argv)
{
struct sigaction act = { 0 };
act.sa_handler = SIG_IGN;

sigaction(SIGPIPE, &act, NULL);

lthread_t *lt = NULL;
int pipes[4];
assert(lthread_pipe(pipes) == 0);
assert(lthread_pipe(pipes + 2) == 0);

lthread_create(&lt, read_pipe, pipes);
lthread_create(&lt, write_pipe, pipes);
lthread_run();

return PASSED != true;
}