예제 #1
0
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);
}
예제 #2
0
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);
    }
}