summaryrefslogtreecommitdiffstats
path: root/src/lib/connection.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/connection.h')
-rw-r--r--src/lib/connection.h260
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