void get_request(int server_sock) { int fd; /* socket */ struct SOCKADDR remote_addr; /* address */ struct SOCKADDR salocal; unsigned int remote_addrlen = sizeof (struct SOCKADDR); request *conn; /* connection */ size_t len; #ifndef INET6 remote_addr.S_FAMILY = (sa_family_t) 0xdead; #endif fd = accept(server_sock, (struct sockaddr *) &remote_addr, &remote_addrlen); if (fd == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { /* abnormal error */ WARN("accept"); } else /* no requests */ ; pending_requests = 0; return; } if (fd >= FD_SETSIZE) { log_error("Got fd >= FD_SETSIZE."); close(fd); return; } #ifdef DEBUGNONINET /* This shows up due to race conditions in some Linux kernels when the client closes the socket sometime between the select() and accept() syscalls. Code and description by Larry Doolittle <*****@*****.**> */ #define HEX(x) (((x)>9)?(('a'-10)+(x)):('0'+(x))) if (remote_addr.sin_family != PF_INET) { struct sockaddr *bogus = (struct sockaddr *) &remote_addr; char *ap, ablock[44]; int i; close(fd); log_error_time(); for (ap = ablock, i = 0; i < remote_addrlen && i < 14; i++) { *ap++ = ' '; *ap++ = HEX((bogus->sa_data[i] >> 4) & 0x0f); *ap++ = HEX(bogus->sa_data[i] & 0x0f); } *ap = '\0'; fprintf(stderr, "non-INET connection attempt: socket %d, " "sa_family = %hu, sa_data[%d] = %s\n", fd, bogus->sa_family, remote_addrlen, ablock); return; } #endif /* XXX Either delete this, or document why it's needed */ /* Pointed out 3-Oct-1999 by Paul Saab <*****@*****.**> */ #ifdef REUSE_EACH_CLIENT_CONNECTION_SOCKET if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt, sizeof (sock_opt))) == -1) { DIE("setsockopt: unable to set SO_REUSEADDR"); } #endif len = sizeof (salocal); if (getsockname(fd, (struct sockaddr *) &salocal, &len) != 0) { WARN("getsockname"); close(fd); return; } conn = new_request(); if (!conn) { close(fd); return; } conn->fd = fd; conn->status = READ_HEADER; conn->header_line = conn->client_stream; conn->time_last = current_time; conn->kacount = ka_max; if (ascii_sockaddr (&salocal, conn->local_ip_addr, sizeof (conn->local_ip_addr)) == NULL) { WARN("ascii_sockaddr failed"); close(fd); enqueue(&request_free, conn); return; } /* nonblocking socket */ if (set_nonblock_fd(conn->fd) == -1) { WARN("fcntl: unable to set new socket to non-block"); close(fd); enqueue(&request_free, conn); return; } /* set close on exec to true */ if (fcntl(conn->fd, F_SETFD, 1) == -1) { WARN("fctnl: unable to set close-on-exec for new socket"); close(fd); enqueue(&request_free, conn); return; } #ifdef TUNE_SNDBUF /* Increase buffer size if we have to. * Only ask the system the buffer size on the first request, * and assume all subsequent sockets have the same size. */ if (system_bufsize == 0) { len = sizeof (system_bufsize); if (getsockopt (conn->fd, SOL_SOCKET, SO_SNDBUF, &system_bufsize, &len) == 0 && len == sizeof (system_bufsize)) { ; } else { WARN("getsockopt(SNDBUF)"); system_bufsize = 1; } } if (system_bufsize < sockbufsize) { if (setsockopt (conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &sockbufsize, sizeof (sockbufsize)) == -1) { WARN("setsockopt: unable to set socket buffer size"); #ifdef DIE_ON_ERROR_TUNING_SNDBUF exit(errno); #endif /* DIE_ON_ERROR_TUNING_SNDBUF */ } } #endif /* TUNE_SNDBUF */ /* for log file and possible use by CGI programs */ if (ascii_sockaddr (&remote_addr, conn->remote_ip_addr, sizeof (conn->remote_ip_addr)) == NULL) { WARN("ascii_sockaddr failed"); close(fd); enqueue(&request_free, conn); return; } /* for possible use by CGI programs */ conn->remote_port = net_port(&remote_addr); status.requests++; #ifdef USE_TCPNODELAY /* Thanks to Jef Poskanzer <*****@*****.**> for this tweak */ { int one = 1; if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &one, sizeof (one)) == -1) { DIE("setsockopt: unable to set TCP_NODELAY"); } } #endif total_connections++; /* gotta have some breathing room */ if (total_connections > max_connections) { pending_requests = 0; #ifndef NO_RATE_LIMIT /* have to fake an http version */ conn->http_version = HTTP10; conn->method = M_GET; send_r_service_unavailable(conn); conn->status = DONE; #endif /* NO_RATE_LIMIT */ } enqueue(&request_ready, conn); }
int main(int argc, char *argv[]) { if (argc == 2 && !tox_strncasecmp(argv[1], "-h", 3)) { printf("Usage (connected) : %s [--ipv4|--ipv6] IP PORT KEY\n", argv[0]); printf("Usage (unconnected): %s [--ipv4|--ipv6]\n", argv[0]); exit(0); } /* let user override default by cmdline */ bool ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */ int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled); if (argvoffset < 0) { exit(1); } /* Initialize networking - Bind to ip 0.0.0.0 / [::] : PORT */ IP ip; ip_init(&ip, ipv6enabled); Logger *logger = logger_new(); if (MIN_LOGGER_LEVEL == LOGGER_LEVEL_TRACE || MIN_LOGGER_LEVEL == LOGGER_LEVEL_DEBUG) { logger_callback_log(logger, print_log, nullptr, nullptr); } Mono_Time *mono_time = mono_time_new(); DHT *dht = new_dht(logger, mono_time, new_networking(logger, ip, PORT), true); Onion *onion = new_onion(mono_time, dht); Onion_Announce *onion_a = new_onion_announce(mono_time, dht); #ifdef DHT_NODE_EXTRA_PACKETS bootstrap_set_callbacks(dht_get_net(dht), DHT_VERSION_NUMBER, DHT_MOTD, sizeof(DHT_MOTD)); #endif if (!(onion && onion_a)) { printf("Something failed to initialize.\n"); exit(1); } perror("Initialization"); manage_keys(dht); printf("Public key: "); uint32_t i; #ifdef TCP_RELAY_ENABLED #define NUM_PORTS 3 uint16_t ports[NUM_PORTS] = {443, 3389, PORT}; TCP_Server *tcp_s = new_TCP_server(ipv6enabled, NUM_PORTS, ports, dht_get_self_secret_key(dht), onion); if (tcp_s == nullptr) { printf("TCP server failed to initialize.\n"); exit(1); } #endif const char *const public_id_filename = "PUBLIC_ID.txt"; FILE *file = fopen(public_id_filename, "w"); if (file == nullptr) { printf("Could not open file \"%s\" for writing. Exiting...\n", public_id_filename); exit(1); } for (i = 0; i < 32; i++) { const uint8_t *const self_public_key = dht_get_self_public_key(dht); printf("%02X", self_public_key[i]); fprintf(file, "%02X", self_public_key[i]); } fclose(file); printf("\n"); printf("Port: %u\n", net_ntohs(net_port(dht_get_net(dht)))); if (argc > argvoffset + 3) { printf("Trying to bootstrap into the network...\n"); uint16_t port = net_htons(atoi(argv[argvoffset + 2])); uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]); int res = dht_bootstrap_from_address(dht, argv[argvoffset + 1], ipv6enabled, port, bootstrap_key); free(bootstrap_key); if (!res) { printf("Failed to convert \"%s\" into an IP address. Exiting...\n", argv[argvoffset + 1]); exit(1); } } int is_waiting_for_dht_connection = 1; uint64_t last_LANdiscovery = 0; lan_discovery_init(dht); while (1) { mono_time_update(mono_time); if (is_waiting_for_dht_connection && dht_isconnected(dht)) { printf("Connected to other bootstrap node successfully.\n"); is_waiting_for_dht_connection = 0; } do_dht(dht); if (mono_time_is_timeout(mono_time, last_LANdiscovery, is_waiting_for_dht_connection ? 5 : LAN_DISCOVERY_INTERVAL)) { lan_discovery_send(net_htons(PORT), dht); last_LANdiscovery = mono_time_get(mono_time); } #ifdef TCP_RELAY_ENABLED do_TCP_server(tcp_s, mono_time); #endif networking_poll(dht_get_net(dht), nullptr); c_sleep(1); } }