diff -r 5229a5d098b2 -r cefec18b8268 src/tcp_server.c --- 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 - -/* - * 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); -}