enum pbpal_resolv_n_connect_result pbpal_check_resolv_and_connect(pubnub_t *pb)
{
    if (PUBNUB_USE_ADNS) {
        uint8_t const* const origin = (uint8_t*)(PUBNUB_ORIGIN_SETTABLE ? pb->origin : PUBNUB_ORIGIN);
        struct sockaddr_in dns_server;
        struct sockaddr_in dest;
        int skt = pb->pal.socket;
        dns_server.sin_family = AF_INET;
        dns_server.sin_port = htons(DNS_PORT);
        inet_pton(AF_INET, "8.8.8.8", &dns_server.sin_addr.s_addr);
        switch (read_response(skt, (struct sockaddr*)&dns_server, origin, &dest)) {
        case -1: return pbpal_resolv_failed_rcv;
        case +1: return pbpal_resolv_rcv_wouldblock;
        case 0: break;
        }
        socket_close(skt);
        skt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (SOCKET_INVALID == skt) {
            return pbpal_connect_resource_failure;
        }
        pb->pal.socket = skt;
        dest.sin_port = htons(HTTP_PORT);
        if (SOCKET_ERROR == connect(skt, (struct sockaddr*)&dest, sizeof dest)) {
            return socket_would_block() ? pbpal_connect_wouldblock : pbpal_connect_failed;
        }

        return pbpal_connect_success;
    }

    /* Under regular BSD-ish sockets, this function should not be
       called unless using async DNS, so this is an error */
    return pbpal_connect_failed;
}
Exemplo n.º 2
0
enum pubnub_res pbpal_line_read_status(pubnub_t *pb)
{
    uint8_t c;

    if (pb->readlen == 0) {
        int recvres = socket_recv(pb->pal.socket, (char*)pb->ptr, pb->left, 0);
        if (recvres < 0) {
            if (socket_timed_out()) {
                return PNR_TIMEOUT;
            }
            if (PUBNUB_BLOCKING_IO_SETTABLE && pb->options.use_blocking_io) {
                return PNR_IO_ERROR;
            }
            return socket_would_block() ? PNR_IN_PROGRESS : PNR_IO_ERROR;
        }
        else if (0 == recvres) {
            return PNR_TIMEOUT;
        }
        PUBNUB_LOG_TRACE("have new data of length=%d: %s\n", recvres, pb->ptr);
        pb->sock_state = STATE_READ_LINE;
        pb->readlen = recvres;
    }

    while (pb->left > 0 && pb->readlen > 0) {
        c = *pb->ptr++;

        --pb->readlen;
        --pb->left;
        
        if (c == '\n') {
            int read_len = pbpal_read_len(pb);
            PUBNUB_LOG_TRACE("\n found: "); WATCH_INT(read_len); WATCH_USHORT(pb->readlen);
            pb->sock_state = STATE_NONE;
            return PNR_OK;
        }
    }

    if (pb->left == 0) {
        /* Buffer has been filled, but new-line char has not been
         * found.  We have to "reset" this "mini-fsm", as otherwise we
         * won't read anything any more. This means that we have lost
         * the current contents of the buffer, which is bad. In some
         * general code, that should be reported, as the caller could
         * save the contents of the buffer somewhere else or simply
         * decide to ignore this line (when it does end eventually).
         */
        pb->sock_state = STATE_NONE;
    }
    else {
        pb->sock_state = STATE_NEWDATA_EXHAUSTED;
    }

    return PNR_IN_PROGRESS;
}
Exemplo n.º 3
0
int read_response(int skt, struct sockaddr *dest, unsigned char const *host, struct sockaddr_in *resolved_addr)
{
    uint8_t buf[8192];
    struct DNS_HEADER *dns = (struct DNS_HEADER *)buf;
    uint8_t *qname = buf + sizeof *dns;
    uint8_t *reader;
    int i, msg_size;

    socklen_t addr_size = sizeof *dest;
    msg_size = recvfrom(skt, (char*)buf, sizeof buf, 0, dest, &addr_size);
    if (msg_size <= 0) {
        return socket_would_block() ? +1 : -1;
    }
 
    reader = buf + sizeof *dns + strlen((const char*)qname)+1 + sizeof(struct QUESTION);

    PUBNUB_LOG_TRACE("DNS response has: %d Questions, %d Answers, %d Auth. Servers, %d Additional records.\n",
                     ntohs(dns->q_count) ,ntohs(dns->ans_count) ,ntohs(dns->auth_count),ntohs(dns->add_count));
 
    for (i = 0; i < ntohs(dns->ans_count); ++i) {
        uint8_t name[256];
        size_t to_skip;
        struct R_DATA* prdata;
        size_t r_data_len;

        dns_label_decode(name, sizeof name, reader, buf, msg_size, &to_skip);
        prdata = (struct R_DATA*)(reader + to_skip);
        r_data_len = ntohs(prdata->data_len);
        reader += to_skip + sizeof *prdata;

        PUBNUB_LOG_TRACE("DNS answer: %s, to_skip:%zu, type=%d, data_len=%zu\n", name, to_skip, ntohs(prdata->type), r_data_len);
  
        if (ntohs(prdata->type) == dnsA) {
            if (r_data_len != 4) {
                PUBNUB_LOG_WARNING("unexpected answer R_DATA length %zu\n", r_data_len);
                continue;
            }
            PUBNUB_LOG_TRACE("Got IPv4: %d.%d.%d.%d\n", reader[0],reader[1],reader[2],reader[3]);
            resolved_addr->sin_family = AF_INET;
            memcpy(&resolved_addr->sin_addr, reader, 4);
            reader += r_data_len;
        }
        else {
            /* Don't care about other resource types, for now */
            reader += r_data_len;
        }
    }

    /* Don't care about Authoritative Servers or Additional records, for now */
 
    return 0;
}
Exemplo n.º 4
0
int read_dns_response(int skt, struct sockaddr* dest, struct sockaddr_in* resolved_addr)
{
    uint8_t  buf[8192];
    int      msg_size;
    unsigned addr_size = sizeof *dest;

    msg_size = recvfrom(skt, (char*)buf, sizeof buf, 0, dest, CAST & addr_size);
    if (msg_size <= 0) {
        return socket_would_block() ? +1 : -1;
    }
            resolved_addr->sin_family = AF_INET;

    return pubnub_pick_resolved_address(buf,
                                        (size_t)msg_size,
                                        (struct pubnub_ipv4_address*)&(resolved_addr->sin_addr.s_addr));
}
static enum pbpal_resolv_n_connect_result connect_TCP_socket(pubnub_t *pb,
                                                             struct sockaddr_in dest,
                                                             const uint16_t port)
{
    pb->pal.socket  = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (SOCKET_INVALID == pb->pal.socket) {

        return pbpal_connect_resource_failure;
    }
    pb->options.use_blocking_io = false;
    pbpal_set_blocking_io(pb);
    socket_disable_SIGPIPE(pb->pal.socket);
    dest.sin_port = htons(port);
    if (SOCKET_ERROR == connect(pb->pal.socket, (struct sockaddr*)&dest, sizeof dest)) {
        return socket_would_block() ? pbpal_connect_wouldblock : pbpal_connect_failed;
    }

    return pbpal_connect_success;
}
Exemplo n.º 6
0
int pbpal_send_status(pubnub_t *pb)
{
    int r;
    if (0 == pb->sendlen) {
        return 0;
    }
    r = socket_send(pb->pal.socket, (char*)pb->sendptr, pb->sendlen, 0);
    if (r < 0) {
        return socket_would_block() ? +1 : -1;
    }
    if (r > pb->sendlen) {
        PUBNUB_LOG_WARNING("That's some over-achieving socket!\n");
        r = pb->sendlen;
    }
    pb->sendptr += r;
    pb->sendlen -= r;

    return (0 == pb->sendlen) ? 0 : +1;
}
Exemplo n.º 7
0
int send_dns_query(int skt, struct sockaddr const* dest, char const* host)
{
    uint8_t buf[4096];
    int     to_send;
    int                sent_to;

    if (-1 == pubnub_prepare_dns_request(buf, sizeof buf, host, &to_send)) {
        PUBNUB_LOG_ERROR("Couldn't prepare dns request! : #prepared bytes=%d\n", to_send);
        return -1;
    }
    TRACE_SOCKADDR("Sending DNS query to: ", dest);
    sent_to = sendto(skt, (char*)buf, to_send, 0, dest, sizeof *dest);
    if (sent_to <= 0) {
        return socket_would_block() ? +1 : -1;
    }
    else if (to_send != sent_to) {
        PUBNUB_LOG_ERROR("sendto() sent %d out of %d bytes!\n", sent_to, to_send);
        return -1;
    }
    return 0;
}
Exemplo n.º 8
0
int send_dns_query(int skt, struct sockaddr const *dest, unsigned char *host)
{
    uint8_t buf[8192];
    struct DNS_HEADER *dns = (struct DNS_HEADER *)buf;
    uint8_t *qname = buf + sizeof *dns;
    struct QUESTION *qinfo;
 
    dns->id = htons(33); /* in lack of a better ID */
    dns->options = htons(dnsoptRDmask);
    dns->q_count = htons(1);
    dns->ans_count = dns->auth_count = dns->add_count = 0;
 
    dns_qname_encode(qname, sizeof buf - sizeof *dns, host);

    qinfo =(struct QUESTION*)(buf + sizeof *dns + strlen((const char*)qname) + 1);
    qinfo->qtype = htons(dnsA);
    qinfo->qclass = htons(dnsqclassInternet);

    if (sendto(skt, buf, sizeof *dns + strlen((char*)qname)+1 + sizeof *qinfo, 0, dest, sizeof *dest) < 0) {
        return socket_would_block() ? +1 : -1;
    }

    return 0;
}
enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb)
{
    int error;
    uint16_t port = HTTP_PORT;
    char const* origin;

#ifdef PUBNUB_CALLBACK_API
    struct sockaddr_in dest;

    prepare_port_and_hostname(pb, &port, &origin);
#if PUBNUB_PROXY_API
    if (0 != pb->proxy_ip_address.ipv4[0]) {
        struct pubnub_ipv4_address* p_dest_addr = (struct pubnub_ipv4_address*)&(dest.sin_addr.s_addr);
        memset(&dest, '\0', sizeof dest);
        memcpy(p_dest_addr->ipv4, pb->proxy_ip_address.ipv4, sizeof p_dest_addr->ipv4);
        dest.sin_family = AF_INET;

        return connect_TCP_socket(pb, dest, port);
    }
#endif

    if (SOCKET_INVALID == pb->pal.socket) {
        pb->pal.socket  = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    }
    if (SOCKET_INVALID == pb->pal.socket) {
        return pbpal_resolv_resource_failure;
    }
    pb->options.use_blocking_io = false;
    pbpal_set_blocking_io(pb);
    dest.sin_family = AF_INET;
    dest.sin_port = htons(DNS_PORT);
    get_dns_ip(&dest);
    error = send_dns_query(pb->pal.socket, (struct sockaddr*)&dest, origin);
    if (error < 0) {
        return pbpal_resolv_failed_send;
    }
    else if (error > 0) {
        return pbpal_resolv_send_wouldblock;
    }
    return pbpal_resolv_sent;

#else
    char port_string[20];
    struct addrinfo *result;
    struct addrinfo *it;
    struct addrinfo hint;

    hint.ai_socktype = SOCK_STREAM;
    hint.ai_family = AF_UNSPEC;
    hint.ai_protocol = hint.ai_flags = hint.ai_addrlen = 0;
    hint.ai_addr = NULL;
    hint.ai_canonname = NULL;
    hint.ai_next = NULL;

    prepare_port_and_hostname(pb, &port, &origin);
    snprintf(port_string, sizeof port_string, "%hu", port);
    error = getaddrinfo(origin, port_string, &hint, &result);
    if (error != 0) {
        return pbpal_resolv_failed_processing;
    }

    for (it = result; it != NULL; it = it->ai_next) {
        pb->pal.socket = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
        if (pb->pal.socket == SOCKET_INVALID) {
            continue;
        }
        pbpal_set_blocking_io(pb);
        if (connect(pb->pal.socket, it->ai_addr, it->ai_addrlen) == SOCKET_ERROR) {
            if (socket_would_block()) {
                error = 1;
                break;
            }
            else {
                PUBNUB_LOG_WARNING("socket connect() failed, will try another IP address, if available\n");
                socket_close(pb->pal.socket);
                pb->pal.socket = SOCKET_INVALID;
                continue;
            }
        }
        break;
    }
    freeaddrinfo(result);

    if (NULL == it) {
        return pbpal_connect_failed;
    }

    socket_set_rcv_timeout(pb->pal.socket, pb->transaction_timeout_ms);
    socket_disable_SIGPIPE(pb->pal.socket);

    return error ? pbpal_connect_wouldblock : pbpal_connect_success;
#endif /* PUBNUB_CALLBACK_API */
}
enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb)
{
    int error;
    char const* origin = PUBNUB_ORIGIN_SETTABLE ? pb->origin : PUBNUB_ORIGIN;

    PUBNUB_ASSERT(pb_valid_ctx_ptr(pb));
    PUBNUB_ASSERT_OPT((pb->state == PBS_READY) || (pb->state == PBS_WAIT_DNS_SEND)  || (pb->state == PBS_WAIT_DNS_RCV));

    if (PUBNUB_USE_ADNS) {
        struct sockaddr_in dest;
        int skt = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

        if (SOCKET_INVALID == skt) {
            return pbpal_resolv_resource_failure;
        }
        pb->options.use_blocking_io = false;
        pbpal_set_blocking_io(pb);
        dest.sin_family = AF_INET;
        dest.sin_port = htons(DNS_PORT);
        inet_pton(AF_INET, "8.8.8.8", &dest.sin_addr.s_addr);
        error = send_dns_query(skt, (struct sockaddr*)&dest, (unsigned char*)origin);
        if (error < 0) {
            socket_close(skt);
            return pbpal_resolv_failed_send;
        }
        else if (error > 0) {
            return pbpal_resolv_send_wouldblock;
        }
        pb->pal.socket = skt;
        return pbpal_resolv_sent;
    }
    else {
        struct addrinfo *result;
        struct addrinfo *it;
        struct addrinfo hint;

        hint.ai_socktype = SOCK_STREAM;
        hint.ai_family = AF_UNSPEC;
        hint.ai_protocol = hint.ai_flags = hint.ai_addrlen = 0;
        hint.ai_addr = NULL;
        hint.ai_canonname = NULL;
        hint.ai_next = NULL;
        error = getaddrinfo(origin, HTTP_PORT_STRING, &hint, &result);
        if (error != 0) {
            return pbpal_resolv_failed_processing;
        }

        for (it = result; it != NULL; it = it->ai_next) {
            pb->pal.socket = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
            if (pb->pal.socket == SOCKET_INVALID) {
                continue;
            }
            pbpal_set_blocking_io(pb);
            if (connect(pb->pal.socket, it->ai_addr, it->ai_addrlen) == SOCKET_ERROR) {
                if (socket_would_block()) {
                    error = 1;
                    break;
                }
                else {
                    PUBNUB_LOG_WARNING("socket connect() failed, will try another IP address, if available\n");
                    socket_close(pb->pal.socket);
                    pb->pal.socket = SOCKET_INVALID;
                    continue;
                }
            }
            break;
        }
        freeaddrinfo(result);

        if (NULL == it) {
            return pbpal_connect_failed;
        }

        socket_set_rcv_timeout(pb->pal.socket, pb->transaction_timeout_ms);

        return error ? pbpal_connect_wouldblock : pbpal_connect_success;
    }
}