diff options
Diffstat (limited to 'src/rexmpp_tcp.h')
-rw-r--r-- | src/rexmpp_tcp.h | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/rexmpp_tcp.h b/src/rexmpp_tcp.h new file mode 100644 index 0000000..124da2a --- /dev/null +++ b/src/rexmpp_tcp.h @@ -0,0 +1,177 @@ +/** + @file rexmpp_tcp.h + @brief TCP connection establishment. + @author defanor <defanor@uberspace.net> + @date 2020 + @copyright MIT license. + + This module tries to establish a TCP connection to a given host + and port. + + A connection establishment procedure begins with + ::rexmpp_tcp_conn_init, followed by repeated calls to + ::rexmpp_tcp_conn_proceed while the return code is + ::REXMPP_CONN_IN_PROGRESS, at the times suggested by + ::rexmpp_tcp_conn_timeout and on events suggested by + ::rexmpp_tcp_conn_fds, and ends with ::rexmpp_tcp_conn_finish. +*/ + +#ifndef REXMPP_TCP_H +#define REXMPP_TCP_H + +#define REXMPP_TCP_MAX_CONNECTION_ATTEMPTS 20 +#define REXMPP_TCP_IPV6_DELAY_MS 50 +#define REXMPP_TCP_CONN_DELAY_MS 250 + +typedef enum rexmpp_tcp_conn_resolution_status +rexmpp_tcp_conn_resolution_status_t; + +/** + @brief Resolution status. + */ +enum rexmpp_tcp_conn_resolution_status { + /** The resolution is not active. */ + REXMPP_CONN_RESOLUTION_INACTIVE, + /** Waiting for resolution. */ + REXMPP_CONN_RESOLUTION_WAITING, + /** Resolved successfully. */ + REXMPP_CONN_RESOLUTION_SUCCESS, + /** Failed to resolve. */ + REXMPP_CONN_RESOLUTION_FAILURE +}; + +typedef enum rexmpp_tcp_conn_error rexmpp_tcp_conn_error_t; + +/** + @brief Connection errors. +*/ +enum rexmpp_tcp_conn_error { + /** Connected, no error. */ + REXMPP_CONN_DONE, + /** Resolver error occurred. The exact error code can be read from + the connection structure. */ + REXMPP_CONN_RESOLVER_ERROR, + /** Connection in progress, no error yet. */ + REXMPP_CONN_IN_PROGRESS, + /** All the connection attempts failed. */ + REXMPP_CONN_FAILURE, + /** An unexpected error during connection. */ + REXMPP_CONN_ERROR +}; + +typedef struct rexmpp_tcp_connection rexmpp_tcp_conn_t; + +/** @brief A connection establishment structure. */ +struct rexmpp_tcp_connection { + /** @brief A host we are connecting to. */ + const char *host; + /** @brief A port we are connecting to. */ + int port; + + /** @brief Resolver channel. */ + ares_channel resolver_channel; + /** @brief Resolver error is stored here when + ::REXMPP_CONN_RESOLVER_ERROR is returned. */ + int resolver_error; + + /** @brief State of A record resolution. */ + enum rexmpp_tcp_conn_resolution_status resolution_v4; + /** @brief Status of A record resolution, as returned by the + resolver. */ + int resolver_status_v4; + /** @brief AF_INET (IPv4) hostent structure. */ + struct hostent *addr_v4; + /** @brief The AF_INET address number we are currently at. */ + int addr_cur_v4; + + /** @brief State of AAAA record resolution. */ + enum rexmpp_tcp_conn_resolution_status resolution_v6; + /** @brief Status of AAAA record resolution, as returned by the + resolver. */ + int resolver_status_v6; + /** @brief AF_INET6 (IPv6) hostent structure. */ + struct hostent *addr_v6; + /** @brief The AF_INET6 address number we are currently at. */ + int addr_cur_v6; + + /** @brief Socket array, one for each connection attempt. */ + int sockets[REXMPP_TCP_MAX_CONNECTION_ATTEMPTS]; + /** @brief The number of connection attempts so far. */ + int connection_attempts; + + /** @brief Next scheduled connection time. */ + struct timeval next_connection_time; + /** @brief File descriptor of a connected socket. */ + int fd; +}; + +/** + @brief Initiates a connection. + @param[out] conn An allocated connection structure. + @param[in] host A host to connect to. This could be a domain name, + or a textual representation of an IPv4 or an IPv6 address. + @param[in] port A port to connect to. + @returns A ::rexmpp_tcp_conn_error state. +*/ +rexmpp_tcp_conn_error_t +rexmpp_tcp_conn_init (rexmpp_tcp_conn_t *conn, + const char *host, + int port); + +/** + @brief Continues a connection process. + @param[in,out] conn An active connection structure. + @param[in] read_fds File descriptors available for reading from. + @param[in] write_fds File descriptors available for writing to. + @returns A ::rexmpp_tcp_conn_error state. +*/ +rexmpp_tcp_conn_error_t +rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn, + fd_set *read_fds, + fd_set *write_fds); + +/** + @brief Finalises a connection process. + + Closes pending connections except for the established one, frees + additionally allocated resources. + + Normally must be called on any state other than + ::REXMPP_CONN_IN_PROGRESS. The connection structure can be freed + after this. + + @param[in,out] conn An active connection structure. + @returns A connected socket's file descriptor, or -1. + */ +int rexmpp_tcp_conn_finish (rexmpp_tcp_conn_t *conn); + +/** + @brief Reports file descriptors a connection process is interested in. + + File descriptors are only added to an @c fd_set, so the ones it + already contains will not be lost. + + @param[in] conn An active connection structure. + @param[out] read_fds File descriptors a connection process is + interested in reading from. + @param[out] write_fds File descriptors a connection process is + interested in writing to. + @returns Maximum file descriptor number, plus 1. + */ +int rexmpp_tcp_conn_fds (rexmpp_tcp_conn_t *conn, + fd_set *read_fds, + fd_set *write_fds); + +/** + @brief Reports timeouts. + @param[in] conn An active connection structure. + @param[in] max_tv An existing maximum timeout. + @param[out] tv A timeval structure to store a new timeout in. + @returns A pointer to either max_tv or tv, depending on which one + is smaller. +*/ +struct timeval *rexmpp_tcp_conn_timeout (rexmpp_tcp_conn_t *conn, + struct timeval *max_tv, + struct timeval *tv); + +#endif |