diff -r 92e71129074d -r 9cb405164250 src/sock_tcp.c --- a/src/sock_tcp.c Thu Apr 02 03:19:44 2009 +0300 +++ b/src/sock_tcp.c Tue Apr 07 18:09:16 2009 +0300 @@ -5,116 +5,14 @@ #include #include #include -#include -#include #include -#include - -/* - * Our basic socket event handler for driving our callbacks - */ -static void sock_tcp_event_handler (evutil_socket_t fd, short what, void *arg) -{ - struct sock_tcp *sock = arg; - - (void) fd; - - // invoke appropriate callback - sock_stream_invoke_callbacks(SOCK_TCP_BASE(sock), what); -} - -/* - * Our sock_stream_methods.read method - */ -static err_t sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t *len) -{ - struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); - int ret; - - // read(), and detect non-EAGAIN or EOF - if ((ret = read(sock->fd, buf, *len)) < 0 && errno != EAGAIN) - // unexpected error - RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_READ); - - else if (ret == 0) - // EOF - return SET_ERROR(SOCK_TCP_ERR(sock), ERR_READ_EOF); - - - if (ret < 0) { - // EAGAIN -> zero bytes - *len = 0; - - } else { - // normal -> bytes read - *len = ret; - } - - // ok - return SUCCESS; -} - -/* - * Our sock_stream_methods.write method - */ -static err_t sock_tcp_write (struct sock_stream *base_sock, const void *buf, size_t *len) -{ - struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); - int ret; - - // write(), and detect non-EAGAIN or EOF - if ((ret = write(sock->fd, buf, *len)) < 0 && errno != EAGAIN) - // unexpected error - RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_WRITE); - - else if (ret == 0) - // EOF - return SET_ERROR(SOCK_TCP_ERR(sock), ERR_WRITE_EOF); - - - if (ret < 0) { - // EAGAIN -> zero bytes - *len = 0; - - } else { - // normal -> bytes read - *len = ret; - } - - return SUCCESS; -} - -static err_t sock_tcp_event_init (struct sock_stream *base_sock) -{ - struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); - err_t err; - - // set nonblocking - if ((err = sock_tcp_set_nonblock(sock, 1))) - return err; - - // add ourselves as the event handler - if ((err = sock_tcp_init_ev(sock, &sock_tcp_event_handler, sock))) - return err; - - // done - return SUCCESS; -} - -static err_t sock_tcp_event_enable (struct sock_stream *base_sock, short mask) -{ - struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); - - // implemented in sock_tcp_add_event - return sock_tcp_add_event(sock, mask); -} static void sock_tcp_release (struct sock_stream *base_sock) { struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); // close and free - sock_tcp_close(sock); + sock_fd_close(SOCK_TCP_FD(sock)); sock_tcp_free(sock); } @@ -123,15 +21,15 @@ */ static struct sock_stream_type sock_tcp_type = { .methods = { - .read = &sock_tcp_read, - .write = &sock_tcp_write, - .event_init = &sock_tcp_event_init, - .event_enable = &sock_tcp_event_enable, + .read = &sock_fd_read, + .write = &sock_fd_write, + .event_init = &sock_fd_event_init, + .event_enable = &sock_fd_event_enable, .release = &sock_tcp_release, }, }; -err_t sock_tcp_alloc (struct sock_tcp **sock_ptr) +static err_t sock_tcp_alloc (struct sock_tcp **sock_ptr) { // alloc if ((*sock_ptr = calloc(1, sizeof(**sock_ptr))) == NULL) @@ -140,82 +38,24 @@ // initialize base with sock_tcp_type sock_stream_init(SOCK_TCP_BASE(*sock_ptr), &sock_tcp_type); - // invalid fds are <0 - (*sock_ptr)->fd = -1; - - // done - return SUCCESS; -} - -err_t sock_tcp_init_fd (struct sock_tcp *sock, int fd) -{ - // valid fd - assert(fd >= 0); - - // initialize - sock->fd = fd; + // init without any fd + sock_fd_init(SOCK_TCP_FD(*sock_ptr), -1); // done return SUCCESS; } -err_t sock_tcp_init_ev (struct sock_tcp *sock, void (*ev_cb)(evutil_socket_t, short, void *), void *cb_arg) -{ - // require valid fd - assert(sock->fd >= 0); - - // this is initialization - assert(sock->ev_read == NULL && sock->ev_write == NULL); - - // create new event - if ((sock->ev_read = event_new(_sock_stream_ctx.ev_base, sock->fd, EV_READ, ev_cb, cb_arg)) == NULL) - return SET_ERROR(SOCK_TCP_ERR(sock), ERR_EVENT_NEW); - - if ((sock->ev_write = event_new(_sock_stream_ctx.ev_base, sock->fd, EV_WRITE, ev_cb, cb_arg)) == NULL) - return SET_ERROR(SOCK_TCP_ERR(sock), ERR_EVENT_NEW); - - // ok - return SUCCESS; -} - -void sock_tcp_deinit_ev (struct sock_tcp *sock) -{ - if (sock->ev_read) { - event_free(sock->ev_read); - - sock->ev_read = NULL; - } - - if (sock->ev_write) { - event_free(sock->ev_write); - - sock->ev_write = NULL; - } -} - err_t sock_tcp_init_socket (struct sock_tcp *sock, struct addrinfo *addr, struct error_info *err) { - // must not be set already - assert(sock->fd < 0); + int fd; // call socket - if ((sock->fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) < 0) + if ((fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) < 0) RETURN_SET_ERROR_ERRNO(err, ERR_SOCKET); // ok - return SUCCESS; -} + sock_fd_init(SOCK_TCP_FD(sock), fd); -err_t sock_tcp_add_event (struct sock_tcp *sock, short mask) -{ - // just add the appropraite events - if (mask & EV_READ && event_add(sock->ev_read, NULL)) - return SET_ERROR(SOCK_TCP_ERR(sock), ERR_EVENT_ADD); - - if (mask & EV_WRITE && event_add(sock->ev_write, NULL)) - return SET_ERROR(SOCK_TCP_ERR(sock), ERR_EVENT_ADD); - - // done return SUCCESS; } @@ -257,15 +97,17 @@ */ static void sock_tcp_connect_async_done (struct sock_tcp *sock, struct error_info *err) { + struct sock_stream *sock_base = SOCK_TCP_BASE(sock); + // free the addrinfo freeaddrinfo(sock->async_res); sock->async_res = sock->async_cur = NULL; // remove our event handler so the user can install their own - sock_tcp_deinit_ev(sock); + sock_fd_deinit_ev(SOCK_TCP_FD(sock)); // ok, run callback - SOCK_TCP_BASE(sock)->conn_cb_func(SOCK_TCP_BASE(sock), err, SOCK_TCP_BASE(sock)->conn_cb_arg); + sock_base->conn_cb_func(sock_base, err, sock_base->conn_cb_arg); } /** @@ -303,7 +145,7 @@ error: // close the socket - if ((tmp = sock_tcp_close(sock))) + if ((tmp = sock_fd_close(SOCK_TCP_FD(sock)))) log_warn("error closing socket after connect error: %s", error_name(tmp)); // log a warning @@ -324,20 +166,20 @@ return ERROR_CODE(err); // then, set it up as nonblocking - if ((ERROR_CODE(err) = sock_tcp_set_nonblock(sock, true))) + if ((ERROR_CODE(err) = sock_fd_set_nonblock(SOCK_TCP_FD(sock), true))) goto error; // then, initiate the connect - if ((ret = connect(sock->fd, addr->ai_addr, addr->ai_addrlen)) < 0 && errno != EINPROGRESS) + 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) { // ok, connect started, setup our completion callback - if ((ERROR_CODE(err) = sock_tcp_init_ev(sock, &sock_tcp_connect_cb, sock))) + if ((ERROR_CODE(err) = sock_fd_init_ev(SOCK_TCP_FD(sock), &sock_tcp_connect_cb, sock))) goto error; // enable for write - if ((ERROR_CODE(err) = sock_tcp_add_event(sock, EV_WRITE))) + if ((ERROR_CODE(err) = sock_fd_enable_events(SOCK_TCP_FD(sock), EV_WRITE))) goto error; // set the "current" address in case it fails and we need to try the next one @@ -354,7 +196,7 @@ error: // close the stuff we did open - if ((tmp = sock_tcp_close(sock))) + if ((tmp = sock_fd_close(SOCK_TCP_FD(sock)))) log_warn("error closing socket after connect error: %s", error_name(tmp)); return ERROR_CODE(err); @@ -375,7 +217,20 @@ RETURN_SET_ERROR_EXTRA(err, ERR_GETADDRINFO, ret); // start connecting - return sock_tcp_connect_async_continue(sock, sock->async_res, err); + if (sock_tcp_connect_async_continue(sock, sock->async_res, err)) + goto error; + + // ok + return SUCCESS; + +error: + // cleanup + if (sock->async_res) { + freeaddrinfo(sock->async_res); + sock->async_res = NULL; + } + + return ERROR_CODE(err); } err_t sock_tcp_connect_blocking (struct sock_tcp *sock, const char *hostname, const char *service, struct error_info *err) @@ -398,7 +253,7 @@ // try each result in turn for (r = res; r; r = r->ai_next) { // create the socket - if ((sock->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0) { + if ((SOCK_TCP_FD(sock)->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0) { // remember error SET_ERROR_ERRNO(err, ERR_SOCKET); @@ -407,13 +262,12 @@ } // connect to remote address - if (connect(sock->fd, r->ai_addr, r->ai_addrlen)) { + if (connect(SOCK_TCP_FD(sock)->fd, r->ai_addr, r->ai_addrlen)) { // remember error SET_ERROR_ERRNO(err, ERR_CONNECT); // close/invalidate socket - close(sock->fd); - sock->fd = -1; + sock_fd_close(SOCK_TCP_FD(sock)); // skip to next one continue; @@ -424,7 +278,7 @@ } // ensure we got some valid socket, else return last error code - if (sock->fd < 0) { + if (SOCK_TCP_FD(sock)->fd < 0) { // did we hit some error? if (IS_ERROR(err)) // return last error @@ -434,50 +288,13 @@ // no results return SET_ERROR(err, ERR_GETADDRINFO_EMPTY); } - + // ok, done return 0; } -err_t sock_tcp_set_nonblock (struct sock_tcp *sock, bool nonblock) -{ - // fcntl it - // XXX: maintain old flags? - if (fcntl(sock->fd, F_SETFL, nonblock ? O_NONBLOCK : 0) < 0) - RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_FCNTL); - - // ok - return SUCCESS; -} - -err_t sock_tcp_close (struct sock_tcp *sock) -{ - struct error_info *err = SOCK_TCP_ERR(sock); - - // no errors yet - RESET_ERROR(err); - - // must be connected - assert(sock->fd >= 0); - - // kill any events - sock_tcp_deinit_ev(sock); - - // close the socket itself - if (close(sock->fd)) - SET_ERROR_ERRNO(err, ERR_CLOSE); - - // invalidate - sock->fd = -1; - - return ERROR_CODE(err); -} - void sock_tcp_free (struct sock_tcp *sock) { - // must not be connected - assert(sock->fd < 0); - // free free(sock); }