src/tcp_server.c
branchnew-lib-errors
changeset 219 cefec18b8268
parent 218 5229a5d098b2
--- a/src/tcp_server.c	Thu May 28 00:35:02 2009 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,260 +0,0 @@
-#include "tcp_internal.h"
-#include "sock_internal.h"
-#include "log.h"
-
-#include <unistd.h>
-
-/*
- * Service methods
- */
-void tcp_server__deinit (service_t *service)
-{
-    struct tcp_server *serv = service_check(service, &tcp_server_type);
-
-    tcp_server_deinit(serv);
-}
-
-/*
- * Service type
- */
-const struct service_type tcp_server_type = {
-    .base_type = {
-        .parent = &service_type_type,
-    },
-    .methods = {
-        .deinit = tcp_server__deinit,
-    },
-};
-
-/*
- * We got a new client, build a transport for it and give it to the user
- */
-static err_t tcp_server_client (struct tcp_server *serv, evutil_socket_t sock, error_t *err)
-{
-    struct tcp_transport *trans;
-    
-    // create a new transport for it, this also makes it nonblocking
-    if (tcp_transport_create(&trans, &serv->base_service.info.trans_info, sock, err))
-        goto error;
-
-    // make it connected
-    // this will call transport_callbacks::on_connect, which is all the user needs
-    if (tcp_transport_connected(trans, err))
-        goto error;
-
-    // ok
-    return SUCCESS;
-
-error:
-    // cleanup
-    if (trans)
-        tcp_transport_destroy(trans);
-
-    return ERROR_CODE(err);    
-}
-
-/*
- * Libevent callback
- */
-static void tcp_server_on_accept (evutil_socket_t sock, short what, void *arg)
-{
-    struct tcp_server *serv = arg;
-    evutil_socket_t client_sock;
-    error_t err;
-
-    (void) what;
-
-    // accept as a new client connection
-    if ((client_sock = accept(sock, NULL, NULL)) < 0 && errno != EAGAIN)
-        JUMP_SET_ERROR_ERRNO(&err, ERR_ACCEPT);
-
-    // spurious read event?
-    if (client_sock < 0)
-        return;
-
-    // handle it
-    if (tcp_server_client(serv, client_sock, &err))
-        goto error;
-
-    // ok
-    return;
-
-error:
-    if (client_sock >= 0)
-        EVUTIL_CLOSESOCKET(client_sock);
-
-    // faaail
-    service_error(&serv->base_service, &err);
-}
-
-/*
- * Attempts to construct a listen()'d socket with the given addr, and return it
- *
- * @param addr the addrinfo to try and create a socket for
- * @param err returned error info
- * @return listening socket, or -err_t on error
- */
-static int tcp_server_sock_addr (struct addrinfo *addr, error_t *err)
-{
-    evutil_socket_t sock;
-
-    // create the sock
-    if ((sock = tcp_sock_create(addr, err)) < 0)
-        goto error;
-
-    // bind it
-    if (bind(sock, addr->ai_addr, addr->ai_addrlen) < 0)
-        JUMP_SET_ERROR_ERRNO(err, ERR_BIND);
-
-    // listen
-    if (listen(sock, TCP_SERVER_BACKLOG) < 0)
-        JUMP_SET_ERROR_ERRNO(err, ERR_LISTEN);
-    
-    // ok, valid socket
-    return sock;
-
-error:
-    if (sock >= 0)
-        // cleanup
-        EVUTIL_CLOSESOCKET(sock);
-    
-    return -ERROR_CODE(err);
-}
-
-/*
- * Construct a listen()'d socket with the given resolver result, and return it.
- *
- * @param rr the resolver lookup result to create a socket for
- * @param err returned error info
- * @return listening socket, or -err_t on error
- */
-static int tcp_server_sock (struct resolve_result *rr, error_t *err)
-{
-    struct addrinfo *addr;
-    evutil_socket_t sock;
-
-    // try each addrinfo
-    while ((addr = resolve_result_next(rr))) {
-        // attempt to construct given socket
-        if ((sock = tcp_server_sock_addr(addr, err)) < 0)
-            // log an informative error warning
-            log_warn_error(err, "%s", resolve_addr_text(addr)); 
-
-        else
-            // got a valid socket 
-            break;
-    }
-    
-    if (sock >= 0)
-        // valid socket
-        return sock;
-
-    else
-        // some error occured
-        return -ERROR_CODE(err);
-}
-
-err_t tcp_server_listen (struct tcp_server *serv, const char *interface, const char *service, error_t *err)
-{
-    struct resolve_result rr;
-    evutil_socket_t sock;
-
-    // get the global event_base
-    struct event_base *ev_base = _sock_stream_ctx.ev_base;
-
-    // init the resolver
-    resolve_result_init(&rr);
-
-    // resolve the interface/service
-    if (resolve_addr(&rr, interface, service, SOCK_STREAM, AI_PASSIVE, err))
-        return ERROR_CODE(err);
-    
-    // create the socket
-    if ((sock = tcp_server_sock(&rr, err)) < 0)
-        goto error;
-
-    // deinit lookup results
-    resolve_result_deinit(&rr);
-
-    // make it nonblocking
-    if (evutil_make_socket_nonblocking(sock))
-        JUMP_SET_ERROR_STR(err, ERR_MISC, "evutil_make_socket_nonblocking");
-    
-    // construct event for the sock
-    if ((serv->ev = event_new(ev_base, sock, EV_READ | EV_PERSIST, tcp_server_on_accept, serv)) == NULL)
-        JUMP_SET_ERROR(err, ERR_EVENT_NEW);
-
-    // add it
-    if (event_add(serv->ev, NULL))
-        JUMP_SET_ERROR(err, ERR_EVENT_ADD);
-
-    // ok
-    return SUCCESS;
-
-error:
-    // deinit results just to be sure
-    resolve_result_deinit(&rr);
-
-    if (sock >= 0 && !serv->ev)
-        // need to close socket ourselves, because we couldn't register our event for it
-        EVUTIL_CLOSESOCKET(sock);
-    
-    // general cleanup
-    tcp_server_deinit(serv);
-    
-    return ERROR_CODE(err);
-}
-
-void tcp_server_deinit (struct tcp_server *serv)
-{
-    if (serv->ev) {
-        // ignore errors
-        event_del(serv->ev);
-
-        // ignore errors
-        close(event_get_fd(serv->ev));
-        
-        // release event
-        event_free(serv->ev);
-        
-        // invalidate
-        serv->ev = NULL;
-    }
-}
-
-static void tcp_server_destroy (struct tcp_server *serv)
-{
-    tcp_server_deinit(serv);
-
-    free(serv);
-}
-
-/*
- * Public interface
- */
-err_t tcp_listen (const struct service_info *info, service_t **service_ptr, 
-        const char *interface, const char *service, error_t *err)
-{
-    struct tcp_server *serv;
-
-    // alloc
-    if ((serv = calloc(1, sizeof(*serv))) == NULL)
-        return SET_ERROR(err, ERR_MEM);
-
-    // init service
-    service_init(&serv->base_service, &tcp_server_type, info);
-
-    // init ourselves
-    if (tcp_server_listen(serv, interface, service, err))
-        goto error;
-
-    // ok
-    *service_ptr = &serv->base_service;
-
-    return SUCCESS;
-
-error:
-    tcp_server_destroy(serv);
-
-    return ERROR_CODE(err);
-}