ret_t cherokee_socket_pton (cherokee_socket_t *socket, cherokee_buffer_t *host) { int re; switch (SOCKET_AF(socket)) { case AF_INET: #ifdef HAVE_INET_PTON re = inet_pton (AF_INET, host->buf, &SOCKET_SIN_ADDR(socket)); if (re <= 0) return ret_error; #else re = inet_aton (host->buf, &SOCKET_SIN_ADDR(socket)); if (re == 0) return ret_error; #endif break; #ifdef HAVE_IPV6 case AF_INET6: re = inet_pton (AF_INET6, host->buf, &SOCKET_SIN6_ADDR(socket)); if (re <= 0) return ret_error; break; #endif default: LOG_CRITICAL (CHEROKEE_ERROR_SOCKET_BAD_FAMILY, SOCKET_AF(socket)); return ret_error; } return ret_ok; }
ret_t cherokee_socket_ntop (cherokee_socket_t *socket, char *dst, size_t cnt) { if (unlikely (SOCKET_FD(socket) < 0)) { return ret_error; } return cherokee_ntop (SOCKET_AF(socket), (struct sockaddr *) &SOCKET_ADDR(socket), dst, cnt); }
ret_t cherokee_socket_create_fd (cherokee_socket_t *sock, unsigned short int family) { /* Create the socket */ do { sock->socket = socket (family, SOCK_STREAM, 0); } while ((sock->socket == -1) && (errno == EINTR)); if (sock->socket < 0) { #ifdef HAVE_IPV6 if ((family == AF_INET6) && (errno == EAFNOSUPPORT)) { LOG_WARNING (CHEROKEE_ERROR_SOCKET_NO_IPV6); } else #endif { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_SOCKET_NEW_SOCKET); return ret_error; } } /* Set the family length */ switch (family) { case AF_INET: sock->client_addr_len = sizeof (struct sockaddr_in); memset (&sock->client_addr, 0, sock->client_addr_len); break; #ifdef HAVE_IPV6 case AF_INET6: sock->client_addr_len = sizeof (struct sockaddr_in6); memset (&sock->client_addr, 0, sock->client_addr_len); break; #endif #ifdef HAVE_SOCKADDR_UN case AF_UNIX: memset (&sock->client_addr, 0, sizeof (struct sockaddr_un)); break; #endif default: SHOULDNT_HAPPEN; return ret_error; } /* Set the family */ SOCKET_AF(sock) = family; return ret_ok; }
ret_t cherokee_socket_gethostbyname (cherokee_socket_t *socket, cherokee_buffer_t *hostname) { #ifndef _WIN32 ret_t ret; cherokee_resolv_cache_t *resolv = NULL; /* Unix sockets */ if (SOCKET_AF(socket) == AF_UNIX) { memset ((char*) SOCKET_SUN_PATH(socket), 0, sizeof (SOCKET_ADDR_UNIX(socket))); SOCKET_ADDR_UNIX(socket)->sun_family = AF_UNIX; if (hostname->buf[0] == '@') { strncpy (SOCKET_SUN_PATH (socket) + 1, hostname->buf + 1, (sizeof (SOCKET_ADDR_UNIX(socket)->sun_path) - 1) - sizeof(short)); SOCKET_SUN_PATH (socket)[0] = 0; } else { strncpy (SOCKET_SUN_PATH (socket), hostname->buf, sizeof (SOCKET_ADDR_UNIX(socket)->sun_path) - sizeof(short)); } return ret_ok; } /* TCP sockets */ ret = cherokee_resolv_cache_get_default (&resolv); if (ret != ret_ok) { return ret_error; } ret = cherokee_resolv_cache_get_host (resolv, hostname, socket); if (ret != ret_ok) { return ret_error; } return ret_ok; #else SHOULDNT_HAPPEN; return ret_no_sys; #endif }
ret_t cherokee_socket_update_from_addrinfo (cherokee_socket_t *socket, const struct addrinfo *addr, cuint_t num) { const struct addrinfo *ai; if (unlikely (addr == NULL)) return ret_error; /* Find the right address */ ai = addr; while (num > 0) { num -= 1; ai = ai->ai_next; if (ai == NULL) { return ret_not_found; } } /* Copy the information */ SOCKET_AF(socket) = addr->ai_family; socket->client_addr_len = addr->ai_addrlen; switch (addr->ai_family) { case AF_INET: memcpy (&SOCKET_SIN_ADDR(socket), &((struct sockaddr_in *) ai->ai_addr)->sin_addr, sizeof(struct in_addr)); break; case AF_INET6: memcpy (&SOCKET_SIN6_ADDR(socket), &((struct sockaddr_in6 *) ai->ai_addr)->sin6_addr, sizeof(struct in6_addr)); break; default: SHOULDNT_HAPPEN; return ret_error; } return ret_ok; }
ret_t cherokee_socket_gethostbyname (cherokee_socket_t *socket, cherokee_buffer_t *hostname) { if (SOCKET_AF(socket) == AF_UNIX) { #ifdef _WIN32 SHOULDNT_HAPPEN; return ret_no_sys; #else memset ((char*) SOCKET_SUN_PATH(socket), 0, sizeof (SOCKET_ADDR_UNIX(socket))); SOCKET_ADDR_UNIX(socket)->sun_family = AF_UNIX; strncpy (SOCKET_SUN_PATH (socket), hostname->buf, sizeof (SOCKET_ADDR_UNIX(socket)->sun_path) - sizeof(short)); return ret_ok; #endif } return cherokee_gethostbyname (hostname->buf, &SOCKET_SIN_ADDR(socket)); }
ret_t cherokee_socket_bind (cherokee_socket_t *sock, cuint_t port, cherokee_buffer_t *listen_to) { /* Bind */ switch (SOCKET_AF(sock)) { case AF_INET: return cherokee_bind_v4 (sock, port, listen_to); #ifdef HAVE_IPV6 case AF_INET6: return cherokee_bind_v6 (sock, port, listen_to); #endif #ifdef HAVE_SOCKADDR_UN case AF_UNIX: return cherokee_bind_local (sock, listen_to); #endif default: break; } SHOULDNT_HAPPEN; return ret_error; }
ret_t cherokee_socket_connect (cherokee_socket_t *sock) { int r; int err; TRACE (ENTRIES",connect", "connect type=%s\n", SOCKET_AF(sock) == AF_INET ? "AF_INET" : SOCKET_AF(sock) == AF_INET6 ? "AF_INET6" : SOCKET_AF(sock) == AF_UNIX ? "AF_UNIX" : "Unknown"); do { switch (SOCKET_AF(sock)) { case AF_INET: r = connect (SOCKET_FD(sock), (struct sockaddr *) &SOCKET_ADDR(sock), sizeof(struct sockaddr_in)); break; #ifdef HAVE_IPV6 case AF_INET6: r = connect (SOCKET_FD(sock), (struct sockaddr *) &SOCKET_ADDR(sock), sizeof(struct sockaddr_in6)); break; #endif #ifdef HAVE_SOCKADDR_UN case AF_UNIX: if (SOCKET_SUN_PATH (socket)[0] != 0) { r = connect (SOCKET_FD(sock), (struct sockaddr *) &SOCKET_ADDR(sock), SUN_LEN (SOCKET_ADDR_UNIX(sock))); } else { r = connect (SOCKET_FD(sock), (struct sockaddr *) &SOCKET_ADDR(sock), SUN_ABSTRACT_LEN (SOCKET_ADDR_UNIX(sock))); } break; #endif default: SHOULDNT_HAPPEN; return ret_no_sys; } } while ((r == -1) && (errno == EINTR)); if (r < 0) { err = SOCK_ERRNO(); TRACE (ENTRIES",connect", "connect error=%d '%s'\n", err, strerror(err)); switch (err) { case EISCONN: break; case EINVAL: case ENOENT: case ECONNRESET: case ECONNREFUSED: case EADDRNOTAVAIL: return ret_deny; case ETIMEDOUT: return ret_error; case EAGAIN: case EALREADY: case EINPROGRESS: #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif return ret_eagain; default: LOG_ERRNO_S (errno, cherokee_err_error, CHEROKEE_ERROR_SOCKET_CONNECT); return ret_error; } } TRACE (ENTRIES",connect", "succeed. fd=%d\n", SOCKET_FD(sock)); sock->status = socket_reading; return ret_ok; }