ret_t cherokee_socket_accept_fd (cherokee_socket_t *server_socket, int *new_fd, cherokee_sockaddr_t *sa) { ret_t ret; socklen_t len; int new_socket; /* Get the new connection */ len = sizeof (cherokee_sockaddr_t); do { new_socket = accept (server_socket->socket, &sa->sa, &len); } while ((new_socket == -1) && (errno == EINTR)); if (new_socket < 0) { return ret_error; } /* It'd nice to be able to reuse the address even if the * socket is still in TIME_WAIT statue (2*RTT ~ 120 seg) */ cherokee_fd_set_reuseaddr (new_socket); /* Close-on-exec: Child processes won't inherit this fd */ cherokee_fd_set_closexec (new_socket); /* Enables nonblocking I/O. */ ret = cherokee_fd_set_nonblocking (new_socket, true); if (ret != ret_ok) { LOG_WARNING (CHEROKEE_ERROR_SOCKET_NON_BLOCKING, new_socket); cherokee_fd_close (new_socket); return ret_error; } /* Disable Nagle's algorithm for this connection * so that there is no delay involved when sending data * which don't fill up a full IP datagram. */ ret = cherokee_fd_set_nodelay (new_socket, true); if (ret != ret_ok) { LOG_WARNING_S (CHEROKEE_ERROR_SOCKET_RM_NAGLES); cherokee_fd_close (new_socket); return ret_error; } *new_fd = new_socket; return ret_ok; }
ret_t cherokee_proxy_util_init_socket (cherokee_socket_t *socket, cherokee_source_t *src) { ret_t ret; cherokee_resolv_cache_t *resolv; TRACE (ENTRIES, "Initializing proxy socket: %s\n", cherokee_string_is_ipv6 (&src->host) ? "IPv6": "IPv4"); /* Family */ if (cherokee_string_is_ipv6 (&src->host)) { ret = cherokee_socket_set_client (socket, AF_INET6); } else { ret = cherokee_socket_set_client (socket, AF_INET); } if (unlikely(ret != ret_ok)) return ret_error; /* TCP port */ SOCKET_SIN_PORT(socket) = htons (src->port); /* IP host */ ret = cherokee_resolv_cache_get_default (&resolv); if (unlikely (ret != ret_ok)) { return ret_error; } ret = cherokee_resolv_cache_get_host (resolv, &src->host, socket); if (ret != ret_ok) { return ret_error; } /* Set a few properties */ cherokee_fd_set_closexec (socket->socket); cherokee_fd_set_nonblocking (socket->socket, true); cherokee_fd_set_nodelay (socket->socket, true); return ret_ok; }
ret_t cherokee_downloader_async_connect (cherokee_downloader_async_t *adownloader) { ret_t ret; cherokee_downloader_t *down = DOWNLOADER(adownloader); cherokee_fdpoll_t *fdpoll = adownloader->fdpoll_ref; if (fdpoll == NULL) return ret_error; ret = cherokee_downloader_connect (down); if (ret != ret_ok) return ret; ret = cherokee_fd_set_nonblocking (down->socket.socket, true); if (ret != ret_ok) return ret; ret = cherokee_fdpoll_add (fdpoll, down->socket.socket, FDPOLL_MODE_WRITE); if (ret != ret_ok) return ret; adownloader->fd_added = down->socket.socket; return ret_ok; }
ret_t cherokee_source_connect (cherokee_source_t *src, cherokee_socket_t *sock) { ret_t ret; cherokee_resolv_cache_t *resolv; /* Short path: it's already connecting */ if (sock->socket >= 0) { return cherokee_socket_connect (sock); } /* Create the new socket and set the target IP info */ if (! cherokee_buffer_is_empty (&src->unix_socket)) { /* Create the socket descriptor */ ret = cherokee_socket_create_fd (sock, AF_UNIX); if (unlikely (ret != ret_ok)) { return ret; } ret = cherokee_socket_gethostbyname (sock, &src->unix_socket); if (unlikely (ret != ret_ok)) { return ret; } } else { cherokee_boolean_t tested_all; const struct addrinfo *addr; const struct addrinfo *addr_info = NULL; /* Query the resolv cache */ ret = cherokee_resolv_cache_get_default (&resolv); if (unlikely (ret!=ret_ok)) { return ret; } ret = cherokee_resolv_cache_get_addrinfo (resolv, &src->host, &addr_info); if ((ret != ret_ok) || (addr_info == NULL)) { return ret_error; } /* Current address */ if (src->addr_current) { tested_all = false; addr = src->addr_current; } else { tested_all = true; addr = addr_info; } /* Create the fd for the address family * * Iterates through the different addresses of the * host and stores a pointer to the first one with * a supported family. */ while (addr != NULL) { ret = cherokee_socket_create_fd (sock, addr->ai_family); #ifdef TRACE_ENABLED if (cherokee_trace_is_tracing()) { ret_t ret2; char ip[46]; ret2 = cherokee_ntop (addr->ai_family, addr->ai_addr, ip, sizeof(ip)); if (ret2 == ret_ok) { TRACE (ENTRIES, "Connecting to %s, ret=%d\n", ip, ret); } } #endif if (ret == ret_ok) { src->addr_current = addr; break; } addr = addr->ai_next; if (addr == NULL) { if (tested_all) { return ret_error; } tested_all = true; src->addr_current = NULL; addr = addr_info; continue; } cherokee_socket_close(sock); } /* Update the new socket with the address info */ switch (src->addr_current->ai_family) { case AF_INET: SOCKET_ADDR_IPv4(sock)->sin_port = htons(src->port); break; case AF_INET6: SOCKET_ADDR_IPv6(sock)->sin6_port = htons(src->port); break; default: SHOULDNT_HAPPEN; return ret_error; } ret = cherokee_socket_update_from_addrinfo (sock, src->addr_current, 0); if (unlikely (ret != ret_ok)) { return ret_error; } } /* Set non-blocking */ ret = cherokee_fd_set_nonblocking (sock->socket, true); if (unlikely (ret != ret_ok)) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_SOURCE_NONBLOCK, sock->socket); } /* Set close-on-exec and reuse-address */ cherokee_fd_set_closexec (sock->socket); cherokee_fd_set_reuseaddr (sock->socket); return cherokee_socket_connect (sock); }
ret_t cherokee_socket_accept_fd (cherokee_socket_t *server_socket, int *new_fd, cherokee_sockaddr_t *sa) { ret_t ret; socklen_t len; int new_socket; /* Get the new connection */ len = sizeof (cherokee_sockaddr_t); do { new_socket = accept (server_socket->socket, &sa->sa, &len); } while ((new_socket == -1) && (errno == EINTR)); if (new_socket < 0) { return ret_error; } #if 0 /* DISABLED */ /* Deal with the FIN_WAIT2 state */ re = 1; re = setsockopt (new_socket, SOL_SOCKET, SO_KEEPALIVE, &re, sizeof(re)); if (re == -1) { LOG_ERRNO (errno, cherokee_err_warning, CHEROKEE_ERROR_SOCKET_SET_KEEPALIVE, new_socket); } linger.l_onoff = 1; linger.l_linger = SECONDS_TO_LINGER; re = setsockopt (new_socket, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); if (re == -1) { LOG_ERRNO (errno, cherokee_err_warning, CHEROKEE_ERROR_SOCKET_SET_LINGER, new_socket); } #endif /* Close-on-exec: Child processes won't inherit this fd */ cherokee_fd_set_closexec (new_socket); /* Enables nonblocking I/O. */ ret = cherokee_fd_set_nonblocking (new_socket, true); if (ret != ret_ok) { LOG_WARNING (CHEROKEE_ERROR_SOCKET_NON_BLOCKING, new_socket); cherokee_fd_close (new_socket); return ret_error; } /* Disable Nagle's algorithm for this connection * so that there is no delay involved when sending data * which don't fill up a full IP datagram. */ ret = cherokee_fd_set_nodelay (new_socket, true); if (ret != ret_ok) { LOG_WARNING_S (CHEROKEE_ERROR_SOCKET_RM_NAGLES); cherokee_fd_close (new_socket); return ret_error; } *new_fd = new_socket; return ret_ok; }