diff options
Diffstat (limited to 'src/lib/connection.h')
-rw-r--r-- | src/lib/connection.h | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/src/lib/connection.h b/src/lib/connection.h new file mode 100644 index 0000000..612c540 --- /dev/null +++ b/src/lib/connection.h @@ -0,0 +1,260 @@ +#ifndef CONNECTION_H +#define CONNECTION_H + +#include "net.h" + +struct ioloop; +struct connection; + +enum connection_behavior { + CONNECTION_BEHAVIOR_DESTROY = 0, + CONNECTION_BEHAVIOR_ALLOW +}; + +enum connection_disconnect_reason { + /* not disconnected yet */ + CONNECTION_DISCONNECT_NOT = 0, + /* normal requested disconnection */ + CONNECTION_DISCONNECT_DEINIT, + /* input buffer full */ + CONNECTION_DISCONNECT_BUFFER_FULL, + /* connection got disconnected */ + CONNECTION_DISCONNECT_CONN_CLOSED, + /* connect() timed out */ + CONNECTION_DISCONNECT_CONNECT_TIMEOUT, + /* remote didn't send input */ + CONNECTION_DISCONNECT_IDLE_TIMEOUT, + /* handshake failed */ + CONNECTION_DISCONNECT_HANDSHAKE_FAILED, +}; + +struct connection_vfuncs { + void (*init)(struct connection *conn); + void (*destroy)(struct connection *conn); + /* For UNIX socket clients this gets called immediately (unless + delayed_unix_client_connected_callback=TRUE) with success=TRUE, + for IP connections it gets called later: + + If connect() fails, sets success=FALSE and errno. Streams aren't + initialized in that situation either. destroy() is called after + the callback. */ + void (*client_connected)(struct connection *conn, bool success); + + /* implement one of the input*() methods. + They return 1 = ok, continue. 0 = ok, but stop processing more + lines, -1 = error, disconnect the client. */ + void (*input)(struct connection *conn); + int (*input_line)(struct connection *conn, const char *line); + int (*input_args)(struct connection *conn, const char *const *args); + + /* handshake functions. Defaults to version checking. + must return 1 when handshake is completed, otherwise return 0. + return -1 to indicate error and disconnect client. + + if you implement this, remember to call connection_verify_version + yourself, otherwise you end up with assert crash. + + these will not be called if you implement `input` virtual function. + */ + int (*handshake)(struct connection *conn); + int (*handshake_line)(struct connection *conn, const char *line); + int (*handshake_args)(struct connection *conn, const char *const *args); + + /* Called when the connection handshake is ready. */ + void (*handshake_ready)(struct connection *conn); + + /* Called when input_idle_timeout_secs is reached, defaults to disconnect */ + void (*idle_timeout)(struct connection *conn); + /* Called when client_connect_timeout_msecs is reached, defaults to disconnect */ + void (*connect_timeout)(struct connection *conn); +}; + +struct connection_settings { + const char *service_name_in; + const char *service_name_out; + unsigned int major_version, minor_version; + + unsigned int client_connect_timeout_msecs; + unsigned int input_idle_timeout_secs; + + /* These need to be non-zero for corresponding stream to + be created. */ + size_t input_max_size; + size_t output_max_size; + enum connection_behavior input_full_behavior; + + /* Set to TRUE if this is a client */ + bool client; + + /* Set to TRUE if version should not be sent */ + bool dont_send_version; + /* By default when only input_args() is used, or when + connection_input_line_default() is used, empty lines aren't allowed + since it would result in additional args[0] == NULL check. Setting + this to TRUE passes it through instead of logging an error. */ + bool allow_empty_args_input; + /* Don't call client_connected() immediately on + connection_client_connect() with UNIX sockets. This is mainly + to make the functionality identical with inet sockets, which may + simplify the calling code. */ + bool delayed_unix_client_connected_callback; + /* Put the connection id in the log prefix */ + bool log_connection_id; + /* If connect() to UNIX socket fails with EAGAIN, retry for this many + milliseconds before giving up (0 = try once) */ + unsigned int unix_client_connect_msecs; + /* Turn on debug logging */ + bool debug; +}; + +struct connection { + struct connection *prev, *next; + struct connection_list *list; + + /* The name for the connection provided by the application. This is + usually a host name or a unix socket path. This may be NULL if the + application provides none. */ + char *base_name; + /* The name of the connection determined by the connection API. It is + equal to base_name when that is available and otherwise it is + composed from the connection properties; e.g., "ip:port". */ + const char *name; + + char *label; + char *property_label; + unsigned int id; + + int fd_in, fd_out; + struct ioloop *ioloop; + struct io *io; + struct istream *input; + struct ostream *output; + + unsigned int input_idle_timeout_secs; + struct timeout *to; + time_t last_input; + struct timeval last_input_tv; + struct timeval connect_started; + struct timeval connect_finished; + + /* set to parent event before calling init */ + struct event *event_parent; + struct event *event; + + /* connection properties */ + struct ip_addr local_ip, remote_ip; + in_port_t remote_port; + pid_t remote_pid; + uid_t remote_uid; + + /* received minor version */ + unsigned int minor_version; + + /* handlers */ + struct connection_vfuncs v; + + enum connection_disconnect_reason disconnect_reason; + + bool version_received:1; + bool handshake_received:1; + bool unix_socket:1; + bool unix_peer_checked:1; + bool disconnected:1; +}; + +struct connection_list { + struct connection *connections; + unsigned int connections_count; + + unsigned int id_counter; + + struct connection_settings set; + struct connection_vfuncs v; +}; + +void connection_init(struct connection_list *list, struct connection *conn, + const char *name) ATTR_NULL(3); +void connection_init_server(struct connection_list *list, + struct connection *conn, const char *name, + int fd_in, int fd_out) ATTR_NULL(3); +void connection_init_server_ip(struct connection_list *list, + struct connection *conn, const char *name, + int fd_in, int fd_out, + const struct ip_addr *remote_ip, + in_port_t remote_port) ATTR_NULL(3, 6); +void connection_init_client_ip(struct connection_list *list, + struct connection *conn, const char *hostname, + const struct ip_addr *ip, in_port_t port) + ATTR_NULL(3); +void connection_init_client_ip_from(struct connection_list *list, + struct connection *conn, + const char *hostname, + const struct ip_addr *ip, in_port_t port, + const struct ip_addr *my_ip) ATTR_NULL(3,6); +void connection_init_client_unix(struct connection_list *list, + struct connection *conn, const char *path); +void connection_init_client_fd(struct connection_list *list, + struct connection *conn, const char *name, + int fd_int, int fd_out) ATTR_NULL(3); +void connection_init_from_streams(struct connection_list *list, + struct connection *conn, const char *name, + struct istream *input, + struct ostream *output) ATTR_NULL(3); + +int connection_client_connect(struct connection *conn); + +/* Disconnects a connection */ +void connection_disconnect(struct connection *conn); + +/* Deinitializes a connection, calls disconnect */ +void connection_deinit(struct connection *conn); + +void connection_input_halt(struct connection *conn); +/* Resume connection handling. If a new IO was added, it's marked as having + pending input. */ +void connection_input_resume(struct connection *conn); + +/* Update event fields and log prefix based on connection properties. */ +void connection_update_event(struct connection *conn); + +/* Update connection properties and labels */ +void connection_update_properties(struct connection *conn); + +/* This needs to be called if the input/output streams are changed */ +void connection_streams_changed(struct connection *conn); + +/* Returns -1 = disconnected, 0 = nothing new, 1 = something new. + If input_full_behavior is ALLOW, may return also -2 = buffer full. */ +int connection_input_read(struct connection *conn); +/* Verify that VERSION input matches what we expect. */ +int connection_verify_version(struct connection *conn, + const char *service_name, + unsigned int major_version, + unsigned int minor_version); + +int connection_handshake_args_default(struct connection *conn, + const char *const *args); + +/* Returns human-readable reason for why connection was disconnected. */ +const char *connection_disconnect_reason(struct connection *conn); +/* Returns human-readable reason for why connection timed out, + e.g. "No input for 10.023 secs". */ +const char *connection_input_timeout_reason(struct connection *conn); + +void connection_switch_ioloop_to(struct connection *conn, + struct ioloop *ioloop); +void connection_switch_ioloop(struct connection *conn); + +struct connection_list * +connection_list_init(const struct connection_settings *set, + const struct connection_vfuncs *vfuncs); +void connection_list_deinit(struct connection_list **list); + +void connection_input_default(struct connection *conn); +int connection_input_line_default(struct connection *conn, const char *line); + +/* Change handlers, calls connection_input_halt and connection_input_resume */ +void connection_set_handlers(struct connection *conn, const struct connection_vfuncs *vfuncs); +void connection_set_default_handlers(struct connection *conn); + +#endif |