コード例 #1
0
/* Initialize networking.
 * Bind to ip and port.
 * ip must be in network order EX: 127.0.0.1 = (7F000001).
 * port is in host byte order (this means don't worry about it).
 *
 *  return Networking_Core object if no problems
 *  return NULL if there are problems.
 */
Networking_Core *new_networking(IP ip, uint16_t port)
{
#ifdef TOX_ENABLE_IPV6

    /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */
    if (ip.family != AF_INET && ip.family != AF_INET6) {
#ifdef DEBUG
        fprintf(stderr, "Invalid address family: %u\n", ip.family);
#endif
        return NULL;
    }

#endif

    if (at_startup() != 0)
        return NULL;

    Networking_Core *temp = calloc(1, sizeof(Networking_Core));

    if (temp == NULL)
        return NULL;

#ifdef TOX_ENABLE_IPV6
    temp->family = ip.family;
#else
    temp->family = AF_INET;
#endif
    temp->port = 0;

    /* Initialize our socket. */
    /* add log message what we're creating */
    temp->sock = socket(temp->family, SOCK_DGRAM, IPPROTO_UDP);

    /* Check for socket error. */
#ifdef WIN32

    if (temp->sock == INVALID_SOCKET) { /* MSDN recommends this. */
        free(temp);
        return NULL;
    }

#else

    if (temp->sock < 0) {
#ifdef DEBUG
        fprintf(stderr, "Failed to get a socket?! %u, %s\n", errno, strerror(errno));
#endif
        free(temp);
        return NULL;
    }

#endif

    /* Functions to increase the size of the send and receive UDP buffers.
     */
    int n = 1024 * 1024 * 2;
    setsockopt(temp->sock, SOL_SOCKET, SO_RCVBUF, (char *)&n, sizeof(n));
    setsockopt(temp->sock, SOL_SOCKET, SO_SNDBUF, (char *)&n, sizeof(n));

    /* Enable broadcast on socket */
    int broadcast = 1;
    setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast));

    /* Set socket nonblocking. */
#ifdef WIN32
    /* I think this works for Windows. */
    u_long mode = 1;
    /* ioctl(sock, FIONBIO, &mode); */
    ioctlsocket(temp->sock, FIONBIO, &mode);
#else
    fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1);
#endif

    /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */
    uint16_t *portptr = NULL;
    struct sockaddr_storage addr;
    size_t addrsize;
#ifdef TOX_ENABLE_IPV6

    if (temp->family == AF_INET) {
        IP4 ip4 = ip.ip4;
#else
    IP4 ip4 = ip;
#endif
        addrsize = sizeof(struct sockaddr_in);
        struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
        addr4->sin_family = AF_INET;
        addr4->sin_port = 0;
        addr4->sin_addr = ip4.in_addr;

        portptr = &addr4->sin_port;
#ifdef TOX_ENABLE_IPV6
    } else if (temp->family == AF_INET6)
    {
        addrsize = sizeof(struct sockaddr_in6);
        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
        addr6->sin6_family = AF_INET6;
        addr6->sin6_port = 0;
        addr6->sin6_addr = ip.ip6.in6_addr;

        addr6->sin6_flowinfo = 0;
        addr6->sin6_scope_id = 0;

        portptr = &addr6->sin6_port;
    } else
        return NULL;

    if (ip.family == AF_INET6)
    {
        char ipv6only = 0;
#ifdef LOGGING
        errno = 0;
        int res =
#endif
            setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only));
#ifdef LOGGING

        if (res < 0) {
            sprintf(logbuffer,
                    "Failed to enable dual-stack on IPv6 socket, won't be able to receive from/send to IPv4 addresses. (%u, %s)\n",
                    errno, strerror(errno));
            loglog(logbuffer);
        } else
            loglog("Embedded IPv4 addresses enabled successfully.\n");

#endif

        /* multicast local nodes */
        struct ipv6_mreq mreq;
        memset(&mreq, 0, sizeof(mreq));
        mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF;
        mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02;
        mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
        mreq.ipv6mr_interface = 0;
#ifdef LOGGING
        errno = 0;
        res =
#endif
            setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
#ifdef LOGGING

        if (res < 0) {
            sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n",
                    errno, strerror(errno));
            loglog(logbuffer);
        } else
            loglog("Local multicast group FF02::1 joined successfully.\n");

#endif
    }

#endif

    /* a hanging program or a different user might block the standard port;
     * as long as it isn't a parameter coming from the commandline,
     * try a few ports after it, to see if we can find a "free" one
     *
     * if we go on without binding, the first sendto() automatically binds to
     * a free port chosen by the system (i.e. anything from 1024 to 65535)
     *
     * returning NULL after bind fails has both advantages and disadvantages:
     * advantage:
     *   we can rely on getting the port in the range 33445..33450, which
     *   enables us to tell joe user to open their firewall to a small range
     *
     * disadvantage:
     *   some clients might not test return of tox_new(), blindly assuming that
     *   it worked ok (which it did previously without a successful bind)
     */
    uint16_t port_to_try = port;
    *portptr = htons(port_to_try);
    int tries, res;

    for (tries = TOX_PORTRANGE_FROM; tries <= TOX_PORTRANGE_TO; tries++)
    {
        res = bind(temp->sock, (struct sockaddr *)&addr, addrsize);

        if (!res) {
            temp->port = *portptr;
#ifdef LOGGING
            loginit(temp->port);

            sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port));
            loglog(logbuffer);
#endif

            /* errno isn't reset on success, only set on failure, the failed
             * binds with parallel clients yield a -EPERM to the outside if
             * errno isn't cleared here */
            if (tries > 0)
                errno = 0;

            return temp;
        }

        port_to_try++;

        if (port_to_try > TOX_PORTRANGE_TO)
            port_to_try = TOX_PORTRANGE_FROM;

        *portptr = htons(port_to_try);
    }

#ifdef DEBUG
    fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno,
            strerror(errno), ip_ntoa(&ip), port);
#endif
    kill_networking(temp);
    return NULL;
}
コード例 #2
0
int addr_resolve(const char *address, IP *to, IP *extra)
{
    if (!address || !to)
        return 0;

    sa_family_t family;
#ifdef TOX_ENABLE_IPV6
    family = to->family;
#else
    family = AF_INET;
#endif

    struct addrinfo *server = NULL;
    struct addrinfo *walker = NULL;
    struct addrinfo  hints;
    int              rc;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family   = family;
    hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.

    if (at_startup() != 0)
        return 0;

    rc = getaddrinfo(address, NULL, &hints, &server);

    // Lookup failed.
    if (rc != 0) {
        return 0;
    }

#ifdef TOX_ENABLE_IPV6
    IP4 ip4;
    memset(&ip4, 0, sizeof(ip4));
    IP6 ip6;
    memset(&ip6, 0, sizeof(ip6));
#endif

    for (walker = server; (walker != NULL) && (rc != 3); walker = walker->ai_next) {
        switch (walker->ai_family) {
            case AF_INET:
                if (walker->ai_family == family) { /* AF_INET requested, done */
                    struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
#ifdef TOX_ENABLE_IPV6
                    to->ip4.in_addr = addr->sin_addr;
#else
                    to->in_addr = addr->sin_addr;
#endif
                    rc = 3;
                }

#ifdef TOX_ENABLE_IPV6
                else if (!(rc & 1)) { /* AF_UNSPEC requested, store away */
                    struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
                    ip4.in_addr = addr->sin_addr;
                    rc |= 1;
                }

#endif
                break; /* switch */
#ifdef TOX_ENABLE_IPV6

            case AF_INET6:
                if (walker->ai_family == family) { /* AF_INET6 requested, done */
                    if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
                        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
                        to->ip6.in6_addr = addr->sin6_addr;
                        rc = 3;
                    }
                } else if (!(rc & 2)) { /* AF_UNSPEC requested, store away */
                    if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
                        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
                        ip6.in6_addr = addr->sin6_addr;
                        rc |= 2;
                    }
                }

                break; /* switch */
#endif
        }
    }

#ifdef TOX_ENABLE_IPV6

    if (to->family == AF_UNSPEC) {
        if (rc & 2) {
            to->family = AF_INET6;
            to->ip6 = ip6;

            if ((rc & 1) && (extra != NULL)) {
                extra->family = AF_INET;
                extra->ip4 = ip4;
            }
        } else if (rc & 1) {
            to->family = AF_INET;
            to->ip4 = ip4;
        } else
            rc = 0;
    }

#endif


    freeaddrinfo(server);
    return rc;
}
コード例 #3
0
ファイル: network.c プロジェクト: Tooker/ProjectTox-Core
/* Initialize networking.
 * Bind to ip and port.
 * ip must be in network order EX: 127.0.0.1 = (7F000001).
 * port is in host byte order (this means don't worry about it).
 *
 * returns Networking_Core object if no problems
 * returns NULL if there are problems.
 */
Networking_Core *new_networking(IP ip, uint16_t port)
{
    if (at_startup() != 0)
        return NULL;

    /* Initialize our socket. */
    Networking_Core *temp = calloc(1, sizeof(Networking_Core));

    if (temp == NULL)
        return NULL;

    temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    /* Check for socket error. */
#ifdef WIN32

    if (temp->sock == INVALID_SOCKET) { /* MSDN recommends this. */
        free(temp);
        return NULL;
    }

#else

    if (temp->sock < 0) {
        free(temp);
        return NULL;
    }

#endif

    /* Functions to increase the size of the send and receive UDP buffers.
     * NOTE: Uncomment if necessary.
     */
    /*
    int n = 1024 * 1024 * 2;
    if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&n, sizeof(n)) == -1)
    {
        return -1;
    }

    if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&n, sizeof(n)) == -1)
        return -1;
    */

    /* Enable broadcast on socket. */
    int broadcast = 1;
    setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast));

    /* Set socket nonblocking. */
#ifdef WIN32
    /* I think this works for Windows. */
    u_long mode = 1;
    /* ioctl(sock, FIONBIO, &mode); */
    ioctlsocket(temp->sock, FIONBIO, &mode);
#else
    fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1);
#endif

    /* Bind our socket to port PORT and address 0.0.0.0 */
    ADDR addr = {AF_INET, htons(port), ip};
    bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr));
    return temp;
}