diff --git a/src/io.c b/src/io.c index 3212499b20eb76fc9a6e8b1a7714e709f5e794ad..aacc6d823bebb5cff5e82b3a6849eb2eb37bf1a1 100644 --- a/src/io.c +++ b/src/io.c @@ -137,6 +137,12 @@ static int io_iter(struct io_backend *b) /* pre_write returns 0 if the buffer is empty */ if (write_buffer_pre_write(fd->buffer)) fds[i].events |= POLLOUT; + else + /* Buffer is empty. Should we close? */ + if (fd->buffer->closed) + { + fd->close_now = 1; + } } END_FOR_FDS; @@ -201,14 +207,12 @@ static int io_iter(struct io_backend *b) break; default: werror("io.c: write failed, %s\n", strerror(errno)); - CALLBACK(fd->close_callback); - fd->please_close = 1; + fd->close_reason = CLOSE_WRITE_FAILED; + fd->close_now = 1; break; } - // else if (!res) - // fatal("What now?"); else fd->buffer->start += res; } @@ -219,31 +223,49 @@ static int io_iter(struct io_backend *b) i = 0; /* Start over */ FOR_FDS(struct io_fd, fd, b->io, i++) { - if (!fd->please_close + if (!fd->close_now && (fds[i].revents & POLLIN)) { + int res; + struct fd_read r = { { STATIC_HEADER do_read }, fd->fd }; /* The handler function may install a new handler */ - if (!READ_HANDLER(fd->handler, - &r.super)) + res = READ_HANDLER(fd->handler, + &r.super); + switch(LSH_GET_ACTION(res)) { - /* FIXME: Perhaps we should not close yet, but - * stop reading and close as soon as the write - * buffer is flushed? But in that case, we - * probably also want to set some flag on the - * write buffer so that no more data can be - * written into it. */ - fd->please_close = 1; + case LSH_GOON: + if (LSH_FAILUREP(res)) + fatal("Internal error\n"); + break; + case LSH_CLOSE: + if (fd->buffer) + write_buffer_close(fd->buffer); + fd->close_reason + = LSH_FAILUREP(res) ? CLOSE_PROTOCOL_FAILURE : CLOSE_EOF; + break; + case LSH_DIE: + fd->close_reason = CLOSE_PROTOCOL_FAILURE; + fd->close_now = 1; + break; + default: + fatal("Internal error!\n"); } } - if (fd->please_close) + if (fd->close_now) { /* FIXME: Cleanup properly... * * After a write error, read state must be freed, * and vice versa. */ + + /* FIXME: The value returned from the close callback could be used + * to choose an exit code. */ + if (fd->close_callback) + CLOSE_CALLBACK(fd->close_callback, fd->close_reason); + UNLINK_FD; b->nio--; if (fd->handler) @@ -262,7 +284,8 @@ static int io_iter(struct io_backend *b) /* FIXME: Do something with the peer address? */ struct sockaddr_in peer; size_t addr_len = sizeof(peer); - + int res; + int conn = accept(fd->fd, (struct sockaddr *) &peer, &addr_len); if (conn < 0) @@ -270,9 +293,12 @@ static int io_iter(struct io_backend *b) werror("io.c: accept() failed, %s", strerror(errno)); continue; } - if (!FD_CALLBACK(fd->callback, conn)) + res = FD_CALLBACK(fd->callback, conn); + if (LSH_PROBLEMP(res)) { - /* FIXME: Should fd be closed here? */ + werror("Strange: Accepted a connection, " + "but failed before writing anything.\n"); + close(fd->fd); UNLINK_FD; lsh_free(fd); continue; @@ -285,8 +311,11 @@ static int io_iter(struct io_backend *b) { if (fds[i].revents & POLLOUT) { - if (!FD_CALLBACK(fd->callback, fd->fd)) - fatal("What now?"); + int res = FD_CALLBACK(fd->callback, fd->fd); + + if (LSH_PROBLEMP(res)) + werror("Strange: Connected, " + "but failed before writing anything.\n"); b->nconnect--; UNLINK_FD; lsh_free(fd); @@ -298,6 +327,7 @@ static int io_iter(struct io_backend *b) return 1; } +/* FIXME: Prehaps this function should return a suitable exit code? */ void io_run(struct io_backend *b) { while(io_iter(b)) @@ -469,13 +499,15 @@ struct abstract_write *io_read_write(struct io_backend *b, int fd, struct read_handler *read_callback, UINT32 block_size, - struct callback *close_callback) + struct close_callback *close_callback) { struct io_fd *f= xalloc(sizeof(struct io_fd)); struct write_buffer *buffer = write_buffer_alloc(block_size); f->fd = fd; - f->please_close = 0; + + f->close_reason = -1; /* Invalid reason */ + f->close_now = 0; /* Reading */ f->handler = read_callback; diff --git a/src/write_buffer.c b/src/write_buffer.c index 04dd222422d11468b3d9b60764b1a735ff4df800..ae68eb1e011e7c00b500dda9d38c96c6ac803877 100644 --- a/src/write_buffer.c +++ b/src/write_buffer.c @@ -40,9 +40,15 @@ static int do_write(struct abstract_write **w, if (!packet->length) { lsh_string_free(packet); - return 1; + return LSH_OK | LSH_GOON; } + if (closure->closed) + { + lsh_string_free(packet); + return LSH_FAIL | LSH_CLOSE; + } + /* Enqueue packet */ new = xalloc(sizeof(struct node)); new->packet = packet; @@ -70,7 +76,7 @@ static int do_write(struct abstract_write **w, closure->empty = 0; - return 1; + return LSH_OK | LSH_GOON; } /* Copy data as necessary, before writing. @@ -150,6 +156,11 @@ int write_buffer_pre_write(struct write_buffer *buffer) return !buffer->empty; } +void write_buffer_close(struct write_buffer *buffer) +{ + buffer->closed = 1; +} + struct write_buffer *write_buffer_alloc(UINT32 size) { struct write_buffer *res = xalloc(sizeof(struct write_buffer) - 1 + size*2); @@ -159,7 +170,8 @@ struct write_buffer *write_buffer_alloc(UINT32 size) res->block_size = size; res->empty = 1; - + res->closed = 0; + #if 0 res->try_write = try; #endif diff --git a/src/write_buffer.h b/src/write_buffer.h index c9daccffe9a407655f209f5e16b19958235d590a..01631086ce5c0823ee0442bbf57a0ae7d8b23135 100644 --- a/src/write_buffer.h +++ b/src/write_buffer.h @@ -45,7 +45,10 @@ struct write_buffer UINT32 block_size; int empty; - + + /* If non-zero, don't accept any more data. The i/o-channel shoudl be closed + * once the current buffers are flushed. */ + int closed; #if 0 int try_write; #endif @@ -63,5 +66,6 @@ struct write_buffer struct write_buffer *write_buffer_alloc(UINT32 size); int write_buffer_pre_write(struct write_buffer *buffer); +void write_buffer_close(struct write_buffer *buffer); #endif /* LSH_WRITE_BUFFER_H_INCLUDED */