rename sock_tcp to tcp_{transport,client}, fix irc_net_connect to use log_err/tcp_connect
--- a/src/irc_net_connect.c Thu May 07 02:13:50 2009 +0300
+++ b/src/irc_net_connect.c Thu May 07 02:17:20 2009 +0300
@@ -1,6 +1,7 @@
#include "irc_net_internal.h"
-#include "sock_tcp.h"
+#include "tcp.h"
+#include "sock_ssl.h"
#include "log.h"
#include <time.h>
@@ -80,7 +81,7 @@
// yay
if (irc_net_connected(net, transport, &err))
- log_err_info(&err, "irc_net_connected");
+ log_error(&err, "irc_net_connected");
}
static void irc_net_on_connect_error (transport_t *transport, const error_t *conn_err, void *arg)
@@ -92,10 +93,10 @@
transport_destroy(transport);
// attempt reconnect later
- log_err_info(conn_err, "connect failed");
+ log_error(conn_err, "connect failed");
if (irc_net_connect(net, false, &err))
- log_err_info(&err, "unable to reconnect");
+ log_error(&err, "unable to reconnect");
}
static const struct transport_callbacks irc_net_transport_callbacks = {
@@ -147,7 +148,7 @@
log_debug("connecting to [%s]:%s", info->hostname, info->service);
// begin async connect
- if (sock_tcp_connect(&transport_info, &transport, info->hostname, info->service, err))
+ if (tcp_connect(&transport_info, &transport, info->hostname, info->service, err))
goto error;
net->connecting = true;
@@ -176,7 +177,7 @@
// execute it?
if (irc_net_connect(net, true, &err))
- log_err_info(&err, "unable to reconnect");
+ log_error(&err, "unable to reconnect");
}
/**
@@ -201,7 +202,7 @@
if (now) {
if (irc_net_do_connect(net, err))
// log error and continue below with schedule_reconnect
- log_err_info(err, "reconnect failed");
+ log_error(err, "reconnect failed");
else
// connecting, done
--- a/src/sock_tcp.c Thu May 07 02:13:50 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,337 +0,0 @@
-
-#include "sock_tcp_internal.h"
-#include "sock_internal.h"
-#include "log.h"
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-
-/**
- * Start connecting to the given address in a non-blocking fashion. Returns any errors that immediately crop up,
- * otherwise eventually calls sock_tcp_connect_done().
- */
-static err_t sock_tcp_connect_addr (struct sock_tcp *sock, struct addrinfo *addr, error_t *err);
-
-
-
-/**
- * Our transport_methods
- */
-static void _sock_tcp_destroy (transport_t *transport)
-{
- struct sock_tcp *sock = transport_check(transport, &sock_tcp_type);
-
- // proxy
- sock_tcp_destroy(sock);
-}
-
-/*
- * Our transport_type
- */
-struct transport_type sock_tcp_type = {
- .parent = &transport_fd_type,
- .methods = {
- .read = transport_fd_methods_read,
- .write = transport_fd_methods_write,
- .events = transport_fd_methods_events,
- .destroy = _sock_tcp_destroy,
- },
-};
-
-/**
- * Create a new socket() using the given addr's family/socktype/protocol, and update our transport_fd state.
- */
-static err_t sock_tcp_create_socket (struct sock_tcp *sock, struct addrinfo *addr, error_t *err)
-{
- int fd;
-
- // call socket()
- if ((fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) < 0)
- RETURN_SET_ERROR_ERRNO(err, ERR_SOCKET);
-
- // ok, update transport_fd
- transport_fd_set(SOCK_TCP_FD(sock), fd);
-
-
- return SUCCESS;
-}
-
-/**
- * Read the socket's error code, if any.
- *
- * The read error number is stored in err->extra on SUCCESS, unless reading the error fails, in which case
- * err contains the normal error info.
- *
- * @return error code on failure
- */
-static err_t sock_tcp_read_error (struct sock_tcp *sock, error_t *err)
-{
- int optval;
- socklen_t optlen;
-
- RESET_ERROR(err);
-
- // init params
- optval = 0;
- optlen = sizeof(optval);
-
- // read error code
- if (getsockopt(SOCK_TCP_FD(sock)->fd, SOL_SOCKET, SO_ERROR, &optval, &optlen))
- RETURN_SET_ERROR_ERRNO(err, ERR_GETSOCKOPT);
-
- // sanity-check optlen... not sure if this is sensible
- if (optlen != sizeof(optval))
- RETURN_SET_ERROR_EXTRA(err, ERR_GETSOCKOPT, EINVAL);
-
- // then store the system error code
- ERROR_EXTRA(err) = optval;
-
- // ok
- return SUCCESS;
-}
-
-/**
- * Attempt to connect to the given addrinfo, or the next one, if that fails, etc.
- *
- * This does not call transport_connected().
- */
-static err_t sock_tcp_connect_continue (struct sock_tcp *sock, struct addrinfo *addr, struct error_info *err)
-{
- if (!addr)
- // no more addresses left to try
- return SET_ERROR(err, ERR_GETADDRINFO_EMPTY);
-
- // try and connect to each one until we find one that works
- do {
- // attempt to start connect
- if (sock_tcp_connect_addr(sock, addr, err) == SUCCESS)
- break;
-
- // log a warning on the failed connect
- log_warn("sock_tcp_connect_addr(%s): %s", addr->ai_canonname, error_msg(err));
-
- } while ((addr = addr->ai_next));
-
-
- if (addr)
- // we succesfully did a sock_tcp_connect_addr on valid address
- return SUCCESS;
-
- else
- // all of the connect_async_addr's failed, return the last error
- return ERROR_CODE(err);
-
-}
-
-/**
- * Cleanup our resolver state and any connect callbacks after a connect
- */
-static void sock_tcp_connect_cleanup (struct sock_tcp *sock)
-{
- // free the addrinfo
- freeaddrinfo(sock->async_res);
- sock->async_res = sock->async_cur = NULL;
-
- // remove our event handler
- transport_fd_clear(SOCK_TCP_FD(sock));
-}
-
-/**
- * Our async connect operation has completed, clean up, set up state for event-based operation with user callbacks, and
- * invoke transport_connected().
- *
- * The given \a err should be NULL for successful completion, or the error for failures.
- */
-static void sock_tcp_connect_done (struct sock_tcp *sock, struct error_info *conn_err)
-{
- error_t err;
-
- // cleanup
- sock_tcp_connect_cleanup(sock);
-
- if (conn_err)
- // passthrough errors
- JUMP_SET_ERROR_INFO(&err, conn_err);
-
- // set up for default transport event-based operation
- if ((ERROR_CODE(&err) = transport_fd_defaults(SOCK_TCP_FD(sock))))
- goto error;
-
- // ok, no error
-
-error:
- // pass on to transport
- transport_connected(SOCK_TCP_TRANSPORT(sock), IS_ERROR(&err) ? &err : NULL, false);
-}
-
-/**
- * Our async connect callback
- */
-static void sock_tcp_on_connect (struct transport_fd *fd, short what, void *arg)
-{
- struct sock_tcp *sock = arg;
- struct error_info err;
- err_t tmp;
-
- // XXX: timeouts
- (void) what;
-
- // read socket error code
- if (sock_tcp_read_error(sock, &err))
- goto error;
-
- // did the connect fail?
- if (ERROR_EXTRA(&err))
- JUMP_SET_ERROR(&err, ERR_CONNECT);
-
- // done, success
- return sock_tcp_connect_done(sock, NULL);
-
-error:
- // close the socket
- if ((tmp = transport_fd_close(fd)))
- log_warn("error closing socket after connect error: %s", error_name(tmp));
-
- // log a warning
- log_warn("connect to '%s' failed: %s", sock->async_cur->ai_canonname, error_msg(&err));
-
- // try the next one or fail completely
- if (sock_tcp_connect_continue(sock, sock->async_cur->ai_next, &err))
- sock_tcp_connect_done(sock, &err);
-}
-
-static err_t sock_tcp_connect_addr (struct sock_tcp *sock, struct addrinfo *addr, error_t *err)
-{
- int ret;
- err_t tmp;
-
- // first, create the socket
- if (sock_tcp_create_socket(sock, addr, err))
- return ERROR_CODE(err);
-
- // then, set it up as nonblocking
- if ((ERROR_CODE(err) = transport_fd_nonblock(SOCK_TCP_FD(sock), true)))
- goto error;
-
- // then, initiate the connect
- if ((ret = connect(SOCK_TCP_FD(sock)->fd, addr->ai_addr, addr->ai_addrlen)) < 0 && errno != EINPROGRESS)
- JUMP_SET_ERROR_ERRNO(err, ERR_CONNECT);
-
- if (ret < 0) {
- // set the "current" address in case it fails and we need to try the next one
- sock->async_cur = addr;
-
- // ok, connect started, setup our completion callback
- if ((ERROR_CODE(err) = transport_fd_setup(SOCK_TCP_FD(sock), sock_tcp_on_connect, sock)))
- goto error;
-
- // enable for write
- if ((ERROR_CODE(err) = transport_fd_enable(SOCK_TCP_FD(sock), TRANSPORT_WRITE)))
- goto error;
-
- } else {
- // oops... blocking connect - fail to avoid confusion
- // XXX: come up with a better error name to use
- // XXX: support non-async connects as well
- JUMP_SET_ERROR_EXTRA(err, ERR_CONNECT, EINPROGRESS);
- }
-
- // ok
- return SUCCESS;
-
-error:
- // close the stuff we did open
- if ((tmp = transport_fd_close(SOCK_TCP_FD(sock))))
- log_warn("error closing socket after connect error: %s", error_name(tmp));
-
- return ERROR_CODE(err);
-}
-
-/**
- * External interface
- */
-void sock_tcp_init (struct sock_tcp *sock)
-{
- struct event_base *ev_base = _sock_stream_ctx.ev_base;
-
- // init without any fd
- transport_fd_init(SOCK_TCP_FD(sock), ev_base, TRANSPORT_FD_INVALID);
-
-}
-
-err_t sock_tcp_connect_async (struct sock_tcp *sock, const char *hostname, const char *service, error_t *err)
-{
- struct addrinfo hints;
- int ret;
-
- // build hints
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
-
- // resolve (blocking)
- if ((ret = getaddrinfo(hostname, service, &hints, &sock->async_res)))
- RETURN_SET_ERROR_EXTRA(err, ERR_GETADDRINFO, ret);
-
- // start connecting on the first result
- if (sock_tcp_connect_continue(sock, sock->async_res, err))
- goto error;
-
- // ok
- return SUCCESS;
-
-error:
- // cleanup
- if (sock->async_res)
- sock_tcp_connect_cleanup(sock);
-
- return ERROR_CODE(err);
-}
-
-void sock_tcp_destroy (struct sock_tcp *sock)
-{
- // cleanup our stuff
- if (sock->async_res)
- sock_tcp_connect_cleanup(sock);
-
- // destroy lower level
- transport_fd_destroy(SOCK_TCP_FD(sock));
-}
-
-/**
- * Public interface
- */
-err_t sock_tcp_connect (const struct transport_info *info, transport_t **transport_ptr,
- const char *host, const char *service, error_t *err)
-{
- struct sock_tcp *sock;
-
- // alloc
- if ((sock = calloc(1, sizeof(*sock))) == NULL)
- return ERR_CALLOC;
-
- // initialize transport
- transport_init(SOCK_TCP_TRANSPORT(sock), &sock_tcp_type, info);
-
- // init our state
- sock_tcp_init(sock);
-
- // connect
- if (sock_tcp_connect_async(sock, host, service, err))
- goto error;
-
- // good
- *transport_ptr = SOCK_TCP_TRANSPORT(sock);
-
- return 0;
-
-error:
- // cleanup
- sock_tcp_destroy(sock);
-
- // return error code
- return ERROR_CODE(err);
-}
-
--- a/src/sock_tcp.h Thu May 07 02:13:50 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#ifndef SOCK_TCP_H
-#define SOCK_TCP_H
-
-/**
- * @file
- *
- * TCP transport implementation.
- *
- * XXX: provide some TCP-specific type/functions?
- */
-#include "transport.h"
-
-/**
- * Connect the given transport via TCP to the given host/service. The transport will not be ready for use until the
- * transport_callbacks::on_connect callback has been invoked.
- *
- * XXX: blocking DNS resolution
- *
- * @param info the transport setup info
- * @param transport_ptr returned transport
- * @param host the hostname to connect to
- * @param service the service name (i.e. port) to connect to
- * @param err returned error info
- */
-err_t sock_tcp_connect (const struct transport_info *info, transport_t **transport_ptr,
- const char *host, const char *service, error_t *err);
-
-#endif
--- a/src/sock_tcp_internal.h Thu May 07 02:13:50 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-#ifndef SOCK_TCP_INTERNAL_H
-#define SOCK_TCP_INTERNAL_H
-
-/**
- * @file
- *
- * Internal interface of the sock_tcp transport implementation.
- */
-#include "sock_tcp.h"
-#include "transport_fd.h"
-#include <netdb.h>
-
-/**
- * Our transport type struct
- */
-extern struct transport_type sock_tcp_type;
-
-/**
- * TCP transport state
- */
-struct sock_tcp {
- /** Base fd-based transport state */
- struct transport_fd base_fd;
-
- /** The resolver state for the async connect process */
- struct addrinfo *async_res, *async_cur;
-};
-
-/**
- * Get a transport_fd pointer from a sock_tcp pointer
- */
-#define SOCK_TCP_FD(sock_ptr) (&(sock_ptr)->base_fd)
-
-/**
- * Get a transport pointer from a sock_tcp pointer
- */
-#define SOCK_TCP_TRANSPORT(sock_ptr) TRANSPORT_FD_BASE(SOCK_TCP_FD(sock_ptr))
-
-/**
- * Initialize the sock_tcp state
- */
-void sock_tcp_init (struct sock_tcp *sock);
-
-/**
- * Attempt to connect asyncronously to the given hostname/service. Once a connection has been established, this will
- * call transport_connected(), so you can register transport_methods::_connected if layering on top of TCP.
- *
- * In case of errors while starting the async connect process, an error code will be returned. If the connect fails
- * later on, transport_connected() will be called with the error code.
- *
- * The sock must have been initialized using sock_tcp_init().
- *
- * @param sock the unconnected TCP socket to connect with
- * @param hostname the hostname to resolve
- * @param service the service to connect to
- * @param err returned error info for immediate errors
- */
-err_t sock_tcp_connect_async (struct sock_tcp *sock, const char *hostname, const char *service, error_t *err);
-
-/**
- * Destroy the sock_tcp's state, including the transport_fd state.
- */
-void sock_tcp_destroy (struct sock_tcp *sock);
-
-#endif /* SOCK_TCP_INTERNAL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tcp.c Thu May 07 02:17:20 2009 +0300
@@ -0,0 +1,43 @@
+#include "tcp_internal.h"
+
+int tcp_sock_create (const struct addrinfo *addr, error_t *err)
+{
+ int sock;
+
+ // create a new socket using addr->ai_family/socktype/protocol
+ if ((sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) < 0)
+ JUMP_SET_ERROR_ERRNO(err, ERR_SOCKET);
+
+ return sock;
+
+error:
+ return -ERROR_CODE(err);
+}
+
+err_t tcp_sock_error (evutil_socket_t sock, error_t *err)
+{
+ int optval;
+ socklen_t optlen;
+
+ RESET_ERROR(err);
+
+ // init params
+ optval = 0;
+ optlen = sizeof(optval);
+
+ // read error code
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen))
+ RETURN_SET_ERROR_ERRNO(err, ERR_GETSOCKOPT);
+
+ // sanity-check optlen... not sure if this is sensible
+ if (optlen != sizeof(optval))
+ RETURN_SET_ERROR_EXTRA(err, ERR_GETSOCKOPT, EINVAL);
+
+ // then store the system error code
+ ERROR_EXTRA(err) = optval;
+
+ // ok
+ return SUCCESS;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tcp.h Thu May 07 02:17:20 2009 +0300
@@ -0,0 +1,35 @@
+#ifndef TCP_H
+#define TCP_H
+
+/**
+ * @file
+ *
+ * TCP transport/service implementation.
+ *
+ * XXX: provide some TCP-specific type/functions?
+ */
+#include "transport.h"
+#include "service.h"
+
+/**
+ * Connect the given transport via TCP to the given host/service. The transport will not be ready for use until the
+ * transport_callbacks::on_connect callback has been invoked.
+ *
+ * XXX: blocking DNS resolution
+ *
+ * @param info the transport setup info
+ * @param transport_ptr returned transport
+ * @param host the hostname to connect to
+ * @param service the service name (i.e. port) to connect to
+ * @param err returned error info
+ */
+err_t tcp_connect (const struct transport_info *info, transport_t **transport_ptr,
+ const char *host, const char *service, error_t *err);
+
+/**
+ * Create a passive/listening TCP socket on the given interface/port (NULL to pick automatically).
+ */
+err_t tcp_listen (const struct service_info *info, service_t **service_ptr,
+ const char *interface, const char *service, error_t *err);
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tcp_client.c Thu May 07 02:17:20 2009 +0300
@@ -0,0 +1,278 @@
+#include "tcp_internal.h"
+#include "log.h"
+
+/*
+ * Our transport methods
+ */
+static void tcp_client__deinit (transport_t *transport)
+{
+ struct tcp_client *client = transport_check(transport, &tcp_client_type);
+
+ // proxy
+ tcp_client_deinit(client);
+}
+
+/*
+ * Our transport_type
+ */
+const struct transport_type tcp_client_type = {
+ .base_type = {
+ .parent = &tcp_transport_type.base_type,
+ },
+ .methods = {
+ .read = transport_fd__read,
+ .write = transport_fd__write,
+ .events = transport_fd__events,
+ .deinit = tcp_client__deinit,
+ },
+};
+
+/*
+ * Forward-declare
+ */
+static void tcp_client_on_connect (struct transport_fd *fd, short what, void *arg);
+
+/*
+ * Function implementations
+ */
+void tcp_client_init (struct tcp_client *client)
+{
+ tcp_transport_init(&client->base_trans, -1);
+
+ resolve_result_init(&client->rr);
+}
+
+/*
+ * Start connecting to the given address in a non-blocking fashion. Returns any errors that immediately crop up,
+ * otherwise eventually calls tcp_client_connect_done().
+ */
+static err_t tcp_client_connect_addr (struct tcp_client *client, struct addrinfo *addr, error_t *err)
+{
+ struct transport_fd *_fd = &client->base_trans.base_fd;
+ int ret;
+ evutil_socket_t sock;
+ err_t tmp;
+
+ // first, create the socket
+ if ((sock = tcp_sock_create(addr, err)) < 0)
+ return ERROR_CODE(err);
+
+ // set it as our sock
+ if ((ERROR_CODE(err) = transport_fd_set(_fd, sock)))
+ goto error;
+
+ // then, set it up as nonblocking
+ if ((ERROR_CODE(err) = transport_fd_nonblock(_fd, true)))
+ goto error;
+
+ // then, initiate the connect
+ if ((ret = connect(sock, addr->ai_addr, addr->ai_addrlen)) < 0 && errno != EINPROGRESS)
+ JUMP_SET_ERROR_ERRNO(err, ERR_CONNECT);
+
+ if (ret < 0) {
+ // ok, connect started, setup our completion callback
+ if ((ERROR_CODE(err) = transport_fd_setup(_fd, tcp_client_on_connect, client)))
+ goto error;
+
+ // enable for write
+ if ((ERROR_CODE(err) = transport_fd_enable(_fd, TRANSPORT_WRITE)))
+ goto error;
+
+ } else {
+ // oops... blocking connect - fail to avoid confusion
+ // XXX: come up with a better error name to use
+ // XXX: support non-async connects as well
+ JUMP_SET_ERROR_EXTRA(err, ERR_CONNECT, EINPROGRESS);
+ }
+
+ // ok
+ return SUCCESS;
+
+error:
+ // close the stuff we did open
+ if ((tmp = transport_fd_close(_fd)))
+ log_warn("error closing socket after connect error: %s", error_name(tmp));
+
+ return ERROR_CODE(err);
+}
+
+
+/*
+ * Attempt to connect to the next addrinfo, or the next one, if that fails, etc.
+ *
+ * This does not call transport_connected().
+ */
+static err_t tcp_client_connect_continue (struct tcp_client *client, error_t *err)
+{
+ struct addrinfo *addr;
+
+ // try and connect to each one until we find one that works
+ while ((addr = resolve_result_next(&client->rr))) {
+ // attempt to start connect
+ if (tcp_client_connect_addr(client, addr, err) == SUCCESS)
+ break;
+
+ // log a warning on the failed connect
+ log_warn_error(err, "%s", resolve_addr_text(addr));
+ }
+
+
+ if (addr)
+ // we succesfully did a tcp_client_connect_addr on valid address
+ return SUCCESS;
+
+ else
+ // all of the connect_async_addr's failed, return the last error
+ return ERROR_CODE(err);
+}
+
+/*
+ * Cleanup our resolver state and any connect callbacks after a connect
+ */
+static void tcp_client_connect_cleanup (struct tcp_client *client)
+{
+ // drop the resolver stuff
+ resolve_result_deinit(&client->rr);
+
+ // remove our event handler
+ transport_fd_clear(&client->base_trans.base_fd);
+}
+
+/*
+ * Our async connect operation has completed, clean up, set up state for event-based operation with user callbacks, and
+ * invoke transport_connected().
+ *
+ * The given \a err should be NULL for successful completion, or the error for failures.
+ */
+static void tcp_client_connect_done (struct tcp_client *client, error_t *conn_err)
+{
+ error_t err;
+
+ // cleanup
+ tcp_client_connect_cleanup(client);
+
+ if (conn_err)
+ JUMP_SET_ERROR_INFO(&err, conn_err);
+
+ // let the transport handle the rest
+ if (tcp_transport_connected(&client->base_trans, &err))
+ goto error;
+
+ // ok
+ return;
+
+error:
+ // pass the error on to transport
+ transport_connected(&client->base_trans.base_fd.base, &err, false);
+}
+
+/*
+ * Our async connect callback
+ */
+static void tcp_client_on_connect (struct transport_fd *fd, short what, void *arg)
+{
+ struct tcp_client *client = arg;
+ error_t err;
+ err_t tmp;
+
+ // XXX: timeouts
+ (void) what;
+
+ // read socket error code
+ if (tcp_sock_error(client->base_trans.base_fd.fd, &err))
+ goto error;
+
+ // did the connect fail?
+ if (ERROR_EXTRA(&err))
+ JUMP_SET_ERROR(&err, ERR_CONNECT);
+
+ // done, success
+ return tcp_client_connect_done(client, NULL);
+
+error:
+ // close the socket
+ if ((tmp = transport_fd_close(fd)))
+ log_warn("error closing socket after connect error: %s", error_name(tmp));
+
+ // log a warning
+ log_warn_error(&err, "connect to %s failed", "???");
+
+ // try the next one or fail completely
+ if (tcp_client_connect_continue(client, &err))
+ tcp_client_connect_done(client, &err);
+}
+
+err_t tcp_client_connect_async (struct tcp_client *client, const char *hostname, const char *service, error_t *err)
+{
+ // do the resolving
+ if (resolve_addr(&client->rr, hostname, service, SOCK_STREAM, 0, err))
+ return ERROR_CODE(err);
+
+ // start connecting with the first result
+ if (tcp_client_connect_continue(client, err))
+ goto error;
+
+ // ok
+ return SUCCESS;
+
+error:
+ // cleanup
+ resolve_result_deinit(&client->rr);
+
+ return ERROR_CODE(err);
+}
+
+void tcp_client_deinit (struct tcp_client *client)
+{
+ // cleanup our stuff
+ resolve_result_deinit(&client->rr);
+
+ // deinit lower transport
+ tcp_transport_deinit(&client->base_trans);
+}
+
+/*
+ * Deinit and free, not using the transport interface
+ */
+static void tcp_client_destroy (struct tcp_client *client)
+{
+ tcp_client_deinit(client);
+
+ free(client);
+}
+
+/*
+ * Public interface
+ */
+err_t tcp_connect (const struct transport_info *info, transport_t **transport_ptr,
+ const char *host, const char *service, error_t *err)
+{
+ struct tcp_client *client;
+
+ // alloc
+ if ((client = calloc(1, sizeof(*client))) == NULL)
+ return ERR_CALLOC;
+
+ // init transport
+ transport_init(&client->base_trans.base_fd.base, &tcp_client_type, info);
+
+ // init our state
+ tcp_client_init(client);
+
+ // begin connect
+ if (tcp_client_connect_async(client, host, service, err))
+ goto error;
+
+ // good
+ *transport_ptr = &client->base_trans.base_fd.base;
+
+ return 0;
+
+error:
+ // cleanup
+ tcp_client_destroy(client);
+
+ // return error code
+ return ERROR_CODE(err);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tcp_internal.h Thu May 07 02:17:20 2009 +0300
@@ -0,0 +1,170 @@
+#ifndef TCP_INTERNAL_H
+#define TCP_INTERNAL_H
+
+/**
+ * @file
+ *
+ * Internal TCP interface for implementations
+ */
+#include "tcp.h"
+#include "resolve.h"
+#include "transport_fd.h"
+#include "transport_internal.h"
+#include "service_internal.h"
+#include "error.h"
+
+#include <event2/event.h>
+#include <event2/util.h>
+
+/**
+ * Create a new socket() using the given addr's family/socktype/protocol and return it.
+ *
+ * In case of errors, this returns -err_t
+ *
+ * @param addr the addrinfo to create the socket for
+ * @param err returned error info
+ * @return new fd on success, -err_t on error
+ */
+int tcp_sock_create (const struct addrinfo *addr, error_t *err);
+
+/**
+ * Return the socket's current error code via err->extra.
+ *
+ * In case getting the socket error code itself fails, this will return normal error code/info.
+ *
+ * Otherwise, this will return SUCCESS, with the errno value stored in err->extra.
+ */
+err_t tcp_sock_error (evutil_socket_t sock, error_t *err);
+
+
+/**
+ * TCP transport type
+ */
+extern const struct transport_type tcp_transport_type;
+
+/**
+ * Base TCP transport
+ *
+ * XXX: currently just the same as transport_fd, but this will probably change
+ */
+struct tcp_transport {
+ /** Base FD-based implementation */
+ struct transport_fd base_fd;
+};
+
+/**
+ * Initialize the tcp_transport state.
+ *
+ * This initializes the transport_fd base using the global sock_ctx::ev_base and the given socket.
+ */
+void tcp_transport_init (struct tcp_transport *trans, evutil_socket_t sock);
+
+/**
+ * Create a new tcp_transport with the given sock.
+ *
+ * For convenience, this will also make the sock nonblocking.
+ *
+ * In case of errors, this will the socket.
+ *
+ * @param trans_ptr returned tcp_transport
+ * @param info the transport user settings
+ * @param sock the unused TCP socket
+ * @param err returned error info
+ */
+err_t tcp_transport_create (struct tcp_transport **trans_ptr, const struct transport_info *info, evutil_socket_t sock, error_t *err);
+
+/**
+ * The transport as now connected, this sets up the intitial user settings, and invokes the callback.
+ *
+ * XXX: this does an 'indirect' call to transport_connected().
+ *
+ * @param err returned error info
+ */
+err_t tcp_transport_connected (struct tcp_transport *trans, error_t *err);
+
+/**
+ * Deinitialize the transport state, terminating the connection and releasing resources.
+ */
+void tcp_transport_deinit (struct tcp_transport *trans);
+
+/**
+ * Deinitialize and free the given tcp_transport
+ */
+void tcp_transport_destroy (struct tcp_transport *trans);
+
+/**
+ * TCP client transport type
+ */
+extern const struct transport_type tcp_client_type;
+
+/**
+ * TCP client state
+ */
+struct tcp_client {
+ /** Base transport stuff */
+ struct tcp_transport base_trans;
+
+ /** The resolver lookup result for the async connect process */
+ struct resolve_result rr;
+};
+
+/**
+ * Initialize the tcp_client state
+ */
+void tcp_client_init (struct tcp_client *client);
+
+/**
+ * Attempt to connect asyncronously to the given hostname/service. Once a connection has been established, this will
+ * call transport_connected(), so you can register transport_methods::_connected if layering on top of TCP.
+ *
+ * In case of errors while starting the async connect process, an error code will be returned. If the connect fails
+ * later on, transport_connected() will be called with the error code.
+ *
+ * The sock must have been initialized using sock_tcp_init().
+ *
+ * @param client the unconnected TCP client socket to connect with
+ * @param hostname the hostname to resolve
+ * @param service the service to connect to
+ * @param err returned error info for immediate errors
+ */
+err_t tcp_client_connect_async (struct tcp_client *client, const char *hostname, const char *service, error_t *err);
+
+/**
+ * Deinitialize the tcp_client's state, including the tcp_transport state.
+ */
+void tcp_client_deinit (struct tcp_client *client);
+
+
+
+/**
+ * TCP service type
+ */
+extern const struct service_type tcp_server_type;
+
+/**
+ * TCP service state
+ */
+struct tcp_server {
+ /** Base service state */
+ struct service base_service;
+
+ /** The input event with our listen() socket */
+ struct event *ev;
+};
+
+/**
+ * The listen() backlog
+ */
+#define TCP_SERVER_BACKLOG 5
+
+/**
+ * Open the listening socket on the given interface/service.
+ */
+err_t tcp_server_listen (struct tcp_server *serv, const char *interface, const char *service, error_t *err);
+
+/**
+ * Release the tcp_server's state, and cleanup the struct.
+ */
+void tcp_server_deinit (struct tcp_server *serv);
+
+#endif /* TCP_INTERNAL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tcp_transport.c Thu May 07 02:17:20 2009 +0300
@@ -0,0 +1,86 @@
+#include "tcp_internal.h"
+#include "sock_internal.h"
+
+#include <unistd.h>
+
+/*
+ * Our transport_type
+ */
+const struct transport_type tcp_transport_type = {
+ .base_type = {
+ .parent = &transport_fd_type.base_type,
+ },
+ .methods = {
+ .read = transport_fd__read,
+ .write = transport_fd__write,
+ .events = transport_fd__events,
+ .deinit = transport_fd__deinit,
+ },
+};
+
+void tcp_transport_init (struct tcp_transport *trans, evutil_socket_t sock)
+{
+ struct event_base *ev_base = _sock_stream_ctx.ev_base;
+
+ transport_fd_init(&trans->base_fd, ev_base, sock);
+}
+
+err_t tcp_transport_create (struct tcp_transport **trans_ptr, const struct transport_info *info, evutil_socket_t sock, error_t *err)
+{
+ struct tcp_transport *trans;
+
+ // alloc
+ if ((trans = calloc(1, sizeof(*trans))) == NULL)
+ JUMP_SET_ERROR(err, ERR_MEM);
+
+ // init transport
+ transport_init(&trans->base_fd.base, &tcp_transport_type, info);
+
+ // init ourselves
+ tcp_transport_init(trans, sock);
+
+ // setup the socket?
+ if (sock >= 0) {
+ // make it non-blocking
+ if ((ERROR_CODE(err) = transport_fd_nonblock(&trans->base_fd, true)))
+ goto error;
+ }
+
+ // ok
+ *trans_ptr = trans;
+
+ return SUCCESS;
+
+error:
+ // cleanup
+ if (trans)
+ tcp_transport_deinit(trans);
+ else
+ EVUTIL_CLOSESOCKET(sock);
+
+ return ERROR_CODE(err);
+}
+
+err_t tcp_transport_connected (struct tcp_transport *trans, error_t *err)
+{
+ // set up for default transport event-based operation
+ if ((ERROR_CODE(err) = transport_fd_defaults(&trans->base_fd)))
+ return ERROR_CODE(err);
+
+ // ok
+ transport_connected(&trans->base_fd.base, NULL, false);
+
+ return SUCCESS;
+}
+
+void tcp_transport_deinit (struct tcp_transport *trans)
+{
+ transport_fd_deinit(&trans->base_fd);
+}
+
+void tcp_transport_destroy (struct tcp_transport *trans)
+{
+ tcp_transport_deinit(trans);
+
+ free(trans);
+}