static ret_t connect_to (cherokee_downloader_t *downloader, cherokee_buffer_t *host, cuint_t port, int protocol) { ret_t ret; cherokee_socket_t *sock = &downloader->socket; TRACE(ENTRIES, "host=%s port=%d proto=%d\n", host->buf, port, protocol); /* Create the socket */ ret = cherokee_socket_create_fd (sock, AF_INET); if (unlikely(ret != ret_ok)) return ret_error; /* Set the port */ SOCKET_SIN_PORT(sock) = htons(port); /* Supposing it's an IP: convert it. */ ret = cherokee_socket_pton (sock, host); if (ret != ret_ok) { /* Oops! It might be a hostname. Try to resolve it. */ ret = cherokee_socket_gethostbyname (sock, host); if (unlikely(ret != ret_ok)) return ret_error; } /* Connect to server */ ret = cherokee_socket_connect (sock); TRACE(ENTRIES, "socket=%p ret=%d\n", sock, ret); if (unlikely(ret != ret_ok)) return ret; /* Is this connection TLS? */ if ((protocol == https) && (sock->cryptor != NULL)) { ret = cherokee_socket_init_client_tls (sock, host); if (ret != ret_ok) return ret; } TRACE(ENTRIES, "Exits ok; socket=%p\n", sock); return ret_ok; }
static ret_t find_empty_port (int starting, int *port) { ret_t ret; cherokee_socket_t s; int p = starting; cherokee_buffer_t bind_ = CHEROKEE_BUF_INIT; cherokee_buffer_add_str (&bind_, "127.0.0.1"); cherokee_socket_init (&s); while (true) { cherokee_socket_create_fd (&s, AF_INET); ret = cherokee_socket_bind (&s, p, &bind_); cherokee_socket_close (&s); if (ret == ret_ok) break; p += 1; if (unlikely (p > 0xFFFF)) { goto error; } } cherokee_socket_mrproper (&s); cherokee_buffer_mrproper (&bind_); *port = p; return ret_ok; error: cherokee_socket_close (&s); cherokee_socket_mrproper (&s); cherokee_buffer_mrproper (&bind_); return ret_error; }
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); }