Current File : //usr/local/apps/dovecot/include/dovecot/connection.h |
#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