int pbpal_ntf_poll_away(struct pbpal_poll_data* data, int ms)
{
    int            i;
    int            rslt;
    fd_set         readfds;
    fd_set         writefds;
    fd_set         exceptfds;
    struct timeval timeout;

    if (0 == data->size) {
        return 0;
    }

    timeout.tv_sec  = ms / 1000;
    timeout.tv_usec = (ms % 1000) * 1000;

    memcpy(&readfds, &data->readfds, sizeof readfds);
    memcpy(&writefds, &data->writefds, sizeof writefds);
    memcpy(&exceptfds, &data->exceptfds, sizeof exceptfds);
    rslt = select(data->nfds + 1, &readfds, &writefds, &exceptfds, &timeout);
    if (SOCKET_ERROR == rslt) {
        int last_err =
#if defined(_WIN32)
            WSAGetLastError()
#else
            errno
#endif
            ;
        /* error? what to do about it? */
        PUBNUB_LOG_WARNING(
            "poll size = %u, error = %d\n", (unsigned)data->size, last_err);
        return -1;
    }
    for (i = 0; (i < (int)data->size) && (rslt > 0); ++i) {
        bool should_process = false;
        if (FD_ISSET(data->asocket[i], &readfds)) {
            should_process = true;
            --rslt;
        }
        if (FD_ISSET(data->asocket[i], &writefds)) {
            should_process = true;
            --rslt;
            PUBNUB_ASSERT_OPT(rslt >= 0);
        }
        if (FD_ISSET(data->asocket[i], &exceptfds)) {
            should_process = true;
            --rslt;
            PUBNUB_ASSERT_OPT(rslt >= 0);
        }
        if (should_process) {
            pbntf_requeue_for_processing(data->apb[i]);
        }
    }
    PUBNUB_ASSERT_OPT(0 == rslt);

    return rslt;
}
Пример #2
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;
}
Пример #3
0
bool pbpal_read_over(pubnub_t *pb)
{
    unsigned to_read = 0;
    WATCH_ENUM(pb->sock_state);
    WATCH_USHORT(pb->readlen);
    WATCH_USHORT(pb->left);
    WATCH_UINT(pb->len);

    if (pb->readlen == 0) {
        int recvres;
        to_read =  pb->len - pbpal_read_len(pb);
        if (to_read > pb->left) {
            to_read = pb->left;
        }
        recvres = socket_recv(pb->pal.socket, (char*)pb->ptr, to_read, 0);
        if (recvres <= 0) {
            /* This is error or connection close, which may be handled
               in some way...
             */
            return false;
        }
        pb->sock_state = STATE_READ;
        pb->readlen = recvres;
    } 

    pb->ptr += pb->readlen;
    pb->left -= pb->readlen;
    pb->readlen = 0;

    if (pbpal_read_len(pb) >= (int)pb->len) {
        /* If we have read all that was requested, we're done. */
        PUBNUB_LOG_TRACE("Read all that was to be read.\n");
        pb->sock_state = STATE_NONE;
        return true;
    }

    if ((pb->left > 0)) {
        pb->sock_state = STATE_NEWDATA_EXHAUSTED;
        return false;
    }

    /* Otherwise, we just filled the buffer, but we return 'true', to
     * enable the user to copy the data from the buffer to some other
     * storage.
     */
    PUBNUB_LOG_WARNING("Filled the buffer, but read %d and should %d\n", pbpal_read_len(pb), pb->len);
    pb->sock_state = STATE_NONE;
    return true;
}
Пример #4
0
static enum pubnub_res parse_pubnub_result(struct pubnub_ *pb)
{
    enum pubnub_res pbres = PNR_OK;
    switch (pb->trans) {
    case PBTT_SUBSCRIBE:
        if (pbcc_parse_subscribe_response(&pb->core) != 0) {
            PUBNUB_LOG_WARNING("parse_subscribe failed\n");
            pbres = PNR_FORMAT_ERROR;
        }
        break;
    case PBTT_PUBLISH:
        pbres = pbcc_parse_publish_response(&pb->core);
        if (pbres != PNR_OK) {
            PUBNUB_LOG_WARNING("parse_publish failed\n");
        }
        break;
    case PBTT_TIME:
        if (pbcc_parse_time_response(&pb->core) != 0) {
            PUBNUB_LOG_WARNING("parse_time failed\n");
            pbres = PNR_FORMAT_ERROR;
        }
        break;
    case PBTT_HISTORY:
        if (pbcc_parse_history_response(&pb->core) != 0) {
            PUBNUB_LOG_WARNING("parse_history failed\n");
            pbres = PNR_FORMAT_ERROR;
        }
        break;
    case PBTT_LEAVE:
    case PBTT_HERENOW:
    case PBTT_GLOBAL_HERENOW:
    case PBTT_WHERENOW:
    case PBTT_SET_STATE:
    case PBTT_STATE_GET:
    case PBTT_HEARTBEAT:
        if (pbcc_parse_presence_response(&pb->core) != 0) {
            PUBNUB_LOG_WARNING("parse_presence failed\n");
            pbres = PNR_FORMAT_ERROR;
        }
        break;
    case PBTT_REMOVE_CHANNEL_GROUP:
    case PBTT_REMOVE_CHANNEL_FROM_GROUP:
    case PBTT_ADD_CHANNEL_TO_GROUP:
    case PBTT_LIST_CHANNEL_GROUP:
        pbres = pbcc_parse_channel_registry_response(&pb->core);
        if (pbres != PNR_OK) {
            PUBNUB_LOG_WARNING("parse_channel_registry failed\n");
        }
        break;
    default:
        break;
    }

    return pbres;
}
Пример #5
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;
}
Пример #6
0
static void save_allocated(pubnub_t* pb)
{
#if defined PUBNUB_ASSERT_LEVEL_EX
    pubnub_mutex_init_static(m_lock);
    pubnub_mutex_lock(m_lock);
    if (m_n == m_cap) {
        pubnub_t** npalloc =
            (pubnub_t**)realloc(m_allocated, sizeof m_allocated[0] * (m_n + 1));
        if (NULL == npalloc) {
            PUBNUB_LOG_WARNING("Couldn't allocate memory for pubnub_alloc_std bookkeeping");
            pubnub_mutex_unlock(m_lock);
            return;
        }
        m_allocated        = npalloc;
        m_allocated[m_n++] = pb;
        m_cap              = m_n;
    }
    else {
        m_allocated[m_n++] = pb;
    }
    pubnub_mutex_unlock(m_lock);
#endif
}
Пример #7
0
static void finish(struct pubnub_ *pb)
{
    enum pubnub_res pbres = PNR_OK;

    pb->core.http_reply[pb->core.http_buf_len] = '\0';
    PUBNUB_LOG_TRACE("finish('%s')\n", pb->core.http_reply);

    switch (pb->trans) {
    case PBTT_SUBSCRIBE:
        if (pbcc_parse_subscribe_response(&pb->core) != 0) {
            PUBNUB_LOG_WARNING("parse_subscribe failed\n");
            pbres = PNR_FORMAT_ERROR;
        }
        break;
    case PBTT_PUBLISH:
        pbres = pbcc_parse_publish_response(&pb->core);
        if (pbres != PNR_OK) {
            PUBNUB_LOG_WARNING("parse_publish failed\n");
        }
        break;
    case PBTT_TIME:
        if (pbcc_parse_time_response(&pb->core) != 0) {
            PUBNUB_LOG_WARNING("parse_time failed\n");
            pbres = PNR_FORMAT_ERROR;
        }
        break;
    case PBTT_HISTORY:
        if (pbcc_parse_history_response(&pb->core) != 0) {
            PUBNUB_LOG_WARNING("parse_history failed\n");
            pbres = PNR_FORMAT_ERROR;
        }
        break;
    case PBTT_LEAVE:
    case PBTT_HERENOW:
    case PBTT_GLOBAL_HERENOW:
    case PBTT_WHERENOW:
    case PBTT_SET_STATE:
    case PBTT_STATE_GET:
    case PBTT_HEARTBEAT:
        if (pbcc_parse_presence_response(&pb->core) != 0) {
            PUBNUB_LOG_WARNING("parse_presence failed\n");
            pbres = PNR_FORMAT_ERROR;
        }
        break;
    case PBTT_REMOVE_CHANNEL_GROUP:
    case PBTT_REMOVE_CHANNEL_FROM_GROUP:
    case PBTT_ADD_CHANNEL_TO_GROUP:
    case PBTT_LIST_CHANNEL_GROUP:
        pbres = pbcc_parse_channel_registry_response(&pb->core);
        if (pbres != PNR_OK) {
            PUBNUB_LOG_WARNING("parse_channel_registry failed\n");
        }
        break;
    default:
        break;
    }

    if ((PNR_OK == pbres) && ((pb->http_code / 100) != 2)) {
        pbres = PNR_HTTP_ERROR;
    }

    outcome_detected(pb, pbres);
}
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 */
}
void socket_watcher_thread(void *arg)
{
    FILETIME prev_time;
    GetSystemTimeAsFileTime(&prev_time);

    for (;;) {
        const DWORD ms = 100;

        EnterCriticalSection(&m_watcher.queue_lock);
        if (m_watcher.queue_head != m_watcher.queue_tail) {
            pubnub_t *pbp = m_watcher.queue_apb[m_watcher.queue_tail++];
            LeaveCriticalSection(&m_watcher.queue_lock);
            if (pbp != NULL) {
                pubnub_mutex_lock(pbp->monitor);
                pbnc_fsm(pbp);
                pubnub_mutex_unlock(pbp->monitor);
            }
            EnterCriticalSection(&m_watcher.queue_lock);
            if (m_watcher.queue_tail == m_watcher.queue_size) {
                m_watcher.queue_tail = 0;
            }
        }
        LeaveCriticalSection(&m_watcher.queue_lock);

        EnterCriticalSection(&m_watcher.mutw);
        if (0 == m_watcher.apoll_size) {
            LeaveCriticalSection(&m_watcher.mutw);
            continue;
        }
        {
            int rslt = WSAPoll(m_watcher.apoll, m_watcher.apoll_size, ms);
            if (SOCKET_ERROR == rslt) {
                /* error? what to do about it? */
                PUBNUB_LOG_WARNING("poll size = %d, error = %d\n", m_watcher.apoll_size, WSAGetLastError());
            }
            else if (rslt > 0) {
                size_t i;
                size_t apoll_size = m_watcher.apoll_size;
                for (i = 0; i < apoll_size; ++i) {
                    if (m_watcher.apoll[i].revents & (POLLIN | POLLOUT)) {
                        pubnub_t *pbp = m_watcher.apb[i];
                        pubnub_mutex_lock(pbp->monitor);
                        pbnc_fsm(pbp);
                        if (apoll_size == m_watcher.apoll_size) {
                            if (m_watcher.apoll[i].events == POLLOUT) {
                                if ((pbp->state == PBS_WAIT_DNS_RCV) ||
                                    (pbp->state >= PBS_RX_HTTP_VER)) {
                                    m_watcher.apoll[i].events = POLLIN;
                                }
                            }
                            else {
                                if ((pbp->state > PBS_WAIT_DNS_RCV) &&
                                    (pbp->state < PBS_RX_HTTP_VER)) {
                                    m_watcher.apoll[i].events = POLLOUT;
                                }
                            }
                        }
                        else {
                            PUBNUB_ASSERT_OPT(apoll_size == m_watcher.apoll_size + 1);
                            apoll_size = m_watcher.apoll_size;
                            --i;
                        }
                        pubnub_mutex_unlock(pbp->monitor);
                    }
                }
            }
        }
        if (PUBNUB_TIMERS_API) {
            FILETIME current_time;
            int elapsed;
            GetSystemTimeAsFileTime(&current_time);
            elapsed = elapsed_ms(prev_time, current_time);
            if (elapsed > 0) {
                pubnub_t *expired = pubnub_timer_list_as_time_goes_by(&m_watcher.timer_head, elapsed);
                while (expired != NULL) {
                    pubnub_t *next = expired->next;

                    pubnub_mutex_lock(expired->monitor);
                    pbnc_stop(expired, PNR_TIMEOUT);
                    pubnub_mutex_unlock(expired->monitor);

                    expired->next = NULL;
                    expired->previous = NULL;
                    expired = next;
                }
                prev_time = current_time;
            }
        }

        LeaveCriticalSection(&m_watcher.mutw);
    }
}
enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb)
{
    SSL *ssl = NULL;
    int rslt;
    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_CONNECT));

    if (!pb->options.useSSL) {
        return resolv_and_connect_wout_SSL(pb);
    }

    if (NULL == pb->pal.ctx) {
        PUBNUB_LOG_TRACE("pb=%p: Don't have SSL_CTX\n", pb);
        pb->pal.ctx = SSL_CTX_new(SSLv23_client_method());
        if (NULL == pb->pal.ctx) {
            ERR_print_errors_cb(print_to_pubnub_log, NULL);
            PUBNUB_LOG_ERROR("pb=%p SSL_CTX_new failed\n", pb);
            return pbpal_resolv_resource_failure;
        }
        PUBNUB_LOG_TRACE("pb=%p: Got SSL_CTX\n", pb);
        add_pubnub_cert(pb->pal.ctx);
    }

    if (NULL == pb->pal.socket) {
        PUBNUB_LOG_TRACE("pb=%p: Don't have BIO\n", pb);
        pb->pal.socket = BIO_new_ssl_connect(pb->pal.ctx);
        if (PUBNUB_TIMERS_API) {
            pb->pal.connect_timeout = time(NULL)  + pb->transaction_timeout_ms/1000;
        }
    }
    else {
        BIO_get_ssl(pb->pal.socket, &ssl);
        if (NULL == ssl) {
            return resolv_and_connect_wout_SSL(pb);
        }
        ssl = NULL;
    }
    if (NULL == pb->pal.socket) {
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        return pbpal_resolv_resource_failure;
    }

    PUBNUB_LOG_TRACE("pb=%p: Using BIO == %p\n", pb, pb->pal.socket);

    BIO_get_ssl(pb->pal.socket, &ssl);
    PUBNUB_ASSERT(NULL != ssl);
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* maybe not auto_retry? */
    if (pb->pal.session != NULL) {
        SSL_set_session(ssl, pb->pal.session);
    }

    BIO_set_conn_hostname(pb->pal.socket, origin);
    BIO_set_conn_port(pb->pal.socket, "https");
    if (pb->pal.ip_timeout != 0) {
        if (pb->pal.ip_timeout < time(NULL)) {
            pb->pal.ip_timeout = 0;
        }
        else {
            PUBNUB_LOG_TRACE("SSL re-connect to: %d.%d.%d.%d\n", pb->pal.ip[0], pb->pal.ip[1], pb->pal.ip[2], pb->pal.ip[3]);
            BIO_set_conn_ip(pb->pal.socket, pb->pal.ip);
        }
    }
    
    BIO_set_nbio(pb->pal.socket, !pb->options.use_blocking_io);
    
    WATCH_ENUM(pb->options.use_blocking_io);
    if (BIO_do_connect(pb->pal.socket) <= 0) {
        if (BIO_should_retry(pb->pal.socket) && PUBNUB_TIMERS_API && (pb->pal.connect_timeout > time(NULL))) {
            PUBNUB_LOG_TRACE("pb=%p: BIO_should_retry\n", pb);
            return pbpal_connect_wouldblock;
        }
        /* Expire the IP for the next connect */
        pb->pal.ip_timeout = 0;
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        if (pb->pal.session != NULL) {
            SSL_SESSION_free(pb->pal.session);
            pb->pal.session = NULL;
        }
        PUBNUB_LOG_ERROR("pb=%p: BIO_do_connect failed\n", pb);
        return pbpal_connect_failed;
    }

    PUBNUB_LOG_TRACE("pb=%p: BIO connected\n", pb);
    {
        int fd = BIO_get_fd(pb->pal.socket, NULL);
        socket_set_rcv_timeout(fd, pb->transaction_timeout_ms);
    }

    rslt = SSL_get_verify_result(ssl);
    if (rslt != X509_V_OK) {
        PUBNUB_LOG_WARNING("pb=%p: SSL_get_verify_result() failed == %d(%s)\n", pb, rslt, X509_verify_cert_error_string(rslt));
        ERR_print_errors_cb(print_to_pubnub_log, NULL);
        if (pb->options.fallbackSSL) {
            BIO_free_all(pb->pal.socket);
            pb->pal.socket = NULL;
            return resolv_and_connect_wout_SSL(pb);
        }
        return pbpal_connect_failed;
    }

    PUBNUB_LOG_INFO("pb=%p: SSL session reused: %s\n", pb, SSL_session_reused(ssl) ? "yes" : "no");
    if (pb->pal.session != NULL) {
        SSL_SESSION_free(pb->pal.session);
    }
    pb->pal.session = SSL_get1_session(ssl);
    if (0 == pb->pal.ip_timeout) {
        pb->pal.ip_timeout = SSL_SESSION_get_time(pb->pal.session) + SSL_SESSION_get_timeout(pb->pal.session);
        memcpy(pb->pal.ip, BIO_get_conn_ip(pb->pal.socket), 4);
    }
    PUBNUB_LOG_TRACE("pb=%p: SSL connected to IP: %d.%d.%d.%d\n", pb, pb->pal.ip[0], pb->pal.ip[1], pb->pal.ip[2], pb->pal.ip[3]);

    return pbpal_connect_success;
}
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;
    }
}