X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fio%2Fio.h;h=9316dd180a9895adc2f60fdb6cdaeff6d77deb4a;hb=HEAD;hp=1664df65f26e353120762f1ab89abc65ee01f1c9;hpb=3f642347378afc9e1db1768d88c9f5b2baffe9ba;p=ccan diff --git a/ccan/io/io.h b/ccan/io/io.h index 1664df65..eeb5e36e 100644 --- a/ccan/io/io.h +++ b/ccan/io/io.h @@ -4,6 +4,7 @@ #include #include #include +#include #include struct timers; @@ -222,7 +223,8 @@ struct io_plan *io_write_(struct io_conn *conn, * * This creates a plan to read data into a buffer. Once it's all * read, the @next function will be called: on an error, the finish - * function is called instead. + * function is called instead. If read() returns 0 (EOF) errno is set + * to 0. * * Note that the I/O may actually be done immediately. * @@ -255,7 +257,8 @@ struct io_plan *io_read_(struct io_conn *conn, * * This creates a plan to read data into a buffer. Once any data is * read, @len is updated and the @next function will be called: on an - * error, the finish function is called instead. + * error, the finish function is called instead. If read() returns 0 (EOF) + * errno is set to 0. * * Note that the I/O may actually be done immediately. * @@ -386,6 +389,39 @@ struct io_plan *io_out_always_(struct io_conn *conn, void *), void *arg); +/** + * io_sock_shutdown - start socket close process (flushes TCP sockets). + * @conn: the connection the plan is for + * + * Simply closing a TCP socket can lose data; unfortunately you should + * shutdown(SHUT_WR) and wait for the other side to see this and close. + * Of course, you also need to set a timer, in case it doesn't (you may + * already have some responsiveness timer, of course). + * + * On error, is equivalent to io_close(). + * + * Example: + * #include + * + * // Timer infra needs wrapper to contain extra data. + * struct timeout_timer { + * struct timer t; + * struct io_conn *conn; + * }; + * static struct timers timers; + * + * static struct io_plan *flush_and_close(struct io_conn *conn) + * { + * struct timeout_timer *timeout; + * // Freed if conn closes normally. + * timeout = tal(conn, struct timeout_timer); + * timeout->conn = conn; + * timer_addrel(&timers, &timeout->t, time_from_sec(5)); + * return io_sock_shutdown(conn); + * } + */ +struct io_plan *io_sock_shutdown(struct io_conn *conn); + /** * io_connect - create an asynchronous connection to a listening socket. * @conn: the connection that plan is for. @@ -673,6 +709,91 @@ void *io_loop(struct timers *timers, struct timer **expired); */ int io_conn_fd(const struct io_conn *conn); +/** + * io_plan_in_started - is this conn doing input I/O now? + * @conn: the conn. + * + * This returns true if input I/O has been performed on the conn but + * @next hasn't been called yet. For example, io_read() may have done + * a partial read. + * + * This can be useful if we want to terminate a connection only after + * reading a whole packet: if this returns true, we would wait until + * @next is called. + */ +bool io_plan_in_started(const struct io_conn *conn); + +/** + * io_plan_out_started - is this conn doing output I/O now? + * @conn: the conn. + * + * This returns true if output I/O has been performed on the conn but + * @next hasn't been called yet. For example, io_write() may have done + * a partial write. + * + * This can be useful if we want to terminate a connection only after + * writing a whole packet: if this returns true, we would wait until + * @next is called. + */ +bool io_plan_out_started(const struct io_conn *conn); + +/** + * io_flush_sync - (synchronously) complete any outstanding output. + * @conn: the connection. + * + * This is generally used as an emergency escape, for example when we + * want to write an error message on a socket before terminating, but it may + * be in the middle of existing I/O. We don't want to service any other + * IO, either. + * + * This returns true if all pending output is complete, false on error. + * The next callback is not called on the conn, but will be as soon as + * io_loop() is called. + * + * See Also: + * io_close_taken_fd + */ +bool io_flush_sync(struct io_conn *conn); + +/** + * io_conn_exclusive - set/unset an io_conn to exclusively serviced + * @conn: the connection + * @exclusive: whether to be exclusive or not + * + * If any io_conn is set exclusive, then no non-exclusive io_conn (or + * io_listener) will be serviced by io_loop(). If it's a io_duplex io_conn(), + * then io_conn_exclusive() makes the read-side exclusive; io_conn_out_exclusive() + * makes the write-side exclusive. + * + * This allows you to temporarily service only one (or several) fds. + * For example, you might want to flush out one io_conn and not + * receive any new connections or read any other input. + * + * Returns true if any exclusive io_conn remain, otherwise false. + * (This is useful for checking your own logic: dangling exclusive io_conn + * are dangerous!). + */ +bool io_conn_exclusive(struct io_conn *conn, bool exclusive); + +/** + * io_conn_out_exclusive - set/unset exclusive on the write-side of a duplex + * @conn: the connection, post io_duplex + * @exclusive: whether to be exclusive or not + * + * See io_conn_exclusive() above. + */ +bool io_conn_out_exclusive(struct io_conn *conn, bool exclusive); + +/** + * io_fd_block - helper to set an fd blocking/nonblocking. + * @fd: the file descriptor + * @block: true to set blocking, false to set non-blocking. + * + * Generally only fails is @fd isn't a valid file descriptor, otherwise + * returns true. + */ +bool io_fd_block(int fd, bool block); + /** * io_time_override - override the normal call for time. * @nowfn: the function to call. @@ -683,4 +804,23 @@ int io_conn_fd(const struct io_conn *conn); */ struct timemono (*io_time_override(struct timemono (*now)(void)))(void); +/** + * io_poll_override - override the normal call for poll. + * @pollfn: the function to call. + * + * io usually uses poll() internally, but this forces it to use your + * function (eg. for debugging, suppressing fds, or polling on others unknown + * to ccan/io). Returns the old one. + */ +int (*io_poll_override(int (*poll)(struct pollfd *fds, nfds_t nfds, int timeout)))(struct pollfd *, nfds_t, int); + +/** + * io_have_fd - do we own this file descriptor? + * @fd: the file descriptor. + * @listener: if non-NULL, set to true if it's a listening socket (io_listener). + * + * Returns NULL if we don't own it, otherwise a struct io_conn * or struct io_listener *. + */ +const void *io_have_fd(int fd, bool *listener); + #endif /* CCAN_IO_H */