conn->data->close(conn);
}
+/* set polling depending on the change between the CURR part of the
+ * flags and the new flags in connection C. The connection flags are
+ * updated with the new flags at the end of the operation. Only the bits
+ * relevant to CO_FL_CURR_* from <flags> are considered.
+ */
+void conn_set_polling(struct connection *c, unsigned int new);
+
+/* update polling depending on the change between the CURR part of the
+ * flags and the DATA part of the flags in connection C. The connection
+ * is assumed to already be in the data phase.
+ */
+static inline void conn_update_data_polling(struct connection *c)
+{
+ conn_set_polling(c, c->flags << 8);
+}
+
+/* update polling depending on the change between the CURR part of the
+ * flags and the SOCK part of the flags in connection C. The connection
+ * is assumed to already be in the handshake phase.
+ */
+static inline void conn_update_sock_polling(struct connection *c)
+{
+ conn_set_polling(c, c->flags << 4);
+}
+
+/* returns non-zero if data flags from c->flags changes from what is in the
+ * current section of c->flags.
+ */
+static inline unsigned int conn_data_polling_changes(const struct connection *c)
+{
+ return ((c->flags << 8) ^ c->flags) & 0xF0000000;
+}
+
+/* returns non-zero if sock flags from c->flags changes from what is in the
+ * current section of c->flags.
+ */
+static inline unsigned int conn_sock_polling_changes(const struct connection *c)
+{
+ return ((c->flags << 4) ^ c->flags) & 0xF0000000;
+}
+
+/* Automatically updates polling on connection <c> depending on the DATA flags
+ * if no handshake is in progress.
+ */
+static inline void conn_cond_update_data_polling(struct connection *c)
+{
+ if (!(c->flags & CO_FL_POLL_SOCK) && conn_data_polling_changes(c))
+ conn_update_data_polling(c);
+}
+
+/* Automatically updates polling on connection <c> depending on the SOCK flags
+ * if a handshake is in progress.
+ */
+static inline void conn_cond_update_sock_polling(struct connection *c)
+{
+ if ((c->flags & CO_FL_POLL_SOCK) && conn_sock_polling_changes(c))
+ conn_update_sock_polling(c);
+}
+
+/* Automatically update polling on connection <c> depending on the DATA and
+ * SOCK flags, and on whether a handshake is in progress or not. This may be
+ * called at any moment when there is a doubt about the effectiveness of the
+ * polling state, for instance when entering or leaving the handshake state.
+ */
+static inline void conn_cond_update_polling(struct connection *c)
+{
+ if (!(c->flags & CO_FL_POLL_SOCK) && conn_data_polling_changes(c))
+ conn_update_data_polling(c);
+ else if ((c->flags & CO_FL_POLL_SOCK) && conn_sock_polling_changes(c))
+ conn_update_sock_polling(c);
+}
+
+/***** Event manipulation primitives for use by DATA I/O callbacks *****/
+/* The __conn_* versions do not propagate to lower layers and are only meant
+ * to be used by handlers called by the connection handler. The other ones
+ * may be used anywhere.
+ */
+static inline void __conn_data_want_recv(struct connection *c)
+{
+ c->flags |= CO_FL_DATA_RD_ENA;
+}
+
+static inline void __conn_data_stop_recv(struct connection *c)
+{
+ c->flags &= ~CO_FL_DATA_RD_ENA;
+}
+
+static inline void __conn_data_poll_recv(struct connection *c)
+{
+ c->flags |= CO_FL_DATA_RD_POL | CO_FL_DATA_RD_ENA;
+}
+
+static inline void __conn_data_want_send(struct connection *c)
+{
+ c->flags |= CO_FL_DATA_WR_ENA;
+}
+
+static inline void __conn_data_stop_send(struct connection *c)
+{
+ c->flags &= ~CO_FL_DATA_WR_ENA;
+}
+
+static inline void __conn_data_poll_send(struct connection *c)
+{
+ c->flags |= CO_FL_DATA_WR_POL | CO_FL_DATA_WR_ENA;
+}
+
+static inline void __conn_data_stop_both(struct connection *c)
+{
+ c->flags &= ~(CO_FL_DATA_WR_ENA | CO_FL_DATA_RD_ENA);
+}
+
+static inline void conn_data_want_recv(struct connection *c)
+{
+ __conn_data_want_recv(c);
+ conn_cond_update_data_polling(c);
+}
+
+static inline void conn_data_stop_recv(struct connection *c)
+{
+ __conn_data_stop_recv(c);
+ conn_cond_update_data_polling(c);
+}
+
+static inline void conn_data_poll_recv(struct connection *c)
+{
+ __conn_data_poll_recv(c);
+ conn_cond_update_data_polling(c);
+}
+
+static inline void conn_data_want_send(struct connection *c)
+{
+ __conn_data_want_send(c);
+ conn_cond_update_data_polling(c);
+}
+
+static inline void conn_data_stop_send(struct connection *c)
+{
+ __conn_data_stop_send(c);
+ conn_cond_update_data_polling(c);
+}
+
+static inline void conn_data_poll_send(struct connection *c)
+{
+ __conn_data_poll_send(c);
+ conn_cond_update_data_polling(c);
+}
+
+static inline void conn_data_stop_both(struct connection *c)
+{
+ __conn_data_stop_both(c);
+ conn_cond_update_data_polling(c);
+}
+
+/***** Event manipulation primitives for use by handshake I/O callbacks *****/
+/* The __conn_* versions do not propagate to lower layers and are only meant
+ * to be used by handlers called by the connection handler. The other ones
+ * may be used anywhere.
+ */
+static inline void __conn_sock_want_recv(struct connection *c)
+{
+ c->flags |= CO_FL_SOCK_RD_ENA;
+}
+
+static inline void __conn_sock_stop_recv(struct connection *c)
+{
+ c->flags &= ~CO_FL_SOCK_RD_ENA;
+}
+
+static inline void __conn_sock_poll_recv(struct connection *c)
+{
+ c->flags |= CO_FL_SOCK_RD_POL | CO_FL_SOCK_RD_ENA;
+}
+
+static inline void __conn_sock_want_send(struct connection *c)
+{
+ c->flags |= CO_FL_SOCK_WR_ENA;
+}
+
+static inline void __conn_sock_stop_send(struct connection *c)
+{
+ c->flags &= ~CO_FL_SOCK_WR_ENA;
+}
+
+static inline void __conn_sock_poll_send(struct connection *c)
+{
+ c->flags |= CO_FL_SOCK_WR_POL | CO_FL_SOCK_WR_ENA;
+}
+
+static inline void __conn_sock_stop_both(struct connection *c)
+{
+ c->flags &= ~(CO_FL_SOCK_WR_ENA | CO_FL_SOCK_RD_ENA);
+}
+
+static inline void conn_sock_want_recv(struct connection *c)
+{
+ __conn_sock_want_recv(c);
+ conn_cond_update_sock_polling(c);
+}
+
+static inline void conn_sock_stop_recv(struct connection *c)
+{
+ __conn_sock_stop_recv(c);
+ conn_cond_update_sock_polling(c);
+}
+
+static inline void conn_sock_poll_recv(struct connection *c)
+{
+ __conn_sock_poll_recv(c);
+ conn_cond_update_sock_polling(c);
+}
+
+static inline void conn_sock_want_send(struct connection *c)
+{
+ __conn_sock_want_send(c);
+ conn_cond_update_sock_polling(c);
+}
+
+static inline void conn_sock_stop_send(struct connection *c)
+{
+ __conn_sock_stop_send(c);
+ conn_cond_update_sock_polling(c);
+}
+
+static inline void conn_sock_poll_send(struct connection *c)
+{
+ __conn_sock_poll_send(c);
+ conn_cond_update_sock_polling(c);
+}
+
+static inline void conn_sock_stop_both(struct connection *c)
+{
+ __conn_sock_stop_both(c);
+ conn_cond_update_sock_polling(c);
+}
#endif /* _PROTO_CONNECTION_H */
struct sock_ops;
struct protocol;
+/* Polling flags that are manipulated by I/O callbacks and handshake callbacks
+ * indicate what they expect from a file descriptor at each layer. For each
+ * direction, we have 2 bits, one stating whether any suspected activity on the
+ * FD induce a call to the iocb, and another one indicating that the FD has
+ * already returned EAGAIN and that polling on it is essential before calling
+ * the iocb again :
+ * POL ENA state
+ * 0 0 STOPPED : any activity on this FD is ignored
+ * 0 1 ENABLED : any (suspected) activity may call the iocb
+ * 1 0 STOPPED : as above
+ * 1 1 POLLED : the FD is being polled for activity
+ *
+ * - Enabling an I/O event consists in ORing with 1.
+ * - Stopping an I/O event consists in ANDing with ~1.
+ * - Polling for an I/O event consists in ORing with ~3.
+ *
+ * The last computed state is remembered in CO_FL_CURR_* so that differential
+ * changes can be applied. For pollers that do not support speculative I/O,
+ * POLLED is the same as ENABLED and the POL flag can safely be ignored.
+ */
+
/* flags for use in connection->flags */
enum {
CO_FL_NONE = 0x00000000,
/* below we have all handshake flags grouped into one */
CO_FL_HANDSHAKE = CO_FL_SI_SEND_PROXY,
+
+ /* when any of these flags is set, polling is defined by socket-layer
+ * operations, as opposed to data-layer.
+ */
+ CO_FL_POLL_SOCK = CO_FL_HANDSHAKE | CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN,
+
+ /* flags used to remember what shutdown have been performed/reported */
+ CO_FL_DATA_RD_SH = 0x00010000, /* DATA layer was notified about shutr/read0 */
+ CO_FL_DATA_WR_SH = 0x00020000, /* DATA layer asked for shutw */
+ CO_FL_SOCK_RD_SH = 0x00040000, /* SOCK layer was notified about shutr/read0 */
+ CO_FL_SOCK_WR_SH = 0x00080000, /* SOCK layer asked for shutw */
+
+ /****** NOTE: do not change the values of the flags below ******/
+ CO_FL_RD_ENA = 1, CO_FL_RD_POL = 2, CO_FL_WR_ENA = 4, CO_FL_WR_POL = 8,
+
+ /* flags describing the DATA layer expectations regarding polling */
+ CO_FL_DATA_RD_ENA = CO_FL_RD_ENA << 20, /* receiving is allowed */
+ CO_FL_DATA_RD_POL = CO_FL_RD_POL << 20, /* receiving needs to poll first */
+ CO_FL_DATA_WR_ENA = CO_FL_WR_ENA << 20, /* sending is desired */
+ CO_FL_DATA_WR_POL = CO_FL_WR_POL << 20, /* sending needs to poll first */
+
+ /* flags describing the SOCK layer expectations regarding polling */
+ CO_FL_SOCK_RD_ENA = CO_FL_RD_ENA << 24, /* receiving is allowed */
+ CO_FL_SOCK_RD_POL = CO_FL_RD_POL << 24, /* receiving needs to poll first */
+ CO_FL_SOCK_WR_ENA = CO_FL_WR_ENA << 24, /* sending is desired */
+ CO_FL_SOCK_WR_POL = CO_FL_WR_POL << 24, /* sending needs to poll first */
+
+ /* flags storing the current polling state */
+ CO_FL_CURR_RD_ENA = CO_FL_RD_ENA << 28, /* receiving is allowed */
+ CO_FL_CURR_RD_POL = CO_FL_RD_POL << 28, /* receiving needs to poll first */
+ CO_FL_CURR_WR_ENA = CO_FL_WR_ENA << 28, /* sending is desired */
+ CO_FL_CURR_WR_POL = CO_FL_WR_POL << 28, /* sending needs to poll first */
};
/* This structure describes a connection with its methods and data.
fdtab[fd].ev &= ~(FD_POLL_IN | FD_POLL_OUT | FD_POLL_HUP | FD_POLL_ERR);
return ret;
}
+
+/* set polling depending on the change between the CURR part of the
+ * flags and the new flags in connection C. The connection flags are
+ * updated with the new flags at the end of the operation. Only the bits
+ * relevant to CO_FL_CURR_* from <flags> are considered.
+ */
+void conn_set_polling(struct connection *c, unsigned int new)
+{
+ unsigned int old = c->flags; /* for CO_FL_CURR_* */
+
+ /* update read status if needed */
+ if ((old & (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL)) != (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL) &&
+ (new & (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL)) == (CO_FL_CURR_RD_ENA|CO_FL_CURR_RD_POL))
+ fd_poll_recv(c->t.sock.fd);
+ else if (!(old & CO_FL_CURR_RD_ENA) && (new & CO_FL_CURR_RD_ENA))
+ fd_want_recv(c->t.sock.fd);
+ else if ((old & CO_FL_CURR_RD_ENA) && !(new & CO_FL_CURR_RD_ENA))
+ fd_stop_recv(c->t.sock.fd);
+
+ /* update write status if needed */
+ if ((old & (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL)) != (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL) &&
+ (new & (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL)) == (CO_FL_CURR_WR_ENA|CO_FL_CURR_WR_POL))
+ fd_poll_send(c->t.sock.fd);
+ else if (!(old & CO_FL_CURR_WR_ENA) && (new & CO_FL_CURR_WR_ENA))
+ fd_want_send(c->t.sock.fd);
+ else if ((old & CO_FL_CURR_WR_ENA) && !(new & CO_FL_CURR_WR_ENA))
+ fd_stop_send(c->t.sock.fd);
+
+ c->flags &= ~(CO_FL_CURR_WR_POL|CO_FL_CURR_WR_ENA|CO_FL_CURR_RD_POL|CO_FL_CURR_RD_ENA);
+ c->flags |= new & (CO_FL_CURR_WR_POL|CO_FL_CURR_WR_ENA|CO_FL_CURR_RD_POL|CO_FL_CURR_RD_ENA);
+}