diff --git a/.pubnub.yml b/.pubnub.yml index 6aef6e12..a7b3a193 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,7 +1,16 @@ name: c-core -version: 2.8.2 +version: 2.8.3 scm: github.com/pubnub/c-core changelog: + - version: v2.8.3 + date: May 31, 2019 + changes: + - type: enhancement + text: Use TTL from DNS response (cache resolved addresses) + - type: enhancement + text: Better identification of the platform we run on + - type: enhancement + text: Detect authenticating proxy that works incorrectly - version: v2.8.2 date: Apr 29, 2019 changes: diff --git a/core/pbgzip_compress.c b/core/pbgzip_compress.c index acb2b755..3f25749a 100644 --- a/core/pbgzip_compress.c +++ b/core/pbgzip_compress.c @@ -33,11 +33,11 @@ static enum pubnub_res deflate_total_to_context_buffer(pubnub_t* pb, if (message_size == unpacked_size) { uint32_t crc; size_t packed_size = GZIP_HEADER_LENGTH_BYTES + compressed + GZIP_FOOTER_LENGTH_BYTES; - long diff = unpacked_size - packed_size; + long diff = (long)unpacked_size - (long)packed_size; PUBNUB_LOG_TRACE("deflate_total_to_context_buffer(pb=%p) - " "Length after compression: %zu bytes - " - "compression ratio=%ld o/oo\n", + "compression ratio=%zd o/oo\n", pb, packed_size, (diff*1000)/unpacked_size); diff --git a/core/pbgzip_decompress.c b/core/pbgzip_decompress.c index f956c590..0af2ca71 100644 --- a/core/pbgzip_decompress.c +++ b/core/pbgzip_decompress.c @@ -30,12 +30,12 @@ static enum pubnub_res inflate_total_to_context_buffer(pubnub_t* pb, return PNR_OK; } else { - PUBNUB_LOG_ERROR("Decompressed length[%u] is smaller than the " - "'unpacked_size' value[%u]!\n" + PUBNUB_LOG_ERROR("Decompressed length[%zu] is smaller than the " + "'unpacked_size' value[%zu]!\n" "(Unpacked:['%.*s'])\n", - (unsigned)dst_buf_size, - (unsigned)out_len, - (int)dst_buf_size, + dst_buf_size, + out_len, + (long)dst_buf_size, pb->core.decomp_http_reply); } break; @@ -69,8 +69,8 @@ static enum pubnub_res inflate_total_to_context_buffer(pubnub_t* pb, static void swap_reply_buffer(pubnub_t* pb) { #if PUBNUB_DYNAMIC_REPLY_BUFFER - char* aux_buf = pb->core.http_reply; - unsigned aux_buf_len = pb->core.http_buf_len; + char* aux_buf = pb->core.http_reply; + size_t aux_buf_len = pb->core.http_buf_len; pb->core.http_reply = pb->core.decomp_http_reply; pb->core.http_buf_len = pb->core.decomp_buf_size; pb->core.decomp_http_reply = aux_buf; @@ -85,6 +85,7 @@ static void swap_reply_buffer(pubnub_t* pb) return; } + static enum pubnub_res inflate_total(pubnub_t* pb, const uint8_t* p_in_buf_next, size_t in_buf_size, @@ -96,7 +97,7 @@ static enum pubnub_res inflate_total(pubnub_t* pb, char* newbuf = (char*)realloc(pb->core.decomp_http_reply, out_len + 1); if (NULL == newbuf) { PUBNUB_LOG_ERROR("Failed to reallocate decompression buffer!\n" - "Out length:%lu\n", + "Out length:%zu\n", out_len); return PNR_REPLY_TOO_BIG; } @@ -105,7 +106,7 @@ static enum pubnub_res inflate_total(pubnub_t* pb, #else if (out_len >= sizeof pb->core.decomp_http_reply) { PUBNUB_LOG_ERROR("Decompression buffer too small!\n" - "Size of buffer:%lu - Out length:%lu\n", + "Size of buffer:%zu - Out length:%zu\n", sizeof pb->core.decomp_http_reply, out_len); return PNR_REPLY_TOO_BIG; @@ -120,6 +121,7 @@ static enum pubnub_res inflate_total(pubnub_t* pb, return result; } + enum pubnub_res pbgzip_decompress(pubnub_t* pb) { const uint8_t* data = (uint8_t*)pb->core.http_reply; @@ -132,16 +134,14 @@ enum pubnub_res pbgzip_decompress(pubnub_t* pb) return PNR_BAD_COMPRESSION_FORMAT; } if (data[2] != 8) { - PUBNUB_LOG_ERROR("Not used 'deflate' compression method(8)!\n" - "Compression method value:%u\n", + PUBNUB_LOG_ERROR("Unknown compression method %uX - only 'deflate'(8) " + "is supported!\n", (unsigned)data[2]); return PNR_BAD_COMPRESSION_FORMAT; } if (data[3] != 0) { - PUBNUB_LOG_ERROR( - "Pubnub gzip doesn't expect any flags on filename and extras!\n" - "Got gzip flags:%u\n", - (unsigned)data[3]); + PUBNUB_LOG_ERROR("GZIP flags should be 0, but are %uX\n", + (unsigned)data[3]); return PNR_BAD_COMPRESSION_FORMAT; } /* Unpacked message size is placed at the end of the 'gzip' formated message @@ -151,11 +151,11 @@ enum pubnub_res pbgzip_decompress(pubnub_t* pb) unpacked_size |= (uint32_t)data[size - 3] << 8; unpacked_size |= (uint32_t)data[size - 2] << 16; unpacked_size |= (uint32_t)data[size - 1] << 24; - PUBNUB_LOG_TRACE("pbgzip_decompress(pb=%p)-Length before:%lu and after " + PUBNUB_LOG_TRACE("pbgzip_decompress(pb=%p)-Length before:%zu and after " "decompresion:%lu\n", pb, - (long unsigned)size, - (long unsigned)unpacked_size); + size, + (unsigned long)unpacked_size); size -= (GZIP_HEADER_LENGTH_BYTES + GZIP_FOOTER_LENGTH_BYTES); return inflate_total( diff --git a/core/pbhttp_digest.c b/core/pbhttp_digest.c index c7b95b16..67f282c3 100644 --- a/core/pbhttp_digest.c +++ b/core/pbhttp_digest.c @@ -1,6 +1,7 @@ /* -*- c-file-style:"stroustrup"; indent-tabs-mode: nil -*- */ #include "pubnub_internal.h" +#include "core/pubnub_proxy_core.h" #include "core/pbhttp_digest.h" #include "lib/md5/pbmd5.h" @@ -12,54 +13,18 @@ #include -void pbhttp_digest_init(struct pbhttp_digest_context *ctx) +void pbhttp_digest_init(struct pbhttp_digest_context* ctx) { PUBNUB_ASSERT_OPT(ctx != NULL); - ctx->realm[0] = ctx->nonce[0] = ctx->opaque[0] = '\0'; + ctx->nonce[0] = ctx->opaque[0] = '\0'; ctx->algorithm = pbhtdigalUnknown; ctx->qop = pbhtdigqopNone; ctx->client_nonce[0] = '\0'; - ctx->nc = 1; -} - - -static char const* get_next_key_value(char const* s, pubnub_chamebl_t *key, pubnub_chamebl_t *val) -{ - s += strspn(s, " \t"); - key->ptr = (char*)s; - key->size = strcspn(s, "= \t"); - s += key->size; - s += strspn(s, " \t"); - if (*s != '=') { - return NULL; - } - s += 1 + strspn(s + 1, " \t"); - val->ptr = (char*)s; - if (*s == '"') { - char const* esc; - char const* end = s + 1; - for (esc = strstr(end, "\\\""); esc != NULL; esc = strstr(end, "\\\"")) { - end = esc + 2; - } - val->size = end - s + strcspn(end, "\"") + 1; - if (*s != '"') { - return NULL; - } - s += val->size; - } - else { - val->size = strcspn(s, " \t"); - s += val->size; - } - s += strspn(s, " \t"); - if (*s == ',') { - ++s; - } - return ('\0' == *s) ? NULL : s; + ctx->nc = 1; } @@ -80,60 +45,65 @@ char const* pubnub_find_str_in_chamebl(pubnub_chamebl_t chamebl, char const* s) } -#define LIT_STR_EQ(lit, str) (0 == memcmp(lit, str, sizeof lit - 1)) - - -void pbhttp_digest_parse_header(struct pbhttp_digest_context *ctx, char const* header) +enum pbhttp_digest_parse_header_rslt +pbhttp_digest_parse_header(struct pbhttp_digest_context* ctx, + char const* header, + char* realm) { - char empty_str[] = { '\0' }; - char const *s = header; + char empty_str[] = { '\0' }; + char const* s = header; + bool realm_found = false; + bool equal_consecutive_realms; do { - pubnub_chamebl_t key = { empty_str, 0 }; + pubnub_chamebl_t key = { empty_str, 0 }; pubnub_chamebl_t value = { empty_str, 0 }; - s = get_next_key_value(s, &key, &value); + s = pbproxy_get_next_key_value(s, &key, &value); if (LIT_STR_EQ("realm", key.ptr)) { - const size_t maxrealm = sizeof ctx->realm / sizeof ctx->realm[0] - 1; - if (value.size > maxrealm) { - PUBNUB_LOG_ERROR("Received `realm` too long: %zu, maximum possible %zu\n", value.size, maxrealm); - return; - } - if ('"' != *value.ptr) { - PUBNUB_LOG_ERROR("Received 'realm' is not quoted\n"); - return; + if (pbproxy_check_realm(&value) != 0) { + return pbhtdig_ParameterError; } - if (value.size <= 2) { - PUBNUB_LOG_ERROR("Received 'realm' is too short (length = %zu)\n", value.size); - return; + realm_found = true; + equal_consecutive_realms = + (strncmp(realm, value.ptr + 1, value.size - 2) == 0) + && (strlen(realm) == (value.size - 2)); + if (!equal_consecutive_realms) { + memcpy(realm, value.ptr + 1, value.size - 2); + realm[value.size - 2] = '\0'; } - memcpy(ctx->realm, value.ptr + 1, value.size - 2); - ctx->realm[value.size - 2] = '\0'; } else if (LIT_STR_EQ("nonce", key.ptr)) { const size_t maxnonce = sizeof ctx->nonce / sizeof ctx->nonce[0] - 1; - size_t actual_size = value.size - 2; + size_t actual_size = value.size - 2; if ('"' != *value.ptr) { PUBNUB_LOG_ERROR("Received 'nonce' is not quoted\n"); - return; + return pbhtdig_ParameterError; } if (value.size <= 2) { - PUBNUB_LOG_ERROR("Received 'nonce' is too short (length = %zu)\n", value.size); - return; + PUBNUB_LOG_ERROR("Received 'nonce' is too short (length %zu)\n", + value.size); + return pbhtdig_ParameterError; } if (actual_size > maxnonce) { - PUBNUB_LOG_ERROR("Received `nonce` too long: %zu, maximum possible %zu\n", value.size, maxnonce); - return; + PUBNUB_LOG_ERROR( + "Received `nonce` too long: %zu, maximum %zu\n", + value.size, + maxnonce); + return pbhtdig_ParameterError; } memcpy(ctx->nonce, value.ptr + 1, actual_size); ctx->nonce[actual_size] = '\0'; - ctx->nc = 1; + ctx->nc = 1; } else if (LIT_STR_EQ("opaque", key.ptr)) { const size_t maxopaque = sizeof ctx->opaque / sizeof ctx->opaque[0] - 1; if (value.size > maxopaque) { - PUBNUB_LOG_ERROR("Received `opaque` too long: %zu, maximum possible %zu\n", value.size, maxopaque); - return; + PUBNUB_LOG_ERROR( + "Received `opaque` too long: %zu, maximum possible %zu\n", + value.size, + maxopaque); + return pbhtdig_ParameterError; } memcpy(ctx->opaque, value.ptr, value.size); ctx->opaque[value.size] = '\0'; @@ -146,7 +116,9 @@ void pbhttp_digest_parse_header(struct pbhttp_digest_context *ctx, char const* h ctx->algorithm = pbhtdigalMD5; } else { - PUBNUB_LOG_WARNING("Unknown or unsupported HTTP digest algorithm field: %.*s\n", (int)value.size, value.ptr); + PUBNUB_LOG_WARNING("Unsupported HTTP digest algorithm: %.*s\n", + (int)value.size, + value.ptr); } } else if (LIT_STR_EQ("qop", key.ptr)) { @@ -164,27 +136,39 @@ void pbhttp_digest_parse_header(struct pbhttp_digest_context *ctx, char const* h } else { /* We ignore `domain`, it has no meaning for HTTP proxies. - + We ignore `charset` as it is only available in latest specs (RFC 7616) and actually has only UTF-8 as the allowed value. - + We ignore `userhash` as it is only available in latest specs (RFC 7616) and we don't support it yet. */ - PUBNUB_LOG_INFO("Unknown or unsupported HTTP digest auth field: %.*s\n", (int)key.size, key.ptr); + PUBNUB_LOG_INFO("Unsupported HTTP digest auth field: %.*s\n", + (int)key.size, + key.ptr); } } while (s != NULL); + if (realm_found) { + return equal_consecutive_realms ? pbhtdig_EqualConsecutiveRealms + : pbhtdig_DifferentConsecutiveRealms; + } + + return pbhtdig_RealmNotFound; } char const* pbhttp_digest_qop2str(enum pbhttp_digest_qop e) { switch (e) { - case pbhtdigqopNone: return ""; - case pbgtdigqop_auth: return "auth"; - case pbgtdigqop_auth_int: return "auth-int"; - default: return "(enum pbhttp_digest_qop)?!"; + case pbhtdigqopNone: + return ""; + case pbgtdigqop_auth: + return "auth"; + case pbgtdigqop_auth_int: + return "auth-int"; + default: + return "(enum pbhttp_digest_qop)?!"; } } @@ -192,39 +176,51 @@ char const* pbhttp_digest_qop2str(enum pbhttp_digest_qop e) char const* pbhttp_digest_algorithm2str(enum pbhttp_digest_algorithm e) { switch (e) { - case pbhtdigalUnknown: return ""; - case pbhtdigalMD5: return "MD5"; - case pbhtdigalMD5_sess: return "MD5-sess"; - default: return "(enum pbhttp_digest_algorithm)?!"; + case pbhtdigalUnknown: + return ""; + case pbhtdigalMD5: + return "MD5"; + case pbhtdigalMD5_sess: + return "MD5-sess"; + default: + return "(enum pbhttp_digest_algorithm)?!"; } } -#define md5_final_to_str(x, dstr) do { \ - uint8_t M_md5_store_[16]; \ - PUBNUB_ASSERT_OPT(sizeof(dstr) == 33); \ - pbmd5_final((x), M_md5_store_); \ - pbmd5_to_str(M_md5_store_, (dstr)); \ - } while(0) +#define md5_final_to_str(x, dstr) \ + do { \ + uint8_t M_md5_store_[16]; \ + PUBNUB_ASSERT_OPT(sizeof(dstr) == 33); \ + pbmd5_final((x), M_md5_store_); \ + pbmd5_to_str(M_md5_store_, (dstr)); \ + } while (0) #define MD5_OF_EMPTY_MESSAGE "d41d8cd98f00b204e9800998ecf8427e" -int pbhttp_digest_prep_header_to_send(struct pbhttp_digest_context *ctx, char const* username, char const* password, char const* uri, pubnub_chamebl_t *buf) +int pbhttp_digest_prep_header_to_send(struct pbhttp_digest_context* ctx, + char const* username, + char const* password, + char const* uri, + char const* realm, + pubnub_chamebl_t* buf) { - char ha1[33]; - char ha2[33]; - char response[33]; + char ha1[33]; + char ha2[33]; + char response[33]; PBMD5_CTX md5; PUBNUB_ASSERT_OPT(ctx != NULL); PUBNUB_ASSERT_OPT(username != NULL); PUBNUB_ASSERT_OPT(password != NULL); PUBNUB_ASSERT_OPT(uri != NULL); + PUBNUB_ASSERT_OPT(realm != NULL); if ((ctx->qop != pbhtdigqopNone) && ('\0' == ctx->nonce[0])) { - PUBNUB_LOG_ERROR("HTTP digest `qop` defined, but haven't received `nonce`\n"); + PUBNUB_LOG_ERROR( + "HTTP digest `qop` defined, but haven't received `nonce`\n"); return -1; } @@ -237,7 +233,7 @@ int pbhttp_digest_prep_header_to_send(struct pbhttp_digest_context *ctx, char co pbmd5_init(&md5); pbmd5_update(&md5, username, strlen(username)); pbmd5_update(&md5, ":", 1); - pbmd5_update(&md5, ctx->realm, strlen(ctx->realm)); + pbmd5_update(&md5, realm, strlen(realm)); pbmd5_update(&md5, ":", 1); pbmd5_update(&md5, password, strlen(password)); md5_final_to_str(&md5, ha1); @@ -267,7 +263,7 @@ int pbhttp_digest_prep_header_to_send(struct pbhttp_digest_context *ctx, char co pbmd5_update(&md5, ctx->nonce, strlen(ctx->nonce)); if (pbhtdigqopNone != ctx->qop) { char const* qop_str = pbhttp_digest_qop2str(ctx->qop); - char nonce_count_str[9]; + char nonce_count_str[9]; snprintf(nonce_count_str, sizeof nonce_count_str, "%08x", ctx->nc); pbmd5_update(&md5, ":", 1); pbmd5_update(&md5, nonce_count_str, sizeof nonce_count_str - 1); @@ -281,30 +277,43 @@ int pbhttp_digest_prep_header_to_send(struct pbhttp_digest_context *ctx, char co md5_final_to_str(&md5, response); if (pbhtdigqopNone == ctx->qop) { - buf->size = snprintf( - buf->ptr, buf->size, - "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"" - "%s%s" - "%s%s", - username, ctx->realm, ctx->nonce, uri, response, - ctx->opaque[0] == '\0' ? "" : ", opaque=", ctx->opaque, - (pbhtdigalUnknown == ctx->algorithm) ? "" : ", algorithm=", - pbhttp_digest_algorithm2str(ctx->algorithm) - ); + buf->size = + snprintf(buf->ptr, + buf->size, + "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", " + "response=\"%s\"" + "%s%s" + "%s%s", + username, + realm, + ctx->nonce, + uri, + response, + ctx->opaque[0] == '\0' ? "" : ", opaque=", + ctx->opaque, + (pbhtdigalUnknown == ctx->algorithm) ? "" : ", algorithm=", + pbhttp_digest_algorithm2str(ctx->algorithm)); } else { - buf->size = snprintf( - buf->ptr, buf->size, - "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", " - "cnonce=\"%s\", nc=\"%08x\", qop=\"%s\", response=\"%s\"" - "%s%s" - "%s%s", - username, ctx->realm, ctx->nonce, uri, - ctx->client_nonce, ctx->nc, pbhttp_digest_qop2str(ctx->qop), response, - (ctx->opaque[0] == '\0' ? "" : ", opaque="), ctx->opaque, - (pbhtdigalUnknown == ctx->algorithm) ? "" : ", algorithm=", - pbhttp_digest_algorithm2str(ctx->algorithm) - ); + buf->size = + snprintf(buf->ptr, + buf->size, + "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", " + "cnonce=\"%s\", nc=\"%08x\", qop=\"%s\", response=\"%s\"" + "%s%s" + "%s%s", + username, + realm, + ctx->nonce, + uri, + ctx->client_nonce, + ctx->nc, + pbhttp_digest_qop2str(ctx->qop), + response, + (ctx->opaque[0] == '\0' ? "" : ", opaque="), + ctx->opaque, + (pbhtdigalUnknown == ctx->algorithm) ? "" : ", algorithm=", + pbhttp_digest_algorithm2str(ctx->algorithm)); ++ctx->nc; } diff --git a/core/pbhttp_digest.h b/core/pbhttp_digest.h index 9071c76f..6de5219d 100644 --- a/core/pbhttp_digest.h +++ b/core/pbhttp_digest.h @@ -5,11 +5,6 @@ #include "pubnub_memory_block.h" -/** Maximum length of the "realm" field used in HTTP - authentication headers. Server sets this. -*/ -#define PUBNUB_MAX_HTTP_AUTH_REALM 31 - /** Maximum length of the "nonce" field used in HTTP authentication headers. Server sets this. */ @@ -60,12 +55,26 @@ enum pbhttp_digest_qop { pbgtdigqop_auth_int }; +/** HTTP Digest authentication header parsing result */ +enum pbhttp_digest_parse_header_rslt { + /** Authentication parameter(one, or more) is invalid */ + pbhtdig_ParameterError, + /** Realm in new 'authentication required' message is different from + realm previously used + */ + pbhtdig_DifferentConsecutiveRealms, + /** Realm in new 'authentication required' message is the same as + realm currently in use + */ + pbhtdig_EqualConsecutiveRealms, + /** attribute 'realm' is not found yet in 'authentication required' message header + */ + pbhtdig_RealmNotFound +}; + /** */ struct pbhttp_digest_context { - /** Authentication realm - received from the server */ - char realm[PUBNUB_MAX_HTTP_AUTH_REALM + 1]; - /** The auth challenge nonce - received from the server */ char nonce[PUBNUB_MAX_HTTP_NONCE + 1]; @@ -101,8 +110,17 @@ void pbhttp_digest_init(struct pbhttp_digest_context *ctx); @param ctx The HTTP digest context @param header The string of the header (key-value pairs) + @param realm pointer to the corresponding pubnub context field to be filled in + @retvel pbhtdig_ParameterError invalid parameter found while parsing + @retval pbhtdig_EqualConsecutiveRealms realm parsed from the header is equal as + one already in use + @retval pbhtdig_DifferentConsecutiveRealms new realm is different from the one previously + used, + @retval pbhtdig_RealmNotFound realm is not discovered(yet) in digest 'auth-info' header line */ -void pbhttp_digest_parse_header(struct pbhttp_digest_context *ctx, char const* header); +enum pbhttp_digest_parse_header_rslt pbhttp_digest_parse_header(struct pbhttp_digest_context *ctx, + char const* header, + char* realm); /** Sets the contents of the string buffer to send as the header during HTTP Digest authentication. @@ -111,10 +129,16 @@ void pbhttp_digest_parse_header(struct pbhttp_digest_context *ctx, char const* h @param username The username to use @param password The password to use @param uri The URI to use + @param realm The URI realm to use @param buf The buffer which contents to set @param 0: OK, -1: error */ -int pbhttp_digest_prep_header_to_send(struct pbhttp_digest_context *ctx, char const* username, char const* password, char const* uri, pubnub_chamebl_t *buf); +int pbhttp_digest_prep_header_to_send(struct pbhttp_digest_context *ctx, + char const* username, + char const* password, + char const* uri, + char const* realm, + pubnub_chamebl_t *buf); /** Returns a read-only string representation of the HTTP Digest Quality of Protection value. diff --git a/core/pbpal.h b/core/pbpal.h index 9c36f182..4648a4b2 100644 --- a/core/pbpal.h +++ b/core/pbpal.h @@ -110,7 +110,7 @@ int pbpal_send(pubnub_t *pb, void const *data, size_t n); literal string, so, handle with care. */ #define pbpal_send_literal_str(pb, litstr) \ - pbpal_send((pb), litstr, sizeof litstr - 1) + pbpal_send((pb), litstr, sizeof litstr - 1) /** The effect of this is the same as: @@ -226,5 +226,7 @@ int pbpal_set_blocking_io(pubnub_t *pb); */ void pbpal_free(pubnub_t *pb); - +#if PUBNUB_USE_MULTIPLE_ADDRESSES +void pbpal_multiple_addresses_reset_counters(struct pubnub_multi_addresses* spare_addresses); +#endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ #endif /* !defined INC_PBPAL */ diff --git a/core/pubnub_api_types.h b/core/pubnub_api_types.h index de93188a..08a7b97c 100644 --- a/core/pubnub_api_types.h +++ b/core/pubnub_api_types.h @@ -95,7 +95,9 @@ enum pubnub_res { /** Invalid input parameters passed to a given function */ PNR_INVALID_PARAMETERS, /** Server reports an error in the response */ - PNR_ERROR_ON_SERVER + PNR_ERROR_ON_SERVER, + /** Proxy authentication failed */ + PNR_AUTHENTICATION_FAILED }; /** 'pubnub_cancel()' return value */ diff --git a/core/pubnub_ccore_pubsub.h b/core/pubnub_ccore_pubsub.h index a1f7dd1d..4c80c453 100644 --- a/core/pubnub_ccore_pubsub.h +++ b/core/pubnub_ccore_pubsub.h @@ -51,7 +51,7 @@ struct pbcc_context { /** The length of the data currently in the HTTP buffer ("scratch" or reply, depending on the state). */ - unsigned http_buf_len; + size_t http_buf_len; #if PUBNUB_CRYPTO_API /** Holds encrypted message */ @@ -63,14 +63,14 @@ struct pbcc_context { char gzip_msg_buf[PUBNUB_COMPRESSED_MAXLEN]; /** The length of compressed data in 'comp_http_buf' ready to be sent */ - unsigned gzip_msg_len; + size_t gzip_msg_len; #endif #if PUBNUB_RECEIVE_GZIP_RESPONSE /** The length of the decompressed data currently in the decompressing * buffer ("scratch"). */ - unsigned decomp_buf_size; + size_t decomp_buf_size; #endif /** The total length of data to be received in a HTTP reply or chunk of it. diff --git a/core/pubnub_core_unit_test.c b/core/pubnub_core_unit_test.c index 155b81cf..68bda462 100644 --- a/core/pubnub_core_unit_test.c +++ b/core/pubnub_core_unit_test.c @@ -77,7 +77,7 @@ static void wait_time_in_seconds(time_t time_in_seconds) static void buf_setup(pubnub_t* pb) { pb->ptr = (uint8_t*)pb->core.http_buf; - pb->left = sizeof pb->core.http_buf; + pb->left = sizeof pb->core.http_buf / sizeof pb->core.http_buf[0]; } void pbpal_init(pubnub_t* pb) @@ -445,6 +445,11 @@ char const* pubnub_uname(void) return "unit-test-0.1"; } +char const* pubnub_uagent(void) +{ + return "POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION; +} + /* The Pubnub NTF mocks and stubs */ void pbntf_trans_outcome(pubnub_t* pb, enum pubnub_state state) @@ -797,9 +802,9 @@ static inline void expect_outgoing_with_url(char const* url) expect(pbpal_send_status, returns(0)); expect(pbpal_send_str, when(s, streqs(PUBNUB_ORIGIN)), returns(0)); expect(pbpal_send_status, returns(0)); - expect(pbpal_send, - when(data, - streqs("\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION + expect(pbpal_send_str, + when(s, + streqs("\r\nUser-Agent: POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" ACCEPT_ENCODING "\r\n")), returns(0)); expect(pbpal_send_status, returns(0)); @@ -1187,9 +1192,9 @@ Ensure(single_context_pubnub, publish_change_origin) expect(pbpal_send_status, returns(0)); expect(pbpal_send_str, when(s, streqs("new_origin_server")), returns(0)); expect(pbpal_send_status, returns(0)); - expect(pbpal_send, - when(data, - streqs("\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION + expect(pbpal_send_str, + when(s, + streqs("\r\nUser-Agent: POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" ACCEPT_ENCODING "\r\n")), returns(0)); expect(pbpal_send_status, returns(0)); diff --git a/core/pubnub_helper.c b/core/pubnub_helper.c index 7d4afd93..d334b366 100644 --- a/core/pubnub_helper.c +++ b/core/pubnub_helper.c @@ -64,6 +64,7 @@ char const* pubnub_res_2_string(enum pubnub_res e) case PNR_BAD_COMPRESSION_FORMAT: return "Bad data compression format"; case PNR_INVALID_PARAMETERS: return "Invalid function parameters"; case PNR_ERROR_ON_SERVER: return "Server reported an error"; + case PNR_AUTHENTICATION_FAILED: return "Proxy authentication failed"; } return "!?!?!"; } @@ -95,6 +96,7 @@ enum pubnub_tribool pubnub_should_retry(enum pubnub_res e) case PNR_BAD_COMPRESSION_FORMAT: return pbccNotSet; /* If bad compressing was transient, a retry might help */ case PNR_INVALID_PARAMETERS: return pbccFalse; /* Check and fix invalid parameters */ case PNR_ERROR_ON_SERVER: return pbccFalse; /* Fix the error reported */ + case PNR_AUTHENTICATION_FAILED: return pbccFalse; /* Check and fix the error reported */ } return pbccFalse; } diff --git a/core/pubnub_internal_common.h b/core/pubnub_internal_common.h index 2ceda231..3eab778c 100644 --- a/core/pubnub_internal_common.h +++ b/core/pubnub_internal_common.h @@ -47,6 +47,7 @@ #define PUBNUB_PROXY_API 0 #elif PUBNUB_PROXY_API #include "core/pubnub_proxy.h" +#include "core/pubnub_proxy_core.h" #include "core/pbhttp_digest.h" #endif @@ -224,19 +225,24 @@ struct pbdns_servers_check { #if PUBNUB_USE_MULTIPLE_ADDRESSES struct pubnub_multi_addresses { + time_t time_of_the_last_dns_query; /* Number of spare ipv4 addresses */ int n_ipv4; - /* Spare ipv4 address index(from the array) currently used */ + /* ipv4 address index(from the array) currently used */ int ipv4_index; - /* Spare ipv4 address array */ + /* ipv4 address array */ struct pubnub_ipv4_address ipv4_addresses[PUBNUB_MAX_IPV4_ADDRESSES]; + /* Time to live for each saved ipv4 address */ + uint16_t ttl_ipv4[PUBNUB_MAX_IPV4_ADDRESSES]; #if PUBNUB_USE_IPV6 /* Number of spare ipv6 addresses */ int n_ipv6; - /* Spare ipv6 address index(from the array) currently used */ + /* ipv6 address index(from the array) currently used */ int ipv6_index; - /* Spare ipv6 address array */ + /* ipv6 address array */ struct pubnub_ipv6_address ipv6_addresses[PUBNUB_MAX_IPV6_ADDRESSES]; + /* Time to live for each saved ipv6 address */ + uint16_t ttl_ipv6[PUBNUB_MAX_IPV6_ADDRESSES]; #endif }; #endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ @@ -414,6 +420,23 @@ struct pubnub_ { */ int proxy_authorization_sent; + /** Authentication realm - received from the server */ + char realm[PUBNUB_MAX_HTTP_AUTH_REALM + 1]; + + /** Proxy 'authentication required' response message counter for repeating realm + within a single transaction. + At this point this field is of importance for Digest proxy authentication sheme. + See RFC 7616 - 5.4. Limited-Use Nonce Values : + ...For example, a server MAY choose to allow each nonce value to be used only once by + maintaining a record of whether, or not each recently issued nonce has been returned + and sending a next-nonce parameter in the Authentication-Info header field of every + response... + + Doing it (within the same transaction)repeatedly, without restrictions, would be a sign + of irregular behaviour. + */ + uint8_t auth_msg_count; + /** Data about NTLM authentication */ struct pbntlm_context ntlm_context; diff --git a/core/pubnub_netcore.c b/core/pubnub_netcore.c index 870aaca4..5b27eb7f 100644 --- a/core/pubnub_netcore.c +++ b/core/pubnub_netcore.c @@ -6,6 +6,7 @@ #include "core/pubnub_ccore.h" #include "core/pubnub_ccore_pubsub.h" #include "core/pbpal.h" +#include "core/pubnub_version.h" #include "core/pubnub_version_internal.h" #include "core/pubnub_helper.h" #if PUBNUB_USE_ADVANCED_HISTORY @@ -42,14 +43,23 @@ #endif /* PUBNUB_RECEIVE_GZIP_RESPONSE */ +static int send_fin_head(struct pubnub_* pb) +{ + char s[200]; + snprintf(s, + sizeof s, + "\r\nUser-Agent: %s%s", + pubnub_uagent(), + "\r\n" ACCEPT_ENCODING "\r\n"); + return pbpal_send_str(pb, s); +} + + #define SEND_FIN_HEAD(pb) \ - if (0 > pbpal_send_literal_str( \ - pb, \ - "\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION \ - "\r\n" ACCEPT_ENCODING "\r\n")) { \ - outcome_detected(pb, PNR_IO_ERROR); \ - break; \ - } + if (0 > send_fin_head(pb)) { \ + outcome_detected(pb, PNR_IO_ERROR); \ + break; \ + } static bool should_keep_alive(struct pubnub_* pb, enum pubnub_res rslt) @@ -71,6 +81,7 @@ static bool should_keep_alive(struct pubnub_* pb, enum pubnub_res rslt) case PNR_CANCELLED: case PNR_STARTED: case PNR_INTERNAL_ERROR: + case PNR_AUTHENTICATION_FAILED: return false; default: return true; @@ -344,17 +355,26 @@ static char const* pbnc_state2str(enum pubnub_state e) } } -#if PUBNUB_USE_MULTIPLE_ADDRESSES -static void multiple_addresses_reset_counters(struct pubnub_multi_addresses* spare_addresses) +static void initialize_fields_in_state_IDLE(struct pubnub_* pb) { - spare_addresses->n_ipv4 = 0; - spare_addresses->ipv4_index = 0; -#if PUBNUB_USE_IPV6 - spare_addresses->n_ipv6 = 0; - spare_addresses->ipv6_index = 0; +#if PUBNUB_CHANGE_DNS_SERVERS + pb->dns_check.dns_server_check = 0; +#endif +#if PUBNUB_NEED_RETRY_AFTER_CLOSE + pb->flags.retry_after_close = false; +#else + PUBNUB_UNUSED(pb); +#endif +#if PUBNUB_PROXY_API + pb->proxy_tunnel_established = false; + pb->proxy_saved_path_len = 0; + pb->proxy_authorization_sent = false; + pb->auth_msg_count = 0; +#endif +#if PUBNUB_USE_SSL + pb->flags.trySSL = pb->options.useSSL; #endif } -#endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ int pbnc_fsm(struct pubnub_* pb) { @@ -369,19 +389,7 @@ int pbnc_fsm(struct pubnub_* pb) case PBS_NULL: break; case PBS_IDLE: -#if PUBNUB_CHANGE_DNS_SERVERS - pb->dns_check.dns_server_check = 0; -#endif -#if PUBNUB_USE_MULTIPLE_ADDRESSES - multiple_addresses_reset_counters(&pb->spare_addresses); -#endif -#if PUBNUB_NEED_RETRY_AFTER_CLOSE - pb->flags.retry_after_close = false; -#endif -#if PUBNUB_PROXY_API - pb->proxy_tunnel_established = false; - pb->proxy_saved_path_len = 0; -#endif + initialize_fields_in_state_IDLE(pb); pb->state = PBS_READY; switch (pbntf_enqueue_for_processing(pb)) { case -1: @@ -565,6 +573,17 @@ int pbnc_fsm(struct pubnub_* pb) pb->flags.trySSL = false; pb->flags.retry_after_close = true; } +#if PUBNUB_USE_MULTIPLE_ADDRESSES + else { + pb->flags.retry_after_close = + (++pb->spare_addresses.ipv4_index < pb->spare_addresses.n_ipv4) +#if PUBNUB_USE_IPV6 + || (++pb->spare_addresses.ipv6_index + < pb->spare_addresses.n_ipv6) +#endif + ; + } +#endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ outcome_detected(pb, PNR_CONNECT_FAILED); return 0; default: @@ -573,7 +592,7 @@ int pbnc_fsm(struct pubnub_* pb) return 0; } } -#endif +#endif /* PUBNUB_USE_SSL */ i = pbpal_send_str(pb, pb->flags.is_publish_via_post ? "POST " : "GET "); if (i < 0) { outcome_detected(pb, PNR_IO_ERROR); @@ -600,6 +619,16 @@ int pbnc_fsm(struct pubnub_* pb) pb->flags.trySSL = false; pb->flags.retry_after_close = true; } +#if PUBNUB_USE_MULTIPLE_ADDRESSES + else { + pb->flags.retry_after_close = + (++pb->spare_addresses.ipv4_index < pb->spare_addresses.n_ipv4) +#if PUBNUB_USE_IPV6 + || (++pb->spare_addresses.ipv6_index < pb->spare_addresses.n_ipv6) +#endif + ; + } +#endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ outcome_detected(pb, PNR_CONNECT_FAILED); break; default: @@ -611,12 +640,6 @@ int pbnc_fsm(struct pubnub_* pb) } #endif /* PUBNUB_USE_SSL */ case PBS_TX_GET: -#if PUBNUB_CHANGE_DNS_SERVERS - pb->dns_check.dns_server_check = 0; -#endif -#if PUBNUB_USE_MULTIPLE_ADDRESSES - multiple_addresses_reset_counters(&pb->spare_addresses); -#endif i = pbpal_send_status(pb); if (i <= 0) { #if PUBNUB_PROXY_API @@ -799,10 +822,12 @@ int pbnc_fsm(struct pubnub_* pb) #if PUBNUB_PROXY_API && (pb->proxy_tunnel_established || (pbproxyNONE == pb->proxy_type)) #endif - ) { + ) { char hedr[128] = "\r\n"; - pbcc_headers_for_publish_via_post(&(pb->core), hedr + 2, sizeof hedr - 2); - PUBNUB_LOG_TRACE("Sending HTTP 'publish via POST' headers: '%s'\n", hedr); + pbcc_headers_for_publish_via_post( + &(pb->core), hedr + 2, sizeof hedr - 2); + PUBNUB_LOG_TRACE( + "Sending HTTP 'publish via POST' headers: '%s'\n", hedr); pb->state = PBS_TX_EXTRA_HEADERS; if (-1 == pbpal_send_str(pb, hedr)) { outcome_detected(pb, PNR_IO_ERROR); @@ -836,10 +861,11 @@ int pbnc_fsm(struct pubnub_* pb) #if PUBNUB_PROXY_API && (pb->proxy_tunnel_established || (pbproxyNONE == pb->proxy_type)) #endif - ) { + ) { const char* message = pb->core.message_to_publish; #if PUBNUB_USE_GZIP_COMPRESSION - size_t len = (pb->core.gzip_msg_len != 0) ? pb->core.gzip_msg_len : strlen(message); + size_t len = (pb->core.gzip_msg_len != 0) ? pb->core.gzip_msg_len + : strlen(message); #else size_t len = strlen(message); #endif @@ -979,8 +1005,9 @@ int pbnc_fsm(struct pubnub_* pb) pb->data_compressed = compressionGZIP; } #endif - else { - pbproxy_handle_http_header(pb, pb->core.http_buf); + else if (pbproxy_handle_http_header(pb, pb->core.http_buf) != 0) { + outcome_detected(pb, PNR_AUTHENTICATION_FAILED); + return 0; } pb->state = PBS_RX_HEADERS; goto next_state; @@ -1023,7 +1050,7 @@ int pbnc_fsm(struct pubnub_* pb) case PNR_OK: { unsigned len = pbpal_read_len(pb); WATCH_UINT(len); - WATCH_UINT(pb->core.http_buf_len); + WATCH_SIZE_T(pb->core.http_buf_len); PUBNUB_ASSERT_OPT(pb->core.http_buf_len + len <= pb->core.http_content_len); memcpy(pb->core.http_reply + pb->core.http_buf_len, pb->core.http_buf, len); @@ -1148,7 +1175,9 @@ int pbnc_fsm(struct pubnub_* pb) break; case PBS_KEEP_ALIVE_IDLE: #if PUBNUB_PROXY_API - pb->proxy_saved_path_len = 0; + pb->proxy_saved_path_len = 0; + pb->proxy_authorization_sent = false; + pb->auth_msg_count = 0; #endif pb->state = PBS_KEEP_ALIVE_READY; pb->flags.started_while_kept_alive = true; @@ -1171,7 +1200,7 @@ int pbnc_fsm(struct pubnub_* pb) break; } pb->state = PBS_TX_GET; - i = pbpal_send_str(pb, pb->flags.is_publish_via_post ? "POST " : "GET "); + i = pbpal_send_str(pb, pb->flags.is_publish_via_post ? "POST " : "GET "); if (i < 0) { pb->state = close_kept_alive_connection(pb); } diff --git a/core/pubnub_proxy.h b/core/pubnub_proxy.h index f3ea157a..4353b378 100644 --- a/core/pubnub_proxy.h +++ b/core/pubnub_proxy.h @@ -84,6 +84,8 @@ enum pubnub_proxy_type { /** Known HTTP authentication schemes to be used with the HTTP proxy. */ enum pubnub_http_authentication_scheme { + /** No authentication scheme. This is the default */ + pbhtauNone, /** The basic authentication scheme. It is not secure and thus should only be used w/HTTPS or private networks. */ @@ -97,9 +99,7 @@ enum pubnub_http_authentication_scheme { even more complex than DIGEST. Support for it may be not as advanced (full-featured) on non-Windows platforms. */ - pbhtauNTLM, - /** No authentication scheme. This is the default */ - pbhtauNone + pbhtauNTLM }; diff --git a/core/pubnub_proxy_NTLM_test.c b/core/pubnub_proxy_NTLM_test.c index e7859b13..5541fd94 100644 --- a/core/pubnub_proxy_NTLM_test.c +++ b/core/pubnub_proxy_NTLM_test.c @@ -455,6 +455,11 @@ char const* pubnub_uname(void) return "unit-test-0.1"; } +char const* pubnub_uagent(void) +{ + return "Windows-PubNub-C-core/" PUBNUB_SDK_VERSION; +} + /* The Pubnub NTF mocks and stubs */ @@ -568,9 +573,9 @@ static void expect_first_outgoing_GET(const char* url) expect("pbpal_send_status", pbp, "", 0); expect("pbpal_send_str", pbp, PUBNUB_ORIGIN, 0); expect("pbpal_send_status", pbp, "", 0); - expect("pbpal_send", + expect("pbpal_send_str", pbp, - "\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION + "\r\nUser-Agent: Windows-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" ACCEPT_ENCODING "\r\n", 0); expect("pbpal_send_status", pbp, "", 0); @@ -590,9 +595,9 @@ static void expect_first_outgoing_CONNECT(void) expect("pbpal_send_status", pbp, "", 0); expect("pbpal_send_str", pbp, PUBNUB_ORIGIN, 0); expect("pbpal_send_status", pbp, "", 0); - expect("pbpal_send", + expect("pbpal_send_str", pbp, - "\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION + "\r\nUser-Agent: Windows-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" ACCEPT_ENCODING "\r\n", 0); expect("pbpal_send_status", pbp, "", 0); @@ -617,9 +622,9 @@ static void expect_outgoing_with_encoded_credentials_GET(char const* url, expect("pbpal_send_status", pbp, "", 0); expect("pbpal_send_str", pbp, HTTP_proxy_header, 0); expect("pbpal_send_status", pbp, "", 0); - expect("pbpal_send", + expect("pbpal_send_str", pbp, - "\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION + "\r\nUser-Agent: Windows-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" ACCEPT_ENCODING "\r\n", 0); expect("pbpal_send_status", pbp, "", 0); @@ -642,9 +647,9 @@ static void expect_outgoing_with_encoded_credentials_CONNECT(char const* url, expect("pbpal_send_status", pbp, "", 0); expect("pbpal_send_str", pbp, HTTP_proxy_header, 0); expect("pbpal_send_status", pbp, "", 0); - expect("pbpal_send", + expect("pbpal_send_str", pbp, - "\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION + "\r\nUser-Agent: Windows-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" ACCEPT_ENCODING "\r\n", 0); expect("pbpal_send_status", pbp, "", 0); @@ -664,9 +669,9 @@ static void expect_outgoing_with_url(char const* url) expect("pbpal_send_status", pbp, "", 0); expect("pbpal_send_str", pbp, PUBNUB_ORIGIN, 0); expect("pbpal_send_status", pbp, "", 0); - expect("pbpal_send", + expect("pbpal_send_str", pbp, - "\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION + "\r\nUser-Agent: Windows-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" ACCEPT_ENCODING "\r\n", 0); expect("pbpal_send_status", pbp, "", 0); diff --git a/core/pubnub_proxy_core.c b/core/pubnub_proxy_core.c index 63101463..4964a083 100644 --- a/core/pubnub_proxy_core.c +++ b/core/pubnub_proxy_core.c @@ -20,8 +20,109 @@ header field */ #define HTTP_CODE_PROXY_AUTH_REQ 407 +/* Maximum number of expected 'proxy auth required' mesages with valid credentials + for single realm in Digest sheme proxy protocol within a single transaction + It may be set to a higher value depending on chosen proxy behavior. + Set to one as default value. + (RFC 7616: See 5.4. Limited-Use Nonce Values) + */ +#define NUM_EXPECTED_DIGEST_AUTH_MESSAGES 1 + +char const* pbproxy_get_next_key_value(char const* s, pubnub_chamebl_t *key, pubnub_chamebl_t *val) +{ + s += strspn(s, " \t"); + key->ptr = (char*)s; + key->size = strcspn(s, "= \t"); + s += key->size; + s += strspn(s, " \t"); + if (*s != '=') { + return NULL; + } + s += 1 + strspn(s + 1, " \t"); + val->ptr = (char*)s; + if ('"' == *s) { + char const* esc; + char const* end = s + 1; + for (esc = strstr(end, "\\\""); esc != NULL; esc = strstr(end, "\\\"")) { + end = esc + 2; + } + val->size = end - s + strcspn(end, "\"") + 1; + s += val->size; + if (*(s - 1) != '"') { + return NULL; + } + } + else { + val->size = strcspn(s, " \t"); + s += val->size; + } + s += strspn(s, " \t"); + if (*s == ',') { + ++s; + } + return ('\0' == *s) ? NULL : s; +} + + +int pbproxy_check_realm(pubnub_chamebl_t const* value) +{ + if (value->size > PUBNUB_MAX_HTTP_AUTH_REALM + 1) { + PUBNUB_LOG_ERROR("Received `realm` too long: %zu, maximum possible %d\n", + value->size, PUBNUB_MAX_HTTP_AUTH_REALM + 1); + return -1; + } + if ('"' != *(value->ptr)) { + PUBNUB_LOG_ERROR("Received 'realm' is not quoted\n"); + return -1; + } + if (value->size <= 2) { + PUBNUB_LOG_ERROR("Received 'realm' is too short (length = %zu)\n", value->size); + return -1; + } + return 0; +} + -void pbproxy_handle_http_header(pubnub_t* p, char const* header) +static int auth_sheme_priority(enum pubnub_http_authentication_scheme sheme) +{ + switch (sheme) { + case pbhtauNone: + return 0; + case pbhtauBasic: + return 1; + case pbhtauDigest: + return 2; + case pbhtauNTLM: + return 3; + default: + break; + } + return -1; +} + + +static int process_digest_header_line(pubnub_t* p, char const* header) +{ + enum pbhttp_digest_parse_header_rslt rslt; + + rslt = pbhttp_digest_parse_header(&p->digest_context, header, p->realm); + if (pbhtdig_EqualConsecutiveRealms == rslt) { + ++p->auth_msg_count; + } + else if (pbhtdig_DifferentConsecutiveRealms == rslt) { + p->auth_msg_count = 1; + } + if ((pbhtdig_ParameterError == rslt) || + ((pbhtdig_EqualConsecutiveRealms == rslt) && + (p->auth_msg_count > NUM_EXPECTED_DIGEST_AUTH_MESSAGES)) + ) { + return -1; + } + return 0; +} + + +int pbproxy_handle_http_header(pubnub_t* p, char const* header) { char scheme_basic[] = "Basic"; char scheme_digest[] = "Digest"; @@ -40,13 +141,15 @@ void pbproxy_handle_http_header(pubnub_t* p, char const* header) use multi-line headers. */ if (p->proxy_auth_scheme != pbhtauDigest) { - return; + return 0; + } + if (process_digest_header_line(p, header + 1) != 0) { + return -1; } - pbhttp_digest_parse_header(&p->digest_context, header + 1); - return; + return 0; default: if (strncmp(header, proxy_auth, sizeof proxy_auth - 1) != 0) { - return; + return 0; } break; } @@ -56,23 +159,57 @@ void pbproxy_handle_http_header(pubnub_t* p, char const* header) header, contents); - if (0 == strncmp(contents, scheme_basic, sizeof scheme_basic - 1)) { - /* We ignore the "realm" for now */ + if ((0 == strncmp(contents, scheme_basic, sizeof scheme_basic - 1)) && + (auth_sheme_priority(p->proxy_auth_scheme) <= auth_sheme_priority(pbhtauBasic))) { + char empty_str[] = { '\0' }; + pubnub_chamebl_t key = { empty_str, 0 }; + pubnub_chamebl_t value = { empty_str, 0 }; + char const *s = contents + sizeof scheme_basic; + PUBNUB_LOG_TRACE("pbproxy_handle_http_header() Basic authentication\n"); + do { + if (NULL == s) { + PUBNUB_LOG_WARNING("Warning: haven't got realm for basic authentication\n"); + if (p->proxy_authorization_sent && ('\0' == p->realm[0])) { + return -1; + } + p->realm[0] = '\0'; + break; + } + s = pbproxy_get_next_key_value(s, &key, &value); + if (LIT_STR_EQ("realm", key.ptr)) { + if (pbproxy_check_realm(&value) != 0) { + return -1; + } + if (p->proxy_authorization_sent && + (strncmp(p->realm, value.ptr + 1, value.size - 2) == 0) && + (strlen(p->realm) == (value.size - 2))) { + /* For same realm another authentication header is received + even though credentials had been sent + */ + return -1; + } + memcpy(p->realm, value.ptr + 1, value.size - 2); + p->realm[value.size - 2] = '\0'; + break; + } + } while (1); + p->proxy_auth_scheme = pbhtauBasic; - p->proxy_authorization_sent = false; + p->proxy_authorization_sent = false; } - else if (0 == strncmp(contents, scheme_digest, sizeof scheme_digest - 1)) { - /* We ignore the "realm" for now */ - PUBNUB_LOG_TRACE( - "pbproxy_handle_http_header() Digest authentication\n"); + else if ((0 == strncmp(contents, scheme_digest, sizeof scheme_digest - 1)) && + (auth_sheme_priority(p->proxy_auth_scheme) <= auth_sheme_priority(pbhtauDigest))) { + PUBNUB_LOG_TRACE("pbproxy_handle_http_header() Digest authentication\n"); p->proxy_auth_scheme = pbhtauDigest; pbhttp_digest_init(&p->digest_context); - pbhttp_digest_parse_header(&p->digest_context, - contents + sizeof scheme_digest); + if (process_digest_header_line(p, contents + sizeof scheme_digest) != 0) { + return -1; + } p->proxy_authorization_sent = false; } - else if (0 == strncmp(contents, scheme_NTLM, sizeof scheme_NTLM - 1)) { + else if ((0 == strncmp(contents, scheme_NTLM, sizeof scheme_NTLM - 1)) && + (auth_sheme_priority(p->proxy_auth_scheme) <= auth_sheme_priority(pbhtauNTLM))) { if (pbhtauNTLM != p->proxy_auth_scheme) { pbntlm_core_init(p); p->proxy_auth_scheme = pbhtauNTLM; @@ -84,9 +221,12 @@ void pbproxy_handle_http_header(pubnub_t* p, char const* header) } } else { - PUBNUB_LOG_ERROR("Proxy Authentication '%s' not supported\n", contents); - p->proxy_auth_scheme = pbhtauNone; + PUBNUB_LOG_WARNING("Warning: Proxy Authentication '%.*s' not supported\n", + (int)strcspn(contents, " \t\r\n"), + contents); } + + return 0; } @@ -160,14 +300,15 @@ int pbproxy_http_header_to_send(pubnub_t* p, char* header, size_t n) memcpy(header, prefix, sizeof prefix); - if (0 - == pbhttp_digest_prep_header_to_send(&p->digest_context, - figure_out_username(p), - figure_out_password(p), - p->proxy_saved_path, - &data)) { + if (0 == pbhttp_digest_prep_header_to_send(&p->digest_context, + figure_out_username(p), + figure_out_password(p), + p->proxy_saved_path, + p->realm, + &data)) { PUBNUB_LOG_TRACE( "pbproxy_http_header_to_send(): Digest header: '%s'\n", header); + p->proxy_authorization_sent = true; } else { PUBNUB_LOG_ERROR("Failed to prepare HTTP digest auth header\n"); diff --git a/core/pubnub_proxy_core.h b/core/pubnub_proxy_core.h index a879613b..508ff9d9 100644 --- a/core/pubnub_proxy_core.h +++ b/core/pubnub_proxy_core.h @@ -4,6 +4,7 @@ #include "pubnub_config.h" #include "pubnub_api_types.h" +#include "pubnub_memory_block.h" #include @@ -19,13 +20,35 @@ #if PUBNUB_PROXY_API /** Processes a proxy related HTTP @p header on the Pubnub context @p p. + @return 0 expected, -1 unexpected proxy authentication header */ -void pbproxy_handle_http_header(pubnub_t *p, char const* header); +int pbproxy_handle_http_header(pubnub_t *p, char const* header); #else -#define pbproxy_handle_http_header(p, header) +#define pbproxy_handle_http_header(p, header) 0 #endif +/** Maximum length of the "realm" field used in HTTP + authentication headers. Server sets this. +*/ +#define PUBNUB_MAX_HTTP_AUTH_REALM 31 + +#define LIT_STR_EQ(lit, str) (0 == memcmp(lit, str, sizeof lit - 1)) + +/** Will get new @p key : @p val(ue) pair from the authentication header string @p s + + @return pointer within @p s behind the element found, + NULL if there isn't 'key=value' pair left in @p s + */ +char const* pbproxy_get_next_key_value(char const* s, pubnub_chamebl_t *key, pubnub_chamebl_t *val); + + +/** Checks the validity of received realm @p value + @return 0 realm valid, -1 invalid + */ +int pbproxy_check_realm(pubnub_chamebl_t const* value); + + /** Will put string to send as HTTP header in @p header, which is caller-allocated buffer of size @p n, on Pubnub context @p p, if there is a need to send some proxy-related HTTP header. diff --git a/core/pubnub_proxy_unit_test.c b/core/pubnub_proxy_unit_test.c index 04f350b2..4ce43c65 100644 --- a/core/pubnub_proxy_unit_test.c +++ b/core/pubnub_proxy_unit_test.c @@ -56,7 +56,7 @@ static void wait4it(time_t time_in_seconds) { static void buf_setup(pubnub_t *pb) { pb->ptr = (uint8_t*)pb->core.http_buf; - pb->left = sizeof pb->core.http_buf; + pb->left = sizeof pb->core.http_buf / sizeof pb->core.http_buf[0]; } void pbpal_init(pubnub_t *pb) @@ -334,6 +334,13 @@ int pbpal_close(pubnub_t *pb) return mock(pb); } +#if PUBNUB_USE_MULTIPLE_ADDRESSES +void pbpal_multiple_addresses_reset_counters(struct pubnub_multi_addresses* spare_addresses) +{ + PUBNUB_UNUSED(spare_addresses); +} +#endif + /* The Pubnub version stubs */ @@ -352,6 +359,11 @@ char const *pubnub_uname(void) return "unit-test-0.1"; } +char const* pubnub_uagent(void) +{ + return "POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION; +} + /* The Pubnub NTF mocks and stubs */ void pbntf_trans_outcome(pubnub_t *pb, enum pubnub_state state) @@ -469,10 +481,10 @@ static inline void expect_first_outgoing_GET(const char* url) expect(pbpal_send_status, returns(0)); expect(pbpal_send_str, when(s, streqs(PUBNUB_ORIGIN)), returns(0)); expect(pbpal_send_status, returns(0)); - expect(pbpal_send, - when(data, streqs("\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" - ACCEPT_ENCODING - "\r\n")), + expect(pbpal_send_str, + when(s, streqs("\r\nUser-Agent: POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" + ACCEPT_ENCODING + "\r\n")), returns(0)); expect(pbpal_send_status, returns(0)); expect(pbntf_watch_in_events, when(pb, equals(pbp)), returns(0)); @@ -491,10 +503,10 @@ static inline void expect_first_outgoing_CONNECT(void) expect(pbpal_send_status, returns(0)); expect(pbpal_send_str, when(s, streqs(PUBNUB_ORIGIN)), returns(0)); expect(pbpal_send_status, returns(0)); - expect(pbpal_send, - when(data, streqs("\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" - ACCEPT_ENCODING - "\r\n")), + expect(pbpal_send_str, + when(s, streqs("\r\nUser-Agent: POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" + ACCEPT_ENCODING + "\r\n")), returns(0)); expect(pbpal_send_status, returns(0)); expect(pbntf_watch_in_events, when(pb, equals(pbp)), returns(0)); @@ -517,10 +529,10 @@ static inline void expect_outgoing_with_encoded_credentials_GET(char const *url, expect(pbpal_send_status, returns(0)); expect(pbpal_send_str, when(s, streqs(HTTP_proxy_header)), returns(0)); expect(pbpal_send_status, returns(0)); - expect(pbpal_send, - when(data, streqs("\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" - ACCEPT_ENCODING - "\r\n")), + expect(pbpal_send_str, + when(s, streqs("\r\nUser-Agent: POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" + ACCEPT_ENCODING + "\r\n")), returns(0)); expect(pbpal_send_status, returns(0)); expect(pbntf_watch_in_events, when(pb, equals(pbp)), returns(0)); @@ -542,10 +554,10 @@ static inline void expect_outgoing_with_encoded_credentials_CONNECT(char const * expect(pbpal_send_status, returns(0)); expect(pbpal_send_str, when(s, streqs(HTTP_proxy_header)), returns(0)); expect(pbpal_send_status, returns(0)); - expect(pbpal_send, - when(data, streqs("\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" - ACCEPT_ENCODING - "\r\n")), + expect(pbpal_send_str, + when(s, streqs("\r\nUser-Agent: POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" + ACCEPT_ENCODING + "\r\n")), returns(0)); expect(pbpal_send_status, returns(0)); expect(pbntf_watch_in_events, when(pb, equals(pbp)), returns(0)); @@ -562,10 +574,10 @@ static inline void expect_outgoing_with_url(char const *url) { expect(pbpal_send_status, returns(0)); expect(pbpal_send_str, when(s, streqs(PUBNUB_ORIGIN)), returns(0)); expect(pbpal_send_status, returns(0)); - expect(pbpal_send, - when(data, streqs("\r\nUser-Agent: PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" - ACCEPT_ENCODING - "\r\n")), + expect(pbpal_send_str, + when(s, streqs("\r\nUser-Agent: POSIX-PubNub-C-core/" PUBNUB_SDK_VERSION "\r\n" + ACCEPT_ENCODING + "\r\n")), returns(0)); expect(pbpal_send_status, returns(0)); expect(pbntf_watch_in_events, when(pb, equals(pbp)), returns(0)); @@ -604,6 +616,7 @@ static void cancel_and_cleanup(pubnub_t *pbp) } #endif + Ensure(single_context_pubnub, establishes_proxy_connection_GET_Basic) { uint16_t proxy_port = 500; @@ -685,6 +698,7 @@ Ensure(single_context_pubnub, establishes_proxy_connection_GET_Basic) attest(pubnub_proxy_protocol_get(pbp), equals(pbproxyNONE)); } + Ensure(single_context_pubnub, proxy_GET_Basic_client_sets_timeout_and_max_operation_count_for_keep_alive) { uint16_t proxy_port = 500; @@ -812,6 +826,7 @@ Ensure(single_context_pubnub, proxy_GET_Basic_client_sets_timeout_and_max_operat attest(pubnub_proxy_protocol_get(pbp), equals(pbproxyHTTP_GET)); } + Ensure(single_context_pubnub, GET_Basic_proxy_closes_connection_after_first_407answer_client_keeps_folloving_protocol_until_established) { uint16_t proxy_port = 500; @@ -884,8 +899,38 @@ Ensure(single_context_pubnub, GET_Basic_proxy_closes_connection_after_first_407a attest(pubnub_get(pbp), equals(NULL)); attest(pubnub_get_channel(pbp), streqs(NULL)); attest(pubnub_last_http_code(pbp), equals(200)); + + /* Basic sheme - Proxy responds with 407 after credentials being sent. + It is supposed that authentication is recognized as erroneous + */ + expect(pbntf_enqueue_for_processing, when(pb, equals(pbp)), returns(0)); + expect(pbntf_got_socket, when(pb, equals(pbp)), returns(0)); + expect_outgoing_with_encoded_credentials_GET("/subscribe/sub-key/colors/0/1516714978925123457?pnsdk=unit-test-0.1", + "\r\nProxy-Authorization: Basic c29tZV91c2VyOnNvbWVfcGFzc3dvcmQ="); + incoming_and_close("HTTP/1.1 407 ProxyAuthentication Required\r\n" + "Server: proxy_server.com\r\n" + "Date: Mon, 5 Mar 2018 23:45:55 GMT\r\n" + "Proxy-Authenticate: Basic\r\n" + "Connection: close\r\n" + "Content-Length: 169\r\n" + "\r\n" + "\r\n" + "\r\n" + " \r\n" + " \r\n" + " Error\r\n" + " \r\n" + " \r\n" + "

407 ProxyAuthentication Required.

\r\n" + " \r\n" + "\n"); + attest(pubnub_subscribe(pbp, "colors", NULL), equals(PNR_AUTHENTICATION_FAILED)); + + attest(pubnub_get(pbp), equals(NULL)); + attest(pubnub_last_http_code(pbp), equals(407)); } + Ensure(single_context_pubnub, establishes_proxy_connection_GET_Digest_and_continues_negotiating_after_stale_nounce) { uint16_t port = 500; @@ -924,7 +969,8 @@ Ensure(single_context_pubnub, establishes_proxy_connection_GET_Digest_and_contin "cnonce=\"82b73144c8da461c988e0506fe09e556\", " "nc=\"00000001\", " "qop=\"auth-int\", " - "response=\"2fec0363450ddc98fcfa587da85d3f60\""; + "response=\"2fec0363450ddc98fcfa587da85d3f60\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; #else char const* HTTP_proxy_header1 = "\r\nProxy-Authorization: Digest username=\"average_user\", " "realm=\"testrealm@host.com\", " @@ -960,7 +1006,8 @@ Ensure(single_context_pubnub, establishes_proxy_connection_GET_Digest_and_contin "cnonce=\"51dcb074ff5c49198a94e82aec585562\", " "nc=\"00000001\", " "qop=\"auth-int\", " - "response=\"d0966999c0711a461db101b2d3648bf8\""; + "response=\"d0966999c0711a461db101b2d3648bf8\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; #endif pubnub_init(pbp, "publ-key", "sub-key"); attest(pubnub_set_proxy_manual(pbp, pbproxyHTTP_GET, "proxy.mythic-beasts.com", port), equals(0)); @@ -1041,7 +1088,7 @@ Ensure(single_context_pubnub, establishes_proxy_connection_GET_Digest_and_contin "qop=\"auth,auth-int\", " "stale=TRUE, " "nonce=\"dcd98b7102cc2f0e8b11d0f700bfb0c093\", " - "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\r\n" + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"\r\n" "Content-Type: text/html\r\n" "Content-Length: 153\r\n" "\r\n" @@ -1080,6 +1127,7 @@ Ensure(single_context_pubnub, establishes_proxy_connection_GET_Digest_and_contin attest(pubnub_proxy_protocol_get(pbp), equals(pbproxyHTTP_GET)); } + Ensure(single_context_pubnub, GET_Digest_proxy_closes_connection_after407_and_stale_nounce_but_keeps_negotiating) { uint16_t port = 500; @@ -1118,7 +1166,26 @@ Ensure(single_context_pubnub, GET_Digest_proxy_closes_connection_after407_and_st "cnonce=\"82b73144c8da461c988e0506fe09e556\", " "nc=\"00000001\", " "qop=\"auth-int\", " - "response=\"2fec0363450ddc98fcfa587da85d3f60\""; + "response=\"2fec0363450ddc98fcfa587da85d3f60\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; + char const* HTTP_proxy_header5 = "\r\nProxy-Authorization: Digest username=\"average_user\", " + "realm=\"testrealm@host.com\", " + "nonce=\"dcd98b7102cc2f0e8b11d0f700bfb0c093\", " + "uri=\"/subscribe/sub-key/music/0/1516014978925123577?pnsdk=unit-test-0.1\", " + "cnonce=\"82b73144c8da461c988e0506fe09e556\", " + "nc=\"00000002\", " + "qop=\"auth-int\", " + "response=\"38f6c94df22f77e29c802da5008791e8\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; + char const* HTTP_proxy_header6 = "\r\nProxy-Authorization: Digest username=\"average_user\", " + "realm=\"testrealm@host.com\", " + "nonce=\"dcd98b7102cc2f0e8b11d0f700bfb0c093\", " + "uri=\"/subscribe/sub-key/music/0/1516014978925123577?pnsdk=unit-test-0.1\", " + "cnonce=\"432ff3564d04447798981631553c7c42\", " + "nc=\"00000001\", " + "qop=\"auth-int\", " + "response=\"d3f795dbe1c3942eb4c3445327cde49f\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; #else char const* HTTP_proxy_header1 = "\r\nProxy-Authorization: Digest username=\"average_user\", " "realm=\"testrealm@host.com\", " @@ -1154,7 +1221,26 @@ Ensure(single_context_pubnub, GET_Digest_proxy_closes_connection_after407_and_st "cnonce=\"51dcb074ff5c49198a94e82aec585562\", " "nc=\"00000001\", " "qop=\"auth-int\", " - "response=\"d0966999c0711a461db101b2d3648bf8\""; + "response=\"d0966999c0711a461db101b2d3648bf8\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; + char const* HTTP_proxy_header5 = "\r\nProxy-Authorization: Digest username=\"average_user\", " + "realm=\"testrealm@host.com\", " + "nonce=\"dcd98b7102cc2f0e8b11d0f700bfb0c093\", " + "uri=\"/subscribe/sub-key/music/0/1516014978925123577?pnsdk=unit-test-0.1\", " + "cnonce=\"51dcb074ff5c49198a94e82aec585562\", " + "nc=\"00000002\", " + "qop=\"auth-int\", " + "response=\"6580aa5fc33cbe37ffa73412c7c0ca48\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; + char const* HTTP_proxy_header6 = "\r\nProxy-Authorization: Digest username=\"average_user\", " + "realm=\"testrealm@host.com\", " + "nonce=\"dcd98b7102cc2f0e8b11d0f700bfb0c093\", " + "uri=\"/subscribe/sub-key/music/0/1516014978925123577?pnsdk=unit-test-0.1\", " + "cnonce=\"291f8e23cd7c4846ba581b3dabd77e50\", " + "nc=\"00000001\", " + "qop=\"auth-int\", " + "response=\"84085a90c8ceca28b53f01ea11ee0a65\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\""; #endif pubnub_init(pbp, "publ-key", "sub-key"); attest(pubnub_set_proxy_manual(pbp, pbproxyHTTP_GET, "proxy_server_url", port), equals(0)); @@ -1239,7 +1325,7 @@ Ensure(single_context_pubnub, GET_Digest_proxy_closes_connection_after407_and_st "qop=\"auth,auth-int\", " "stale=TRUE, " "nonce=\"dcd98b7102cc2f0e8b11d0f700bfb0c093\", " - "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\r\n" + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"\r\n" "Connection: close\r\n" "Content-Type: text/html\r\n" "Content-Length: 153\r\n" @@ -1279,8 +1365,68 @@ Ensure(single_context_pubnub, GET_Digest_proxy_closes_connection_after407_and_st attest(pubnub_get_channel(pbp), streqs(NULL)); attest(pubnub_last_http_code(pbp), equals(200)); attest(pubnub_proxy_protocol_get(pbp), equals(pbproxyHTTP_GET)); + + /* Digest sheme - Sending repeated 'authentication required' messages on same realm + within the same transaction should be considered eroneous + */ + expect(pbntf_enqueue_for_processing, when(pb, equals(pbp)), returns(0)); + expect(pbntf_got_socket, when(pb, equals(pbp)), returns(0)); + expect_outgoing_with_encoded_credentials_GET( + "/subscribe/sub-key/music/0/1516014978925123577?pnsdk=unit-test-0.1", + HTTP_proxy_header5); + incoming("HTTP/1.0 407 ProxyAuthentication Required\r\n" + "Server: proxy_server.com\r\n" + "Date: Tue, 12 Mar 2018 19:42:31 GMT\r\n" + "Proxy-Authenticate: Digest realm=\"testrealm@host.com\", " + "qop=\"auth,auth-int\", " + "nonce=\"dcd98b7102cc2f0e8b11d0f700bfb0c093\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"\r\n" + "Connection: keep-alive\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 153\r\n" + "\r\n" + "\r\n" + "\r\n" + " \r\n" + " \r\n" + " Error\r\n" + " \r\n" + " \r\n" + "

401 Unauthorized.

\r\n" + " \r\n" + "\n"); + expect_outgoing_with_encoded_credentials_GET( + "/subscribe/sub-key/music/0/1516014978925123577?pnsdk=unit-test-0.1", + HTTP_proxy_header6); + incoming_and_close("HTTP/1.0 407 ProxyAuthentication Required\r\n" + "Server: proxy_server.com\r\n" + "Date: Tue, 12 Mar 2018 19:42:31 GMT\r\n" + "Proxy-Authenticate: Digest realm=\"testrealm@host.com\", " + "qop=\"auth,auth-int\", " + "nonce=\"dcd98b7102cc2f0e8b11d0f700bfb0c093\", " + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"\r\n" + "Connection: keep-alive\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 153\r\n" + "\r\n" + "\r\n" + "\r\n" + " \r\n" + " \r\n" + " Error\r\n" + " \r\n" + " \r\n" + "

401 Unauthorized.

\r\n" + " \r\n" + "\n"); + attest(pubnub_subscribe(pbp, "music", NULL), equals(PNR_STARTED)); + attest(pbnc_fsm(pbp), equals(0)); + attest(pbnc_fsm(pbp), equals(0)); + attest(pbnc_fsm(pbp), equals(0)); + attest(pbp->core.last_result, equals(PNR_AUTHENTICATION_FAILED)); } + Ensure(single_context_pubnub, try_to_establish_proxy_connection_GET_No_response) { uint16_t port = 500; @@ -1295,6 +1441,7 @@ Ensure(single_context_pubnub, try_to_establish_proxy_connection_GET_No_response) attest(pubnub_subscribe(pbp, "music", NULL), equals(PNR_TIMEOUT)); } + Ensure(single_context_pubnub, try_to_establish_proxy_connection_GET_unsupported_proxy_authentication) { uint16_t port = 500; @@ -1326,11 +1473,12 @@ Ensure(single_context_pubnub, try_to_establish_proxy_connection_GET_unsupported_ attest(pubnub_subscribe(pbp, "music", NULL), equals(PNR_STARTED)); attest(pbnc_fsm(pbp), equals(0)); - attest(pubnub_proxy_protocol_get(pbp), equals(pbproxyHTTP_GET)); attest(pbnc_fsm(pbp), equals(0)); + attest(pbp->core.last_result, equals(PNR_HTTP_ERROR)); } + Ensure(single_context_pubnub, establishes_proxy_connection_CONNECT_Basic) { uint16_t proxy_port = 500; @@ -1396,6 +1544,7 @@ Ensure(single_context_pubnub, establishes_proxy_connection_CONNECT_Basic) attest(pubnub_proxy_protocol_get(pbp), equals(pbproxyHTTP_CONNECT)); } + Ensure(single_context_pubnub, establishes_proxy_connection_CONNECT_Digest) { uint16_t port = 500; @@ -1499,5 +1648,3 @@ Ensure(single_context_pubnub, illegal_parameter_fires_assert) { expect_assert_in(pubnub_proxy_protocol_get(NULL), "pubnub_proxy.c"); expect_assert_in(pubnub_set_proxy_authentication_username_password(NULL, "username", "password"), "pubnub_proxy.c"); } - - diff --git a/core/pubnub_pubsubapi.c b/core/pubnub_pubsubapi.c index 15e90f53..d8e7bd42 100644 --- a/core/pubnub_pubsubapi.c +++ b/core/pubnub_pubsubapi.c @@ -28,7 +28,7 @@ pubnub_t* pubnub_init(pubnub_t* p, const char* publish_key, const char* subscrib #if defined(PUBNUB_CALLBACK_API) p->cb = NULL; p->user_data = NULL; -#endif +#endif /* defined(PUBNUB_CALLBACK_API) */ if (PUBNUB_ORIGIN_SETTABLE) { p->origin = PUBNUB_ORIGIN; } @@ -72,7 +72,7 @@ pubnub_t* pubnub_init(pubnub_t* p, const char* publish_key, const char* subscrib p->proxy_auth_scheme = pbhtauNone; p->proxy_auth_username = NULL; p->proxy_auth_password = NULL; - p->proxy_authorization_sent = false; + p->realm[0] = '\0'; #endif #if PUBNUB_RECEIVE_GZIP_RESPONSE @@ -301,18 +301,23 @@ char const* pubnub_get_origin(pubnub_t* pb) int pubnub_origin_set(pubnub_t* pb, char const* origin) -{ +{ PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); if (PUBNUB_ORIGIN_SETTABLE) { + bool origin_set = false; if (NULL == origin) { origin = PUBNUB_ORIGIN; } pubnub_mutex_lock(pb->monitor); +#if PUBNUB_USE_MULTIPLE_ADDRESSES + pbpal_multiple_addresses_reset_counters(&pb->spare_addresses); +#endif pb->origin = origin; + origin_set = (PBS_IDLE == pb->state); pubnub_mutex_unlock(pb->monitor); - return 0; + return origin_set ? 0 : +1; } return -1; } diff --git a/core/pubnub_pubsubapi.h b/core/pubnub_pubsubapi.h index 8a6ddc6e..b6c01630 100644 --- a/core/pubnub_pubsubapi.h +++ b/core/pubnub_pubsubapi.h @@ -242,8 +242,10 @@ char const* pubnub_get_origin(pubnub_t* p); @param p Pubnub context to set the origin for @param origin The origin to use for context @p p. If NULL, - the default origin will be set - @return 0: success, -1: fail + the default origin will be set + @retval 0 origin set, + @retval +1 origin set will be applied with new connection, + @retval -1 setting origin not enabled */ int pubnub_origin_set(pubnub_t* p, char const* origin); diff --git a/core/pubnub_ssl.c b/core/pubnub_ssl.c index ccb59e1c..be9b7cf4 100644 --- a/core/pubnub_ssl.c +++ b/core/pubnub_ssl.c @@ -9,7 +9,7 @@ void pubnub_set_ssl_options(pubnub_t *p, bool useSSL, bool ignoreSecureConnectio { PUBNUB_ASSERT(pb_valid_ctx_ptr(p)); #if PUBNUB_USE_SSL - p->options.useSSL = p->flags.trySSL = useSSL; + p->options.useSSL = useSSL; p->options.fallbackSSL = ignoreSecureConnectionRequirement; #endif } diff --git a/core/pubnub_subscribe_v2.c b/core/pubnub_subscribe_v2.c index 24b372b8..6165be9f 100644 --- a/core/pubnub_subscribe_v2.c +++ b/core/pubnub_subscribe_v2.c @@ -66,10 +66,8 @@ static enum pubnub_res subscribe_v2_prep(struct pbcc_context* p, p->http_content_len = 0; p->msg_ofs = p->msg_end = 0; - p->http_buf_len = snprintf(p->http_buf, - sizeof p->http_buf, - "/v2/subscribe/%s/", - p->subscribe_key); + p->http_buf_len = snprintf( + p->http_buf, sizeof p->http_buf, "/v2/subscribe/%s/", p->subscribe_key); APPEND_URL_ENCODED_M(p, channel); p->http_buf_len += snprintf(p->http_buf + p->http_buf_len, sizeof p->http_buf - p->http_buf_len, @@ -120,13 +118,12 @@ enum pubnub_res pbcc_parse_subscribe_v2_response(struct pbcc_context* p) enum pbjson_object_name_parse_result jpresult; struct pbjson_elem el; struct pbjson_elem found; - char* reply = p->http_reply; - int replylen = p->http_buf_len; + char* reply = p->http_reply; - if (replylen < MIN_SUBSCRIBE_V2_RESPONSE_LENGTH) { + if (p->http_buf_len < MIN_SUBSCRIBE_V2_RESPONSE_LENGTH) { return PNR_FORMAT_ERROR; } - if ((reply[0] != '{') || (reply[replylen - 1] != '}')) { + if ((reply[0] != '{') || (reply[p->http_buf_len - 1] != '}')) { return PNR_FORMAT_ERROR; } @@ -136,16 +133,16 @@ enum pubnub_res pbcc_parse_subscribe_v2_response(struct pbcc_context* p) if (jonmpOK == jpresult) { struct pbjson_elem titel; if (jonmpOK == pbjson_get_object_value(&found, "t", &titel)) { - unsigned len = titel.end - titel.start - 2; + size_t len = titel.end - titel.start - 2; if ((*titel.start != '"') || (titel.end[-1] != '"')) { PUBNUB_LOG_ERROR("Time token in response is not a string\n"); return PNR_FORMAT_ERROR; } if (len >= sizeof p->timetoken) { - PUBNUB_LOG_ERROR("Time token in response has length %u, longer " - "than our max %lu\n", - len, - sizeof p->timetoken - 1); + PUBNUB_LOG_ERROR( + "Time token in response, length %zu, longer than max %zu\n", + len, + sizeof p->timetoken - 1); return PNR_FORMAT_ERROR; } @@ -180,8 +177,8 @@ enum pubnub_res pbcc_parse_subscribe_v2_response(struct pbcc_context* p) */ jpresult = pbjson_get_object_value(&el, "m", &found); if (jonmpOK == jpresult) { - p->msg_ofs = found.start - reply + 1; - p->msg_end = found.end - reply - 1; + p->msg_ofs = (unsigned)(found.start - reply + 1); + p->msg_end = (unsigned)(found.end - reply - 1); } else { PUBNUB_LOG_ERROR( @@ -223,7 +220,7 @@ struct pubnub_v2_message pubnub_get_v2(pubnub_t* pbp) return rslt; } - p->msg_ofs = seeker - p->http_reply + 2; + p->msg_ofs = (unsigned)(seeker - p->http_reply + 2); el.start = start; el.end = seeker; diff --git a/core/pubnub_version.h b/core/pubnub_version.h index 68d52652..51b2061d 100644 --- a/core/pubnub_version.h +++ b/core/pubnub_version.h @@ -25,5 +25,11 @@ char const *pubnub_version(void); */ char const *pubnub_uname(void); +/** Returns the full identification of the SDK - name, version, etc. + (without Url encoding). + */ +char const *pubnub_uagent(void); + + #endif /* !defined INC_PUBNUB_VERSION */ diff --git a/core/pubnub_version_internal.h b/core/pubnub_version_internal.h index 7540e639..09421597 100644 --- a/core/pubnub_version_internal.h +++ b/core/pubnub_version_internal.h @@ -3,7 +3,7 @@ #define INC_PUBNUB_VERSION_INTERNAL -#define PUBNUB_SDK_VERSION "2.8.2" +#define PUBNUB_SDK_VERSION "2.8.3" #endif /* !defined INC_PUBNUB_VERSION_INTERNAL */ diff --git a/core/samples/console/pnc_subscriptions.c b/core/samples/console/pnc_subscriptions.c index 8919d5c1..54cfcb9f 100644 --- a/core/samples/console/pnc_subscriptions.c +++ b/core/samples/console/pnc_subscriptions.c @@ -19,7 +19,7 @@ static int m_groups_length = 0; void pnc_subscribe_list_channels(char *value, unsigned max_length) { int i; - unsigned length; + size_t length; PUBNUB_ASSERT_OPT(max_length > 0); @@ -30,7 +30,7 @@ void pnc_subscribe_list_channels(char *value, unsigned max_length) } for (i = 0; i < m_channels_length; ++i) { - unsigned channel_length = strlen(m_channels[i]); + size_t channel_length = strlen(m_channels[i]); if (channel_length > 0) { if (length + channel_length + 1 >= max_length) { PUBNUB_ASSERT_OPT(0); @@ -50,7 +50,7 @@ void pnc_subscribe_list_channels(char *value, unsigned max_length) void pnc_subscribe_list_channel_groups(char *value, unsigned max_length) { int i; - unsigned length; + size_t length; PUBNUB_ASSERT_OPT(max_length > 0); @@ -61,7 +61,7 @@ void pnc_subscribe_list_channel_groups(char *value, unsigned max_length) } for (i = 0; i < m_groups_length; ++i) { - unsigned group_length = strlen(m_groups[i]); + size_t group_length = strlen(m_groups[i]); if (group_length > 0) { if (length + group_length + 1 >= max_length) { PUBNUB_ASSERT_OPT(0); diff --git a/core/test/pubnub_config.h b/core/test/pubnub_config.h index 7810fd7a..4d8996cf 100644 --- a/core/test/pubnub_config.h +++ b/core/test/pubnub_config.h @@ -90,17 +90,10 @@ #endif #if PUBNUB_USE_MULTIPLE_ADDRESSES -#if PUBNUB_USE_SSL #define PUBNUB_MAX_IPV4_ADDRESSES 2 #if PUBNUB_USE_IPV6 #define PUBNUB_MAX_IPV6_ADDRESSES 2 #endif -#else -#define PUBNUB_MAX_IPV4_ADDRESSES 1 -#if PUBNUB_USE_IPV6 -#define PUBNUB_MAX_IPV6_ADDRESSES 1 -#endif -#endif /* PUBNUB_USE_SSL */ #endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ #if !defined(PUBNUB_SET_DNS_SERVERS) diff --git a/cpp/posix.mk b/cpp/posix.mk index 96668614..43e3e23b 100644 --- a/cpp/posix.mk +++ b/cpp/posix.mk @@ -1,4 +1,4 @@ -SOURCEFILES = ../core/pubnub_pubsubapi.c ../core/pubnub_coreapi.c ../core/pubnub_coreapi_ex.c ../core/pubnub_ccore_pubsub.c ../core/pubnub_ccore.c ../core/pubnub_netcore.c ../lib/sockets/pbpal_sockets.c ../lib/sockets/pbpal_resolv_and_connect_sockets.c ../core/pubnub_alloc_std.c ../core/pubnub_assert_std.c ../core/pubnub_generate_uuid.c ../core/pubnub_blocking_io.c ../posix/posix_socket_blocking_io.c ../core/pubnub_timers.c ../core/pubnub_json_parse.c ../lib/md5/md5.c ../lib/base64/pbbase64.c ../core/pubnub_helper.c ../posix/pubnub_version_posix.c ../posix/pubnub_generate_uuid_posix.c ../posix/pbpal_posix_blocking_io.c ../core/pubnub_free_with_timeout_std.c pubnub_subloop.cpp ../posix/msstopwatch_monotonic_clock.c ../core/pubnub_url_encode.c +SOURCEFILES = ../core/pubnub_pubsubapi.c ../core/pubnub_coreapi.c ../core/pubnub_coreapi_ex.c ../core/pubnub_ccore_pubsub.c ../core/pubnub_ccore.c ../core/pubnub_netcore.c ../lib/sockets/pbpal_sockets.c ../lib/sockets/pbpal_resolv_and_connect_sockets.c ../core/pubnub_alloc_std.c ../core/pubnub_assert_std.c ../core/pubnub_generate_uuid.c ../core/pubnub_blocking_io.c ../posix/posix_socket_blocking_io.c ../core/pubnub_timers.c ../core/pubnub_json_parse.c ../lib/md5/md5.c ../lib/base64/pbbase64.c ../core/pubnub_helper.c pubnub_version_posix.cpp ../posix/pubnub_generate_uuid_posix.c ../posix/pbpal_posix_blocking_io.c ../core/pubnub_free_with_timeout_std.c pubnub_subloop.cpp ../posix/msstopwatch_monotonic_clock.c ../core/pubnub_url_encode.c ifndef ONLY_PUBSUB_API ONLY_PUBSUB_API = 0 diff --git a/cpp/posix_openssl.mk b/cpp/posix_openssl.mk index 3720bfbd..9f6936c3 100644 --- a/cpp/posix_openssl.mk +++ b/cpp/posix_openssl.mk @@ -1,4 +1,4 @@ -SOURCEFILES = ../core/pubnub_pubsubapi.c ../core/pubnub_coreapi.c ../core/pubnub_ccore_pubsub.c ../core/pubnub_ccore.c ../core/pubnub_netcore.c ../lib/sockets/pbpal_resolv_and_connect_sockets.c ../openssl/pbpal_openssl.c ../openssl/pbpal_connect_openssl.c ../openssl/pbpal_add_system_certs_posix.c ../core/pubnub_alloc_std.c ../core/pubnub_assert_std.c ../core/pubnub_generate_uuid.c ../core/pubnub_blocking_io.c ../posix/posix_socket_blocking_io.c ../core/pubnub_free_with_timeout_std.c ../core/pubnub_timers.c ../core/pubnub_json_parse.c ../lib/md5/md5.c ../lib/base64/pbbase64.c ../core/pubnub_helper.c ../openssl/pubnub_version_openssl.c ../posix/pubnub_generate_uuid_posix.c ../openssl/pbpal_openssl_blocking_io.c ../core/pubnub_crypto.c ../core/pubnub_coreapi_ex.c ../openssl/pbaes256.c ../posix/msstopwatch_monotonic_clock.c ../core/pubnub_url_encode.c +SOURCEFILES = ../core/pubnub_pubsubapi.c ../core/pubnub_coreapi.c ../core/pubnub_ccore_pubsub.c ../core/pubnub_ccore.c ../core/pubnub_netcore.c ../lib/sockets/pbpal_resolv_and_connect_sockets.c ../openssl/pbpal_openssl.c ../openssl/pbpal_connect_openssl.c ../openssl/pbpal_add_system_certs_posix.c ../core/pubnub_alloc_std.c ../core/pubnub_assert_std.c ../core/pubnub_generate_uuid.c ../core/pubnub_blocking_io.c ../posix/posix_socket_blocking_io.c ../core/pubnub_free_with_timeout_std.c ../core/pubnub_timers.c ../core/pubnub_json_parse.c ../lib/md5/md5.c ../lib/base64/pbbase64.c ../core/pubnub_helper.c pubnub_version_posix.cpp ../posix/pubnub_generate_uuid_posix.c ../openssl/pbpal_openssl_blocking_io.c ../core/pubnub_crypto.c ../core/pubnub_coreapi_ex.c ../openssl/pbaes256.c ../posix/msstopwatch_monotonic_clock.c ../core/pubnub_url_encode.c ifndef ONLY_PUBSUB_API ONLY_PUBSUB_API = 0 diff --git a/cpp/pubnub_version_posix.cpp b/cpp/pubnub_version_posix.cpp new file mode 100644 index 00000000..eb831f00 --- /dev/null +++ b/cpp/pubnub_version_posix.cpp @@ -0,0 +1,31 @@ +/* -*- c-file-style:"stroustrup"; indent-tabs-mode: nil -*- */ +#include "core/pubnub_version.h" + +#include "core/pubnub_version_internal.h" + + +#define PUBNUB_SDK_NAME "POSIX" + + +char const *pubnub_sdk_name(void) +{ + return PUBNUB_SDK_NAME; +} + + +char const *pubnub_version(void) +{ + return PUBNUB_SDK_VERSION; +} + + +char const *pubnub_uname(void) +{ + return PUBNUB_SDK_NAME "-PubNub-C++-core%2F" PUBNUB_SDK_VERSION; +} + + +char const *pubnub_uagent(void) +{ + return PUBNUB_SDK_NAME "-PubNub-C++-core/" PUBNUB_SDK_VERSION; +} diff --git a/cpp/pubnub_version_windows.cpp b/cpp/pubnub_version_windows.cpp new file mode 100644 index 00000000..139e2d2b --- /dev/null +++ b/cpp/pubnub_version_windows.cpp @@ -0,0 +1,31 @@ +/* -*- c-file-style:"stroustrup"; indent-tabs-mode: nil -*- */ +#include "core/pubnub_version.h" + +#include "core/pubnub_version_internal.h" + + +#define PUBNUB_SDK_NAME "Windows" + + +char const *pubnub_sdk_name(void) +{ + return PUBNUB_SDK_NAME; +} + + +char const *pubnub_version(void) +{ + return PUBNUB_SDK_VERSION; +} + + +char const *pubnub_uname(void) +{ + return PUBNUB_SDK_NAME "-PubNub-C++-core%2F" PUBNUB_SDK_VERSION; +} + + +char const *pubnub_uagent(void) +{ + return PUBNUB_SDK_NAME "-PubNub-C++-core/" PUBNUB_SDK_VERSION; +} diff --git a/cpp/windows.mk b/cpp/windows.mk index 6a6d56ec..c696848d 100644 --- a/cpp/windows.mk +++ b/cpp/windows.mk @@ -1,4 +1,4 @@ -SOURCEFILES = ..\core\pubnub_pubsubapi.c ..\core\pubnub_coreapi.c ..\core\pubnub_coreapi_ex.c ..\core\pubnub_ccore_pubsub.c ..\core\pubnub_ccore.c ..\core\pubnub_netcore.c ..\lib\sockets\pbpal_sockets.c ..\lib\sockets\pbpal_resolv_and_connect_sockets.c ..\core\pubnub_alloc_std.c ..\core\pubnub_assert_std.c ..\core\pubnub_generate_uuid.c ..\core\pubnub_timers.c ..\core\pubnub_blocking_io.c ..\lib\base64\pbbase64.c ..\core\pubnub_json_parse.c ..\core\pubnub_free_with_timeout_std.c ..\lib\md5\md5.c ..\core\pubnub_helper.c ..\windows\pubnub_version_windows.c ..\windows\pubnub_generate_uuid_windows.c ..\windows\pbpal_windows_blocking_io.c ..\windows\windows_socket_blocking_io.c ..\core\c99\snprintf.c ..\lib\miniz\miniz_tinfl.c ..\lib\miniz\miniz_tdef.c ..\lib\miniz\miniz.c ..\lib\pbcrc32.c ..\core\pbgzip_compress.c ..\core\pbgzip_decompress.c ..\core\pubnub_subscribe_v2.c ..\windows\msstopwatch_windows.c ..\core\pubnub_url_encode.c ..\core\pbcc_advanced_history.c ..\core\pubnub_advanced_history.c +SOURCEFILES = ..\core\pubnub_pubsubapi.c ..\core\pubnub_coreapi.c ..\core\pubnub_coreapi_ex.c ..\core\pubnub_ccore_pubsub.c ..\core\pubnub_ccore.c ..\core\pubnub_netcore.c ..\lib\sockets\pbpal_sockets.c ..\lib\sockets\pbpal_resolv_and_connect_sockets.c ..\core\pubnub_alloc_std.c ..\core\pubnub_assert_std.c ..\core\pubnub_generate_uuid.c ..\core\pubnub_timers.c ..\core\pubnub_blocking_io.c ..\lib\base64\pbbase64.c ..\core\pubnub_json_parse.c ..\core\pubnub_free_with_timeout_std.c ..\lib\md5\md5.c ..\core\pubnub_helper.c pubnub_version_windows.cpp ..\windows\pubnub_generate_uuid_windows.c ..\windows\pbpal_windows_blocking_io.c ..\windows\windows_socket_blocking_io.c ..\core\c99\snprintf.c ..\lib\miniz\miniz_tinfl.c ..\lib\miniz\miniz_tdef.c ..\lib\miniz\miniz.c ..\lib\pbcrc32.c ..\core\pbgzip_compress.c ..\core\pbgzip_decompress.c ..\core\pubnub_subscribe_v2.c ..\windows\msstopwatch_windows.c ..\core\pubnub_url_encode.c ..\core\pbcc_advanced_history.c ..\core\pubnub_advanced_history.c LIBS=ws2_32.lib rpcrt4.lib diff --git a/cpp/windows_openssl.mk b/cpp/windows_openssl.mk index a46823cf..45acf2e3 100644 --- a/cpp/windows_openssl.mk +++ b/cpp/windows_openssl.mk @@ -1,4 +1,4 @@ -SOURCEFILES = ..\core\pubnub_pubsubapi.c ..\core\pubnub_coreapi.c ..\core\pubnub_ccore_pubsub.c ..\core\pubnub_ccore.c ..\core\pubnub_netcore.c ..\lib\sockets\pbpal_resolv_and_connect_sockets.c ..\openssl\pbpal_openssl.c ..\openssl\pbpal_connect_openssl.c ..\core\pubnub_alloc_std.c ..\core\pubnub_assert_std.c ..\core\pubnub_generate_uuid.c ..\core\pubnub_blocking_io.c ..\lib\base64\pbbase64.c ..\core\pubnub_json_parse.c ..\core\pubnub_helper.c ..\openssl\pubnub_version_openssl.c ..\windows\pubnub_generate_uuid_windows.c ..\openssl\pbpal_openssl_blocking_io.c ..\windows\windows_socket_blocking_io.c ..\core\pubnub_timers.c ..\core\c99\snprintf.c ..\openssl\pbpal_add_system_certs_windows.c ..\core\pubnub_free_with_timeout_std.c ..\lib\md5\md5.c ..\core\pubnub_ssl.c ..\core\pubnub_crypto.c ..\core\pubnub_coreapi_ex.c ..\openssl\pbaes256.c ..\lib\miniz\miniz_tinfl.c ..\lib\miniz\miniz_tdef.c ..\lib\miniz\miniz.c ..\lib\pbcrc32.c ..\core\pbgzip_compress.c ..\core\pbgzip_decompress.c ..\core\pubnub_subscribe_v2.c ..\windows\msstopwatch_windows.c ..\core\pubnub_url_encode.c ..\core\pbcc_advanced_history.c ..\core\pubnub_advanced_history.c +SOURCEFILES = ..\core\pubnub_pubsubapi.c ..\core\pubnub_coreapi.c ..\core\pubnub_ccore_pubsub.c ..\core\pubnub_ccore.c ..\core\pubnub_netcore.c ..\lib\sockets\pbpal_resolv_and_connect_sockets.c ..\openssl\pbpal_openssl.c ..\openssl\pbpal_connect_openssl.c ..\core\pubnub_alloc_std.c ..\core\pubnub_assert_std.c ..\core\pubnub_generate_uuid.c ..\core\pubnub_blocking_io.c ..\lib\base64\pbbase64.c ..\core\pubnub_json_parse.c ..\core\pubnub_helper.c pubnub_version_windows.cpp ..\windows\pubnub_generate_uuid_windows.c ..\openssl\pbpal_openssl_blocking_io.c ..\windows\windows_socket_blocking_io.c ..\core\pubnub_timers.c ..\core\c99\snprintf.c ..\openssl\pbpal_add_system_certs_windows.c ..\core\pubnub_free_with_timeout_std.c ..\lib\md5\md5.c ..\core\pubnub_ssl.c ..\core\pubnub_crypto.c ..\core\pubnub_coreapi_ex.c ..\openssl\pbaes256.c ..\lib\miniz\miniz_tinfl.c ..\lib\miniz\miniz_tdef.c ..\lib\miniz\miniz.c ..\lib\pbcrc32.c ..\core\pbgzip_compress.c ..\core\pbgzip_decompress.c ..\core\pubnub_subscribe_v2.c ..\windows\msstopwatch_windows.c ..\core\pubnub_url_encode.c ..\core\pbcc_advanced_history.c ..\core\pubnub_advanced_history.c !ifndef OPENSSLPATH OPENSSLPATH=c:\OpenSSL-Win32 diff --git a/lib/pubnub_dns_codec.c b/lib/pubnub_dns_codec.c index 1df287b6..995d86e8 100644 --- a/lib/pubnub_dns_codec.c +++ b/lib/pubnub_dns_codec.c @@ -67,6 +67,9 @@ enum DNSoptionsMask { /** Offset of the type sub-field of the RESOURCE DATA */ #define RESOURCE_DATA_TYPE_OFFSET -10 +/** Offset of the data length sub-field of the RESOURCE DATA */ +#define RESOURCE_DATA_TTL_OFFSET -6 + /** Offset of the data length sub-field of the RESOURCE DATA */ #define RESOURCE_DATA_DATA_LEN_OFFSET -2 @@ -510,17 +513,32 @@ static int check_answer(const uint8_t** o_reader, if (false == *p_address_found) { memcpy(resolved_addr_ipv4->ipv4, reader, 4); *p_address_found = true; -#if PUBNUB_USE_MULTIPLE_ADDRESSES && PUBNUB_USE_SSL - if (options->fallbackSSL) { - memcpy(spare_addresses->ipv4_addresses[spare_addresses->n_ipv4++].ipv4, - resolved_addr_ipv4->ipv4, - 4); - } -#endif /* PUBNUB_USE_SSL */ } #if PUBNUB_USE_MULTIPLE_ADDRESSES - else if (spare_addresses->n_ipv4 < PUBNUB_MAX_IPV4_ADDRESSES) { - memcpy(spare_addresses->ipv4_addresses[spare_addresses->n_ipv4++].ipv4, reader, 4); + if (spare_addresses->n_ipv4 < PUBNUB_MAX_IPV4_ADDRESSES) { + /* Time to live. Network byte order - big endian */ + uint32_t ttl_ipv4 = ((uint32_t)reader[RESOURCE_DATA_TTL_OFFSET] << 24) | + ((uint32_t)reader[RESOURCE_DATA_TTL_OFFSET + 1] << 16) | + ((uint32_t)reader[RESOURCE_DATA_TTL_OFFSET + 2] << 8) | + (uint32_t)reader[RESOURCE_DATA_TTL_OFFSET + 3]; + if (ttl_ipv4 > 0) { + /* We have intention remembering 2 least significant bytes(lower 16 bits: + 2^16 == 65536(seconds), considering that transaction('subscribe') is allowed + to last up to five minutes(300 seconds) and we aim to use only necessary + amount of memory. + */ + if (ttl_ipv4 >= 65536) { + PUBNUB_LOG_WARNING("Warning: ttl for ipv4 received is out of range: " + "ttl_ipv4=%u seconds\n", + ttl_ipv4); + spare_addresses->ttl_ipv4[spare_addresses->n_ipv4] = 0xFFFF; + } + else { + PUBNUB_LOG_TRACE("ttl_ipv4= %u seconds\n", ttl_ipv4); + spare_addresses->ttl_ipv4[spare_addresses->n_ipv4] = (uint16_t)ttl_ipv4; + } + memcpy(spare_addresses->ipv4_addresses[spare_addresses->n_ipv4++].ipv4, reader, 4); + } } #endif return 0; @@ -548,17 +566,27 @@ static int check_answer(const uint8_t** o_reader, if (false == *p_address_found) { memcpy(resolved_addr_ipv6->ipv6, reader, 16); *p_address_found = true; -#if PUBNUB_USE_MULTIPLE_ADDRESSES && PUBNUB_USE_SSL - if (options->fallbackSSL) { - memcpy(spare_addresses->ipv6_addresses[spare_addresses->n_ipv6++].ipv6, - resolved_addr_ipv6->ipv6, - 16); - } -#endif /* PUBNUB_USE_SSL */ } #if PUBNUB_USE_MULTIPLE_ADDRESSES - else if (spare_addresses->n_ipv6 < PUBNUB_MAX_IPV6_ADDRESSES) { - memcpy(spare_addresses->ipv6_addresses[spare_addresses->n_ipv6++].ipv6, reader, 16); + if (spare_addresses->n_ipv6 < PUBNUB_MAX_IPV6_ADDRESSES) { + /* Time to live. Network byte order - big endian */ + uint32_t ttl_ipv6 = ((uint32_t)reader[RESOURCE_DATA_TTL_OFFSET] << 24) | + ((uint32_t)reader[RESOURCE_DATA_TTL_OFFSET + 1] << 16) | + ((uint32_t)reader[RESOURCE_DATA_TTL_OFFSET + 2] << 8) | + (uint32_t)reader[RESOURCE_DATA_TTL_OFFSET + 3]; + if (ttl_ipv6 > 0) { + if (ttl_ipv6 >= 65536) { + PUBNUB_LOG_WARNING("Warning: ttl for ipv6 received is out of range: " + "ttl_ipv6=%u seconds\n", + ttl_ipv6); + spare_addresses->ttl_ipv6[spare_addresses->n_ipv6] = 0xFFFF; + } + else { + PUBNUB_LOG_TRACE("ttl_ipv6= %u seconds\n", ttl_ipv6); + spare_addresses->ttl_ipv6[spare_addresses->n_ipv6] = (uint16_t)ttl_ipv6; + } + memcpy(spare_addresses->ipv6_addresses[spare_addresses->n_ipv6++].ipv6, reader, 16); + } } #endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ return 0; diff --git a/lib/pubnub_dns_codec_unit_test.c b/lib/pubnub_dns_codec_unit_test.c index b4b09470..d9207dc6 100644 --- a/lib/pubnub_dns_codec_unit_test.c +++ b/lib/pubnub_dns_codec_unit_test.c @@ -170,7 +170,7 @@ static void set_offset(uint8_t* name, size_t length) set_offset((uint8_t*)(name), length); \ } while(0) -#define append_answer_M(name, type, data) \ +#define append_answer_M(name, type, data, ttl) \ do { \ size_t length = length_M(name); \ size_t recordDataLength = sizeof data; \ @@ -186,6 +186,10 @@ static void set_offset(uint8_t* name, size_t length) m_buf[m_msg_size] = (type) >> 8; \ m_buf[m_msg_size + 1] = (type) & 0xFF; \ m_msg_size += TYPE_AND_CLASS_FIELDS_SIZE + TTL_FIELD_SIZE;\ + m_buf[m_msg_size - 4] = (uint64_t)ttl >> 24; \ + m_buf[m_msg_size - 3] = ((uint64_t)ttl >> 16) & 0xFF; \ + m_buf[m_msg_size - 2] = ((uint64_t)ttl >> 8) & 0xFF; \ + m_buf[m_msg_size - 1] = (uint64_t)ttl & 0xFF; \ m_buf[m_msg_size] = recordDataLength >> 8; \ m_buf[m_msg_size + 1] = recordDataLength & 0xFF; \ m_msg_size += RECORD_DATA_LENGTH_FIELD_SIZE; \ @@ -307,9 +311,9 @@ Ensure(pubnub_dns_codec, decodes_strange_response_2_questions_3_answers) make_dns_header_M(RESPONSE, 2, 3); append_question_M(just_offset); append_question_M(encoded_piece1); - append_answer_M(encoded_domain_name, RecordTypeA, data); - append_answer_M(encoded_piece2, RecordTypeTXT, data); - append_answer_M(encoded_domain_name, RecordTypeA, data_2); + append_answer_M(encoded_domain_name, RecordTypeA, data, 13); + append_answer_M(encoded_piece2, RecordTypeTXT, data, 10); + append_answer_M(encoded_domain_name, RecordTypeA, data_2, 100); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, @@ -319,22 +323,17 @@ Ensure(pubnub_dns_codec, decodes_strange_response_2_questions_3_answers) equals(0)); attest(memcmp(&resolved_addr_ipv4, &key_addr, sizeof resolved_addr_ipv4), equals(0)); #if PUBNUB_USE_MULTIPLE_ADDRESSES -#if PUBNUB_USE_SSL attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, data, sizeof resolved_addr_ipv4.ipv4), equals(0)); + attest(bp.spare_addresses.ttl_ipv4[0], equals(13)); attest(memcmp(bp.spare_addresses.ipv4_addresses[1].ipv4, data_2, sizeof bp.spare_addresses.ipv4_addresses[1].ipv4), equals(0)); + attest(bp.spare_addresses.ttl_ipv4[1], equals(100)); attest(bp.spare_addresses.n_ipv4, equals(2)); -#else - attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, - data_2, - sizeof resolved_addr_ipv4.ipv4), equals(0)); - attest(bp.spare_addresses.n_ipv4, equals(1)); -#endif /* PUBNUB_USE_SSL */ attest(bp.spare_addresses.ipv4_index, equals(0)); #if PUBNUB_USE_IPV6 attest(bp.spare_addresses.n_ipv6, equals(0)); @@ -363,9 +362,10 @@ Ensure(pubnub_dns_codec, decodes_response_1_question_3_answers_no_ssl_fallback) */ make_dns_header_M(RESPONSE, 1, 3); append_question_M(encoded_abc_domain_name); - append_answer_M(encoded_domain_name, RecordTypeA, data); - append_answer_M(encoded_domain_name, RecordTypeA, data_2); - append_answer_M(encoded_domain_name, RecordTypeA, data_3); + append_answer_M(encoded_domain_name, RecordTypeA, data, 150); + /* Time to live out of range */ + append_answer_M(encoded_domain_name, RecordTypeA, data_2, 65536); + append_answer_M(encoded_domain_name, RecordTypeA, data_3, 2); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, @@ -375,23 +375,17 @@ Ensure(pubnub_dns_codec, decodes_response_1_question_3_answers_no_ssl_fallback) equals(0)); attest(memcmp(&resolved_addr_ipv4, &key_addr, sizeof resolved_addr_ipv4), equals(0)); #if PUBNUB_USE_MULTIPLE_ADDRESSES -#if PUBNUB_USE_SSL attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, - data_2, + data, sizeof bp.spare_addresses.ipv4_addresses[0].ipv4), equals(0)); + attest(bp.spare_addresses.ttl_ipv4[0], equals(150)); attest(memcmp(bp.spare_addresses.ipv4_addresses[1].ipv4, - data_3, + data_2, sizeof bp.spare_addresses.ipv4_addresses[1].ipv4), equals(0)); + attest(bp.spare_addresses.ttl_ipv4[1], equals(0xFFFF)); attest(bp.spare_addresses.n_ipv4, equals(2)); -#else - attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, - data_2, - sizeof bp.spare_addresses.ipv4_addresses[0].ipv4), - equals(0)); - attest(bp.spare_addresses.n_ipv4, equals(1)); -#endif /* PUBNUB_USE_SSL */ attest(bp.spare_addresses.ipv4_index, equals(0)); #if PUBNUB_USE_IPV6 attest(bp.spare_addresses.n_ipv6, equals(0)); @@ -409,8 +403,8 @@ Ensure(pubnub_dns_codec, decodes_strange_response_wrong_answers) make_dns_header_M(RESPONSE, 1, 2); append_question_M(just_offset); - append_answer_M(encoded_domain_name, RecordTypeSRV, data); - append_answer_M(encoded_abc_domain_name, RecordTypeTXT, data); + append_answer_M(encoded_domain_name, RecordTypeSRV, data, 7000); + append_answer_M(encoded_abc_domain_name, RecordTypeTXT, data, 65000); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, @@ -442,7 +436,7 @@ Ensure(pubnub_dns_codec, decodes_label_too_long_to_fit_in_modules_buffer) /** name ends with offset */ encoded_long_piece21[length_M(encoded_long_piece21) - 2] = '\322'; append_question_M(encoded_long_piece21); - append_answer_M(encoded_long_piece21, RecordTypeA, data); + append_answer_M(encoded_long_piece21, RecordTypeA, data, 5); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, @@ -460,15 +454,12 @@ Ensure(pubnub_dns_codec, decodes_label_too_long_to_fit_in_modules_buffer) PBDNS_OPTIONAL_PARAMS_BP), equals(-1)); #if PUBNUB_USE_MULTIPLE_ADDRESSES -#if PUBNUB_USE_SSL attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, data, sizeof resolved_addr_ipv4.ipv4), equals(0)); + attest(bp.spare_addresses.ttl_ipv4[0], equals(5)); attest(bp.spare_addresses.n_ipv4, equals(1)); -#else - attest(bp.spare_addresses.n_ipv4, equals(0)); -#endif /* PUBNUB_USE_SSL */ attest(bp.spare_addresses.ipv4_index, equals(0)); #if PUBNUB_USE_IPV6 attest(bp.spare_addresses.n_ipv6, equals(0)); @@ -487,7 +478,7 @@ Ensure(pubnub_dns_codec, decodes_name_too_long_for_modules_buffer_ending_with_ba /* Label finishes with bad offset format */ encoded_long_piece21[length_M(encoded_long_piece21) - 2] = '\100'; append_question_M(encoded_long_piece21); - append_answer_M(encoded_long_piece21, RecordTypeA, data); + append_answer_M(encoded_long_piece21, RecordTypeA, data, 3); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, @@ -513,7 +504,7 @@ Ensure(pubnub_dns_codec, decodes_name_too_long_for_modules_buffer_finishing_with /* Changing the length of the last label stretch(+ 1 byte) */ encoded_long_piece21[length_M(encoded_long_piece21) - 37] = '\43'; append_question_M(encoded_long_piece21); - append_answer_M(encoded_long_piece21, RecordTypeA, data); + append_answer_M(encoded_long_piece21, RecordTypeA, data, 4); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, @@ -539,9 +530,9 @@ Ensure(pubnub_dns_codec, decodes_another_spooky_response) */ make_dns_header_M(RESPONSE, 1, 2); append_question_M(encoded_abc_domain_name); - append_answer_M(encoded_piece1, RecordTypeTXT, data); - append_answer_M(encoded_domain_name, RecordTypeA, data); - append_answer_M(encoded_piece2, RecordTypePTR, data); + append_answer_M(encoded_piece1, RecordTypeTXT, data, 250); + append_answer_M(encoded_domain_name, RecordTypeA, data, 60); + append_answer_M(encoded_piece2, RecordTypePTR, data, 87); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, @@ -562,9 +553,9 @@ Ensure(pubnub_dns_codec, decodes_response_encoded_label_splitted) memcpy(key_addr.ipv4, data, sizeof key_addr.ipv4); /* Ignores the fact that response has no questions */ make_dns_header_M(RESPONSE, 0, 2); - append_answer_M(encoded_piece21, RecordTypeSRV, data); + append_answer_M(encoded_piece21, RecordTypeSRV, data, 133); PUBNUB_LOG_TRACE("------->forming encoded label:\n"); - append_answer_M(encoded_piece1, RecordTypeA, data); + append_answer_M(encoded_piece1, RecordTypeA, data, 4); place_encoded_label_piece_M(encoded_piece2); place_encoded_label_piece_M(encoded_piece31); place_encoded_label_piece_M(encoded_piece4); @@ -579,15 +570,12 @@ Ensure(pubnub_dns_codec, decodes_response_encoded_label_splitted) equals(0)); attest(memcmp(&resolved_addr_ipv4, &key_addr, sizeof resolved_addr_ipv4), equals(0)); #if PUBNUB_USE_MULTIPLE_ADDRESSES -#if PUBNUB_USE_SSL attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, data, sizeof resolved_addr_ipv4.ipv4), equals(0)); + attest(bp.spare_addresses.ttl_ipv4[0], equals(4)); attest(bp.spare_addresses.n_ipv4, equals(1)); -#else - attest(bp.spare_addresses.n_ipv4, equals(0)); -#endif /* PUBNUB_USE_SSL */ attest(bp.spare_addresses.ipv4_index, equals(0)); #if PUBNUB_USE_IPV6 attest(bp.spare_addresses.n_ipv6, equals(0)); @@ -667,7 +655,7 @@ Ensure(pubnub_dns_codec, handles_response_no_usable_answer) PBDNS_OPTIONAL_PARAMS_BP), equals(-1)); - append_answer_M(encoded_long_piece1, RecordTypeAAAA, data); + append_answer_M(encoded_long_piece1, RecordTypeAAAA, data, 11); /* Message doesn't contain complete answer name?! */ attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size @@ -699,7 +687,7 @@ Ensure(pubnub_dns_codec, handles_response_no_usable_answer) equals(-1)); place_encoded_label_piece_M(offset_within_header); /* Won't find the answer due to contaminated answers label */ - append_answer_M(encoded_piece21, RecordTypeA, data2); + append_answer_M(encoded_piece21, RecordTypeA, data2, 79); place_encoded_label_piece_M(bad_offset_format); resize_msg(); @@ -727,7 +715,7 @@ Ensure(pubnub_dns_codec, handles_label_offset_to_itself_preventing_infinite_loop make_dns_header_M(RESPONSE, 1, 1); append_question_M(encoded_label_start_with_offset_to_itself); PUBNUB_LOG_TRACE("------->forming encoded label:\n"); - append_answer_M(encoded_piece1, RecordTypeA, data); + append_answer_M(encoded_piece1, RecordTypeA, data, 9); place_encoded_label_piece_M(encoded_piece21); place_encoded_label_piece_M(encoded_piece4); PUBNUB_LOG_TRACE("------->encoded label formed:\n"); @@ -805,12 +793,13 @@ Ensure(pubnub_dns_codec, handles_splitted_label_too_long_for_modules_buffer) m_buf[NS_COUNT_OFFSET] = 0xFF; m_buf[AR_COUNT_OFFSET] = 0xFF; PUBNUB_LOG_TRACE("------->forming encoded label:\n"); - append_answer_M(encoded_long_piece1, RecordTypeAAAA, data); + append_answer_M(encoded_long_piece1, RecordTypeAAAA, data, 10); place_encoded_label_piece_M(encoded_piece21); place_encoded_label_piece_M(encoded_long_piece2); place_encoded_label_piece_M(encoded_piece4); PUBNUB_LOG_TRACE("------->encoded label formed:\n"); - append_answer_M(encoded_long_piece1, RecordTypeA, data); + /* Address with time to live 0 wan't be 'cashed'(, but might be used just once) */ + append_answer_M(encoded_long_piece1, RecordTypeA, data, 0); resize_msg(); attest(pbdns_pick_resolved_addresses(m_buf, @@ -820,6 +809,12 @@ Ensure(pubnub_dns_codec, handles_splitted_label_too_long_for_modules_buffer) PBDNS_OPTIONAL_PARAMS_BP), equals(0)); attest(memcmp(&resolved_addr_ipv4, &key_addr, sizeof resolved_addr_ipv4), equals(0)); +#if PUBNUB_USE_MULTIPLE_ADDRESSES + attest(bp.spare_addresses.n_ipv4, equals(0)); + attest(bp.spare_addresses.ipv4_index, equals(0)); + attest(bp.spare_addresses.n_ipv6, equals(0)); + attest(bp.spare_addresses.ipv6_index, equals(0)); +#endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ } /* If there is a badly encoded label(some label stretch shorter or longer than it indicates @@ -833,7 +828,7 @@ Ensure(pubnub_dns_codec, handles_response_label_encoded_badly) struct pubnub_ipv4_address resolved_addr_ipv4; make_dns_header_M(RESPONSE, 1, 1); append_question_M(label_start_encoded_badly_with_offset_to_itself); - append_answer_M(encoded_piece31, RecordTypeA, data); + append_answer_M(encoded_piece31, RecordTypeA, data, 19); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, &resolved_addr_ipv4 @@ -846,18 +841,31 @@ Ensure(pubnub_dns_codec, handles_response_RecordType_and_DataLength_mismatch) { /* Resolved IpvX address */ uint8_t data[] = {255,255,0,0,0}; - uint8_t data2[] = {255,255,0,0}; + uint8_t data_2[] = {255,255,0,0}; struct pubnub_ipv4_address resolved_addr_ipv4; make_dns_header_M(RESPONSE, 1, 2); append_question_M(encoded_abc_domain_name); - append_answer_M(encoded_piece3, RecordTypeA, data); - append_answer_M(encoded_piece3, RecordTypeA, data2); + append_answer_M(encoded_piece3, RecordTypeA, data, 47); + append_answer_M(encoded_piece3, RecordTypeA, data_2, 123); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, &resolved_addr_ipv4 IPV6_NULL_ARGUMENT PBDNS_OPTIONAL_PARAMS_BP), equals(0)); +#if PUBNUB_USE_MULTIPLE_ADDRESSES + attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, + data_2, + sizeof resolved_addr_ipv4.ipv4), + equals(0)); + attest(bp.spare_addresses.ttl_ipv4[0], equals(123)); + attest(bp.spare_addresses.n_ipv4, equals(1)); + attest(bp.spare_addresses.ipv4_index, equals(0)); +#if PUBNUB_USE_IPV6 + attest(bp.spare_addresses.n_ipv6, equals(0)); + attest(bp.spare_addresses.ipv6_index, equals(0)); +#endif +#endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ } Ensure(pubnub_dns_codec, makes_valid_DNS_query_request) @@ -935,12 +943,12 @@ Ensure(pubnub_dns_codec, handles_response_RecordType_and_DataLength_mismatch_on_ { /* Resolved IpvX address */ uint8_t data[] = {255,255,0,0,0}; - uint8_t data2[] = {0xAB,0xCD,0x02,0x55,0,0,0,0,0x32}; + uint8_t data_2[] = {0xAB,0xCD,0x02,0x55,0,0,0,0,0x32}; struct pubnub_ipv6_address resolved_addr_ipv6; make_dns_header_M(RESPONSE, 1, 2); append_question_M(encoded_abc_domain_name); - append_answer_M(encoded_piece3, RecordTypeAAAA, data2); - append_answer_M(encoded_piece3, RecordTypeA, data); + append_answer_M(encoded_piece3, RecordTypeAAAA, data_2, 7); + append_answer_M(encoded_piece3, RecordTypeA, data, 54); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, NULL, @@ -970,9 +978,9 @@ Ensure(pubnub_dns_codec, handles_response_RecordTypeAAAA_and_RecordTypeA) make_dns_header_M(RESPONSE, 1, 3); append_question_M(encoded_abc_domain_name); - append_answer_M(encoded_piece3, RecordTypeAAAA, data_2); - append_answer_M(encoded_piece3, RecordTypeAAAA, data_3); - append_answer_M(encoded_piece3, RecordTypeA, data); + append_answer_M(encoded_piece3, RecordTypeAAAA, data_2, 8); + append_answer_M(encoded_piece3, RecordTypeAAAA, data_3, 14); + append_answer_M(encoded_piece3, RecordTypeA, data, 58); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, &resolved_addr_ipv4, @@ -982,27 +990,22 @@ Ensure(pubnub_dns_codec, handles_response_RecordTypeAAAA_and_RecordTypeA) attest(memcmp(&resolved_addr_ipv6, &key_addr, sizeof resolved_addr_ipv6), equals(0)); attest(memcmp(&resolved_addr_ipv4.ipv4, data_zeros, sizeof resolved_addr_ipv4.ipv4), equals(0)); #if PUBNUB_USE_MULTIPLE_ADDRESSES -#if PUBNUB_USE_SSL attest(memcmp(bp.spare_addresses.ipv6_addresses[0].ipv6, data_2, sizeof resolved_addr_ipv6.ipv6), equals(0)); + attest(bp.spare_addresses.ttl_ipv6[0], equals(8)); attest(memcmp(bp.spare_addresses.ipv6_addresses[1].ipv6, data_3, sizeof resolved_addr_ipv6.ipv6), equals(0)); + attest(bp.spare_addresses.ttl_ipv6[1], equals(14)); attest(bp.spare_addresses.n_ipv6, equals(2)); -#else - attest(memcmp(bp.spare_addresses.ipv6_addresses[0].ipv6, - data_3, - sizeof resolved_addr_ipv6.ipv6), - equals(0)); - attest(bp.spare_addresses.n_ipv6, equals(1)); -#endif /* PUBNUB_USE_SSL */ attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, data, sizeof bp.spare_addresses.ipv4_addresses[0].ipv4), equals(0)); + attest(bp.spare_addresses.ttl_ipv4[0], equals(58)); attest(bp.spare_addresses.n_ipv4, equals(1)); attest(bp.spare_addresses.ipv4_index, equals(0)); attest(bp.spare_addresses.ipv6_index, equals(0)); @@ -1027,12 +1030,15 @@ Ensure(pubnub_dns_codec, handles_response_with_RecordTypeAAAA_no_ssl_fallback) bp.options.fallbackSSL = false; #endif - make_dns_header_M(RESPONSE, 1, 4); + make_dns_header_M(RESPONSE, 1, 5); append_question_M(encoded_abc_domain_name); - append_answer_M(encoded_piece3, RecordTypeAAAA, data_1); - append_answer_M(encoded_piece3, RecordTypeA, data); - append_answer_M(encoded_piece3, RecordTypeAAAA, data_2); - append_answer_M(encoded_piece3, RecordTypeAAAA, data_3); + append_answer_M(encoded_piece3, RecordTypeAAAA, data_1, 10); + append_answer_M(encoded_piece3, RecordTypeA, data, 25); + /* Address with time to live 0 wan't be 'cashed' */ + append_answer_M(encoded_piece3, RecordTypeAAAA, data_2, 0); + /* Time to live out of range */ + append_answer_M(encoded_piece3, RecordTypeAAAA, data_3, 65536); + append_answer_M(encoded_piece3, RecordTypeAAAA, data_2, 30); attest(pbdns_pick_resolved_addresses(m_buf, m_msg_size, &resolved_addr_ipv4, @@ -1042,32 +1048,28 @@ Ensure(pubnub_dns_codec, handles_response_with_RecordTypeAAAA_no_ssl_fallback) attest(memcmp(&resolved_addr_ipv4.ipv4, data_zeros, sizeof resolved_addr_ipv4), equals(0)); attest(memcmp(&resolved_addr_ipv6, &key_addr, sizeof resolved_addr_ipv6), equals(0)); #if PUBNUB_USE_MULTIPLE_ADDRESSES -#if PUBNUB_USE_SSL attest(memcmp(bp.spare_addresses.ipv6_addresses[0].ipv6, - data_2, + data_1, sizeof bp.spare_addresses.ipv6_addresses[0].ipv6), equals(0)); + attest(bp.spare_addresses.ttl_ipv6[0], equals(10)); attest(memcmp(bp.spare_addresses.ipv6_addresses[1].ipv6, data_3, sizeof bp.spare_addresses.ipv6_addresses[0].ipv6), equals(0)); + attest(bp.spare_addresses.ttl_ipv6[1], equals(0xFFFF)); attest(bp.spare_addresses.n_ipv6, equals(2)); -#else - attest(memcmp(bp.spare_addresses.ipv6_addresses[0].ipv6, - data_2, - sizeof bp.spare_addresses.ipv6_addresses[0].ipv6), - equals(0)); - attest(bp.spare_addresses.n_ipv6, equals(1)); -#endif /* PUBNUB_USE_SSL */ attest(bp.spare_addresses.ipv6_index, equals(0)); attest(memcmp(bp.spare_addresses.ipv4_addresses[0].ipv4, data, sizeof bp.spare_addresses.ipv4_addresses[0].ipv4), equals(0)); + attest(bp.spare_addresses.ttl_ipv4[0], equals(25)); attest(bp.spare_addresses.n_ipv4, equals(1)); attest(bp.spare_addresses.ipv4_index, equals(0)); #endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ } + #endif /* PUBNUB_USE_IPV6 */ diff --git a/lib/sockets/pbpal_adns_sockets.c b/lib/sockets/pbpal_adns_sockets.c index 740f4344..1994a26b 100644 --- a/lib/sockets/pbpal_adns_sockets.c +++ b/lib/sockets/pbpal_adns_sockets.c @@ -14,6 +14,9 @@ #endif #include +#if PUBNUB_USE_MULTIPLE_ADDRESSES +#include +#endif #define DNS_PORT 53 @@ -124,6 +127,9 @@ int read_dns_response(pb_socket_t skt, if (msg_size <= 0) { return socket_would_block() ? +1 : -1; } +#if PUBNUB_USE_MULTIPLE_ADDRESSES + time(&spare_addresses->time_of_the_last_dns_query); +#endif if (pbdns_pick_resolved_addresses(buf, (size_t)msg_size, &addr_ipv4 @@ -155,24 +161,6 @@ int read_dns_response(pb_socket_t skt, #include #endif -#if PUBNUB_USE_MULTIPLE_ADDRESSES -#define PBDNS_OPTIONAL_PARAMS_PBP , &pbp->spare_addresses, &pbp->options - -static void multiple_addresses_reset_counters(struct pubnub_multi_addresses* spare_addresses) -{ - spare_addresses->n_ipv4 = 0; - spare_addresses->ipv4_index = 0; -#if PUBNUB_USE_IPV6 - spare_addresses->n_ipv6 = 0; - spare_addresses->ipv6_index = 0; -#endif -} - -#else -#define PBDNS_OPTIONAL_PARAMS_PBP -#endif - - /* When running this test example PUBNUB_USE_MULTIPLE_ADDRESSES should be defined and set to zero in the corresponding make file */ @@ -180,15 +168,7 @@ int main() { struct sockaddr_in dest; struct sockaddr_in6 dest6; - struct sockaddr* resolved_addr; - pubnub_t* pbp = pubnub_alloc(); - if (NULL == pbp) { - printf("Failed to allocate Pubnub context!\n"); - return -1; - } -#if PUBNUB_USE_SSL - pbp->options.fallbackSSL = false; -#endif + struct sockaddr_storage resolved_addr; #if defined(_WIN32) WSADATA wsaData; @@ -241,13 +221,7 @@ int main() timev.tv_sec, timev.tv_usec); #endif -#if PUBNUB_USE_MULTIPLE_ADDRESSES - multiple_addresses_reset_counters(&pbp->spare_addresses) -#endif - read_dns_response(skt, - (struct sockaddr*)&dest, - &resolved_addr - PBDNS_OPTIONAL_PARAMS_PBP); + read_dns_response(skt, (struct sockaddr*)&dest, (struct sockaddr*)&resolved_addr); #if !defined(_WIN32) } else { @@ -294,13 +268,7 @@ int main() timev.tv_sec, timev.tv_usec); #endif -#if PUBNUB_USE_MULTIPLE_ADDRESSES - multiple_addresses_reset_counters(&pbp->spare_addresses) -#endif - read_dns_response(skt, - (struct sockaddr*)&dest6, - &resolved_addr - PBDNS_OPTIONAL_PARAMS_PBP); + read_dns_response(skt, (struct sockaddr*)&dest6, (struct sockaddr*)&resolved_addr); #if !defined(_WIN32) } else { diff --git a/lib/sockets/pbpal_resolv_and_connect_sockets.c b/lib/sockets/pbpal_resolv_and_connect_sockets.c index 89c4a903..02edd871 100644 --- a/lib/sockets/pbpal_resolv_and_connect_sockets.c +++ b/lib/sockets/pbpal_resolv_and_connect_sockets.c @@ -1,7 +1,7 @@ /* -*- c-file-style:"stroustrup"; indent-tabs-mode: nil -*- */ -#include "core/pbpal.h" - #include "pubnub_internal.h" + +#include "core/pbpal.h" #include "core/pubnub_assert.h" #include "core/pubnub_log.h" #include "lib/sockets/pbpal_adns_sockets.h" @@ -21,8 +21,8 @@ #define TLS_PORT 443 #ifndef PUBNUB_CALLBACK_API -#define send_dns_query(x,y,z,v) -1 -#define read_response(x,y,z,v) -1 +#define send_dns_query(x, y, z, v) -1 +#define read_response(x, y, z, v) -1 #else #if PUBNUB_USE_IPV6 typedef struct sockaddr_storage sockaddr_inX_t; @@ -34,7 +34,9 @@ typedef struct sockaddr_in sockaddr_inX_t; #endif /* PUBNUB_CALLBACK_API */ -static void prepare_port_and_hostname(pubnub_t *pb, uint16_t* p_port, char const** p_origin) +static void prepare_port_and_hostname(pubnub_t* pb, + uint16_t* p_port, + char const** p_origin) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); PUBNUB_ASSERT_OPT((pb->state == PBS_READY) || (pb->state == PBS_WAIT_DNS_SEND)); @@ -55,7 +57,7 @@ static void prepare_port_and_hostname(pubnub_t *pb, uint16_t* p_port, char const break; case pbproxyHTTP_GET: *p_origin = pb->proxy_hostname; - *p_port = pb->proxy_port; + *p_port = pb->proxy_port; PUBNUB_LOG_TRACE("Using proxy: %s : %hu\n", *p_origin, *p_port); break; default: @@ -65,6 +67,7 @@ static void prepare_port_and_hostname(pubnub_t *pb, uint16_t* p_port, char const return; } + #ifdef PUBNUB_CALLBACK_API #if PUBNUB_SET_DNS_SERVERS #if PUBNUB_CHANGE_DNS_SERVERS @@ -74,32 +77,31 @@ static void get_dns_ip(struct pbdns_servers_check* dns_check, struct sockaddr* a #if PUBNUB_USE_IPV6 void* pv6 = ((struct sockaddr_in6*)addr)->sin6_addr.s6_addr; #endif - addr->sa_family = AF_INET; + addr->sa_family = AF_INET; dns_check->dns_mask = 1; if ((pubnub_get_dns_primary_server_ipv4((struct pubnub_ipv4_address*)p) == -1) - || (dns_check->dns_server_check & dns_check->dns_mask) - ) { + || (dns_check->dns_server_check & dns_check->dns_mask)) { dns_check->dns_mask <<= 1; - if ((pubnub_get_dns_secondary_server_ipv4((struct pubnub_ipv4_address*)p) == -1) - || (dns_check->dns_server_check & dns_check->dns_mask) - ) { + if ((pubnub_get_dns_secondary_server_ipv4((struct pubnub_ipv4_address*)p) + == -1) + || (dns_check->dns_server_check & dns_check->dns_mask)) { dns_check->dns_mask <<= 1; #if PUBNUB_USE_IPV6 addr->sa_family = AF_INET6; -#else +#else inet_pton(AF_INET, PUBNUB_DEFAULT_DNS_SERVER, p); #endif /* PUBNUB_USE_IPV6 */ } } #if PUBNUB_USE_IPV6 if (AF_INET6 == addr->sa_family) { - if ((pubnub_get_dns_primary_server_ipv6((struct pubnub_ipv6_address*)pv6) == -1) - || (dns_check->dns_server_check & dns_check->dns_mask) - ) { + if ((pubnub_get_dns_primary_server_ipv6((struct pubnub_ipv6_address*)pv6) + == -1) + || (dns_check->dns_server_check & dns_check->dns_mask)) { dns_check->dns_mask <<= 1; - if ((pubnub_get_dns_secondary_server_ipv6((struct pubnub_ipv6_address*)pv6) == -1) - || (dns_check->dns_server_check & dns_check->dns_mask) - ) { + if ((pubnub_get_dns_secondary_server_ipv6((struct pubnub_ipv6_address*)pv6) + == -1) + || (dns_check->dns_server_check & dns_check->dns_mask)) { dns_check->dns_mask <<= 1; addr->sa_family = AF_INET; inet_pton(AF_INET, PUBNUB_DEFAULT_DNS_SERVER, p); @@ -111,24 +113,25 @@ static void get_dns_ip(struct pbdns_servers_check* dns_check, struct sockaddr* a #else static void get_dns_ip(struct sockaddr* addr) { - void* p = &(((struct sockaddr_in*)addr)->sin_addr.s_addr); + void* p = &(((struct sockaddr_in*)addr)->sin_addr.s_addr); #if PUBNUB_USE_IPV6 - void* pv6 = ((struct sockaddr_in6*)addr)->sin6_addr.s6_addr; + void* pv6 = ((struct sockaddr_in6*)addr)->sin6_addr.s6_addr; #endif addr->sa_family = AF_INET; if ((pubnub_get_dns_primary_server_ipv4((struct pubnub_ipv4_address*)p) == -1) - && (pubnub_get_dns_secondary_server_ipv4((struct pubnub_ipv4_address*)p) == -1) - ) { + && (pubnub_get_dns_secondary_server_ipv4((struct pubnub_ipv4_address*)p) + == -1)) { #if PUBNUB_USE_IPV6 addr->sa_family = AF_INET6; -#else +#else inet_pton(AF_INET, PUBNUB_DEFAULT_DNS_SERVER, p); #endif /* PUBNUB_USE_IPV6 */ } if (AF_INET6 == addr->sa_family) { - if ((pubnub_get_dns_primary_server_ipv6((struct pubnub_ipv6_address*)pv6) == -1) - && (pubnub_get_dns_secondary_server_ipv6((struct pubnub_ipv6_address*)pv6) == -1) - ) { + if ((pubnub_get_dns_primary_server_ipv6((struct pubnub_ipv6_address*)pv6) + == -1) + && (pubnub_get_dns_secondary_server_ipv6((struct pubnub_ipv6_address*)pv6) + == -1)) { addr->sa_family = AF_INET; inet_pton(AF_INET, PUBNUB_DEFAULT_DNS_SERVER, p); } @@ -139,38 +142,43 @@ static void get_dns_ip(struct sockaddr* addr) static void get_dns_ip(struct sockaddr* addr) { addr->sa_family = AF_INET; - inet_pton(AF_INET, PUBNUB_DEFAULT_DNS_SERVER, &(((struct sockaddr_in*)addr)->sin_addr.s_addr)); + inet_pton(AF_INET, + PUBNUB_DEFAULT_DNS_SERVER, + &(((struct sockaddr_in*)addr)->sin_addr.s_addr)); } #endif /* PUBNUB_SET_DNS_SERVERS */ -static enum pbpal_resolv_n_connect_result connect_TCP_socket(pb_socket_t* skt, - struct pubnub_options* options, - struct sockaddr *dest, - const uint16_t port) + +static enum pbpal_resolv_n_connect_result +connect_TCP_socket(pb_socket_t* skt, + struct pubnub_options* options, + struct sockaddr* dest, + const uint16_t port) { size_t sockaddr_size; PUBNUB_ASSERT_OPT(dest != NULL); switch (dest->sa_family) { - case AF_INET: - sockaddr_size = sizeof(struct sockaddr_in); + case AF_INET: + sockaddr_size = sizeof(struct sockaddr_in); ((struct sockaddr_in*)dest)->sin_port = htons(port); break; #if PUBNUB_USE_IPV6 case AF_INET6: - sockaddr_size = sizeof(struct sockaddr_in6); + sockaddr_size = sizeof(struct sockaddr_in6); ((struct sockaddr_in6*)dest)->sin6_port = htons(port); break; #endif default: - PUBNUB_LOG_ERROR("connect_TCP_socket(socket=%d): invalid internet protokol " - "dest->sa_family =%uh\n", - *skt, - dest->sa_family); + PUBNUB_LOG_ERROR( + "connect_TCP_socket(socket=%ld): invalid internet protokol " + "dest->sa_family =%uh\n", + (long)*skt, + dest->sa_family); return pbpal_connect_failed; } - *skt = socket(dest->sa_family, SOCK_STREAM, IPPROTO_TCP); + *skt = socket(dest->sa_family, SOCK_STREAM, IPPROTO_TCP); if (SOCKET_INVALID == *skt) { return pbpal_connect_resource_failure; } @@ -178,15 +186,28 @@ static enum pbpal_resolv_n_connect_result connect_TCP_socket(pb_socket_t* skt, pbpal_set_socket_blocking_io(*skt, options->use_blocking_io); socket_disable_SIGPIPE(*skt); if (SOCKET_ERROR == connect(*skt, dest, sockaddr_size)) { - return socket_would_block() ? pbpal_connect_wouldblock : pbpal_connect_failed; + return socket_would_block() ? pbpal_connect_wouldblock + : pbpal_connect_failed; } return pbpal_connect_success; } + +#if PUBNUB_ADNS_RETRY_AFTER_CLOSE +static void if_no_retry_close_socket(pb_socket_t* skt, struct pubnub_flags* flags) +{ + if (!flags->retry_after_close && (*skt != SOCKET_INVALID)) { + socket_close(*skt); + *skt = SOCKET_INVALID; + } +} +#endif /* PUBNUB_ADNS_RETRY_AFTER_CLOSE */ + + #if PUBNUB_CHANGE_DNS_SERVERS static void check_dns_server_error(struct pbdns_servers_check* dns_check, - struct pubnub_flags* flags) -{ + struct pubnub_flags* flags) +{ dns_check->dns_server_check |= dns_check->dns_mask; if (dns_check->dns_mask < PUBNUB_MAX_DNS_SERVERS_MASK) { flags->retry_after_close = true; @@ -195,114 +216,147 @@ static void check_dns_server_error(struct pbdns_servers_check* dns_check, #endif /* PUBNUB_CHANGE_DNS_SERVERS */ #if PUBNUB_USE_MULTIPLE_ADDRESSES -static enum pbpal_resolv_n_connect_result try_TCP_connect_spare_address( - pb_socket_t* skt, - struct pubnub_multi_addresses* spare_addresses, - struct pubnub_options* options, - struct pubnub_flags* flags, - const uint16_t port) +void pbpal_multiple_addresses_reset_counters(struct pubnub_multi_addresses* spare_addresses) +{ + spare_addresses->n_ipv4 = 0; + spare_addresses->ipv4_index = 0; +#if PUBNUB_USE_IPV6 + spare_addresses->n_ipv6 = 0; + spare_addresses->ipv6_index = 0; +#endif +} + + +static enum pbpal_resolv_n_connect_result +try_TCP_connect_spare_address(pb_socket_t* skt, + struct pubnub_multi_addresses* spare_addresses, + struct pubnub_options* options, + struct pubnub_flags* flags, + const uint16_t port) { + enum pbpal_resolv_n_connect_result rslt = pbpal_resolv_resource_failure; + if (spare_addresses->ipv4_index < spare_addresses->n_ipv4) { - struct sockaddr_in dest = {0}; - memcpy(&(dest.sin_addr.s_addr), - spare_addresses->ipv4_addresses[spare_addresses->ipv4_index].ipv4, - sizeof dest.sin_addr.s_addr); + /* Need at least a second to live */ + if (spare_addresses->ttl_ipv4[spare_addresses->ipv4_index] - 2 + > time(NULL) - spare_addresses->time_of_the_last_dns_query) { + struct sockaddr_in dest = { 0 }; + memcpy(&(dest.sin_addr.s_addr), + spare_addresses->ipv4_addresses[spare_addresses->ipv4_index].ipv4, + sizeof dest.sin_addr.s_addr); + dest.sin_family = AF_INET; + rslt = connect_TCP_socket(skt, options, (struct sockaddr*)&dest, port); + } + else { + rslt = pbpal_connect_failed; + } + if (pbpal_connect_failed == rslt) { + flags->retry_after_close = + (++spare_addresses->ipv4_index < spare_addresses->n_ipv4); + if_no_retry_close_socket(skt, flags); #if PUBNUB_USE_SSL - if (!options->fallbackSSL || !flags->trySSL) + flags->trySSL = options->useSSL; #endif - { - spare_addresses->ipv4_index++; } - flags->retry_after_close = true; - dest.sin_family = AF_INET; - return connect_TCP_socket(skt, options, (struct sockaddr*)&dest, port); } #if PUBNUB_USE_IPV6 else if (spare_addresses->ipv6_index < spare_addresses->n_ipv6) { - struct sockaddr_in6 dest = {0}; - memcpy(dest.sin6_addr.s6_addr, - spare_addresses->ipv6_addresses[spare_addresses->ipv6_index].ipv6, - sizeof dest.sin6_addr.s6_addr); + /* Need at least a second to live */ + if (spare_addresses->ttl_ipv6[spare_addresses->ipv6_index] - 2 + > time(NULL) - spare_addresses->time_of_the_last_dns_query) { + struct sockaddr_in6 dest = { 0 }; + memcpy(dest.sin6_addr.s6_addr, + spare_addresses->ipv6_addresses[spare_addresses->ipv6_index].ipv6, + sizeof dest.sin6_addr.s6_addr); + dest.sin6_family = AF_INET6; + rslt = connect_TCP_socket(skt, options, (struct sockaddr*)&dest, port); + } + else { + rslt = pbpal_connect_failed; + } + if (pbpal_connect_failed == rslt) { + flags->retry_after_close = + (++spare_addresses->ipv6_index < spare_addresses->n_ipv6); + if_no_retry_close_socket(skt, flags); #if PUBNUB_USE_SSL - if (!options->fallbackSSL || !flags->trySSL) + flags->trySSL = options->useSSL; #endif - { - spare_addresses->ipv6_index++; } - flags->retry_after_close = true; - dest.sin6_family = AF_INET6; - return connect_TCP_socket(skt, options, (struct sockaddr*)&dest, port); - } - else if (spare_addresses->n_ipv6 > 0) { - return pbpal_connect_failed; } #endif /* PUBNUB_USE_IPV6 */ - else if (spare_addresses->n_ipv4 > 0) { - return pbpal_connect_failed; + else { + pbpal_multiple_addresses_reset_counters(spare_addresses); } - return pbpal_resolv_resource_failure; + return rslt; } #endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ #endif /* PUBNUB_CALLBACK_API */ -enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb) +enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t* pb) { - int error; - uint16_t port = HTTP_PORT; + int error; + uint16_t port = HTTP_PORT; char const* origin; #ifdef PUBNUB_CALLBACK_API - sockaddr_inX_t dest = {0}; + sockaddr_inX_t dest = { 0 }; prepare_port_and_hostname(pb, &port, &origin); #if PUBNUB_PROXY_API if (0 != pb->proxy_ipv4_address.ipv4[0]) { - struct sockaddr_in dest = {0}; - memcpy(&(dest.sin_addr.s_addr), pb->proxy_ipv4_address.ipv4, sizeof dest.sin_addr.s_addr); + struct sockaddr_in dest = { 0 }; + memcpy(&(dest.sin_addr.s_addr), + pb->proxy_ipv4_address.ipv4, + sizeof dest.sin_addr.s_addr); dest.sin_family = AF_INET; - return connect_TCP_socket(&pb->pal.socket, &pb->options, (struct sockaddr*)&dest, port); + return connect_TCP_socket( + &pb->pal.socket, &pb->options, (struct sockaddr*)&dest, port); } #if PUBNUB_USE_IPV6 - else if ((0 != pb->proxy_ipv6_address.ipv6[0]) || (0 != pb->proxy_ipv6_address.ipv6[1])) { - struct sockaddr_in6 dest = {0}; - memcpy(dest.sin6_addr.s6_addr, pb->proxy_ipv6_address.ipv6, sizeof dest.sin6_addr.s6_addr); + else if ((0 != pb->proxy_ipv6_address.ipv6[0]) + || (0 != pb->proxy_ipv6_address.ipv6[1])) { + struct sockaddr_in6 dest = { 0 }; + memcpy(dest.sin6_addr.s6_addr, + pb->proxy_ipv6_address.ipv6, + sizeof dest.sin6_addr.s6_addr); dest.sin6_family = AF_INET6; - return connect_TCP_socket(&pb->pal.socket, &pb->options, (struct sockaddr*)&dest, port); + return connect_TCP_socket( + &pb->pal.socket, &pb->options, (struct sockaddr*)&dest, port); } #endif /* PUBNUB_USE_IPV6 */ #endif /* PUBNUB_PROXY_API */ #if PUBNUB_USE_MULTIPLE_ADDRESSES { enum pbpal_resolv_n_connect_result rslt; - rslt = try_TCP_connect_spare_address(&pb->pal.socket, - &pb->spare_addresses, - &pb->options, - &pb->flags, - port); + rslt = try_TCP_connect_spare_address( + &pb->pal.socket, &pb->spare_addresses, &pb->options, &pb->flags, port); if (rslt != pbpal_resolv_resource_failure) { return rslt; } } -#endif +#endif #if PUBNUB_CHANGE_DNS_SERVERS get_dns_ip(&pb->dns_check, (struct sockaddr*)&dest); #else get_dns_ip((struct sockaddr*)&dest); #endif if (SOCKET_INVALID == pb->pal.socket) { - pb->pal.socket = socket(((struct sockaddr*)&dest)->sa_family, SOCK_DGRAM, IPPROTO_UDP); + pb->pal.socket = + socket(((struct sockaddr*)&dest)->sa_family, 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); - error = send_dns_query(pb->pal.socket, (struct sockaddr*)&dest, origin, QUERY_TYPE); + error = + send_dns_query(pb->pal.socket, (struct sockaddr*)&dest, origin, QUERY_TYPE); if (error < 0) { #if PUBNUB_CHANGE_DNS_SERVERS check_dns_server_error(&pb->dns_check, &pb->flags); + if_no_retry_close_socket(&pb->pal.socket, &pb->flags); #endif return pbpal_resolv_failed_send; } @@ -313,17 +367,17 @@ enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb) return pbpal_resolv_sent; #else - char port_string[20]; - struct addrinfo *result; - struct addrinfo *it; - struct addrinfo hint; + 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_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; + 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); @@ -344,7 +398,8 @@ enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb) break; } else { - PUBNUB_LOG_WARNING("socket connect() failed, will try another IP address, if available\n"); + 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; @@ -371,13 +426,14 @@ enum pbpal_resolv_n_connect_result pbpal_resolv_and_connect(pubnub_t *pb) #define PBDNS_OPTIONAL_PARAMS_PB #endif -enum pbpal_resolv_n_connect_result pbpal_check_resolv_and_connect(pubnub_t *pb) +enum pbpal_resolv_n_connect_result pbpal_check_resolv_and_connect(pubnub_t* pb) { #ifdef PUBNUB_CALLBACK_API - sockaddr_inX_t dns_server = {0}; - sockaddr_inX_t dest = {0}; - uint16_t port = HTTP_PORT; + sockaddr_inX_t dns_server = { 0 }; + sockaddr_inX_t dest = { 0 }; + uint16_t port = HTTP_PORT; + enum pbpal_resolv_n_connect_result rslt; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); PUBNUB_ASSERT_OPT(pb->state == PBS_WAIT_DNS_RCV); @@ -399,13 +455,12 @@ enum pbpal_resolv_n_connect_result pbpal_check_resolv_and_connect(pubnub_t *pb) #endif switch (read_dns_response(pb->pal.socket, (struct sockaddr*)&dns_server, - (struct sockaddr*)&dest - PBDNS_OPTIONAL_PARAMS_PB)) { + (struct sockaddr*)&dest PBDNS_OPTIONAL_PARAMS_PB)) { case -1: #if PUBNUB_CHANGE_DNS_SERVERS check_dns_server_error(&pb->dns_check, &pb->flags); #endif - return pbpal_resolv_failed_rcv; + return pbpal_resolv_failed_rcv; case +1: return pbpal_resolv_rcv_wouldblock; case 0: @@ -413,8 +468,27 @@ enum pbpal_resolv_n_connect_result pbpal_check_resolv_and_connect(pubnub_t *pb) } socket_close(pb->pal.socket); - return connect_TCP_socket(&pb->pal.socket, &pb->options, (struct sockaddr*)&dest, port); -#else + rslt = connect_TCP_socket( + &pb->pal.socket, &pb->options, (struct sockaddr*)&dest, port); +#if PUBNUB_USE_MULTIPLE_ADDRESSES + if (pbpal_connect_failed == rslt) { + if (AF_INET == ((struct sockaddr*)&dest)->sa_family) { + pb->flags.retry_after_close = + (++pb->spare_addresses.ipv4_index < pb->spare_addresses.n_ipv4); + } +#if PUBNUB_USE_IPV6 + else if (AF_INET6 == ((struct sockaddr*)&dest)->sa_family) { + pb->flags.retry_after_close = + (++pb->spare_addresses.ipv6_index < pb->spare_addresses.n_ipv6); + } +#endif +#if PUBNUB_USE_SSL + pb->flags.trySSL = pb->options.useSSL; +#endif + } +#endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ + return rslt; +#else /* PUBNUB_CALLBACK_API */ PUBNUB_UNUSED(pb); @@ -426,10 +500,10 @@ enum pbpal_resolv_n_connect_result pbpal_check_resolv_and_connect(pubnub_t *pb) } -enum pbpal_resolv_n_connect_result pbpal_check_connect(pubnub_t *pb) +enum pbpal_resolv_n_connect_result pbpal_check_connect(pubnub_t* pb) { - fd_set write_set; - int rslt; + fd_set write_set; + int rslt; struct timeval timev = { 0, 300000 }; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); diff --git a/lib/sockets/pbpal_sockets.c b/lib/sockets/pbpal_sockets.c index 5dbf73dc..41393fa2 100644 --- a/lib/sockets/pbpal_sockets.c +++ b/lib/sockets/pbpal_sockets.c @@ -1,9 +1,9 @@ /* -*- c-file-style:"stroustrup"; indent-tabs-mode: nil -*- */ -#include "core/pbpal.h" +#include "pubnub_internal.h" +#include "core/pbpal.h" #include "core/pubnub_ntf_sync.h" #include "core/pubnub_netcore.h" -#include "pubnub_internal.h" #include "core/pubnub_assert.h" #include "core/pubnub_log.h" @@ -40,6 +40,9 @@ void pbpal_init(pubnub_t* pb) pb->pal.socket = SOCKET_INVALID; pb->sock_state = STATE_NONE; buf_setup(pb); +#if PUBNUB_USE_MULTIPLE_ADDRESSES + pbpal_multiple_addresses_reset_counters(&pb->spare_addresses); +#endif } diff --git a/openssl/posix.mk b/openssl/posix.mk index 9729abec..3af1b482 100644 --- a/openssl/posix.mk +++ b/openssl/posix.mk @@ -1,6 +1,6 @@ -SOURCEFILES = ../core/pubnub_ssl.c ../core/pubnub_pubsubapi.c ../core/pubnub_coreapi.c ../core/pubnub_ccore_pubsub.c ../core/pubnub_ccore.c ../core/pubnub_netcore.c ../lib/sockets/pbpal_resolv_and_connect_sockets.c pbpal_openssl.c pbpal_connect_openssl.c pbpal_add_system_certs_posix.c ../core/pubnub_alloc_std.c ../core/pubnub_assert_std.c ../core/pubnub_generate_uuid.c ../core/pubnub_blocking_io.c ../posix/posix_socket_blocking_io.c ../core/pubnub_timers.c ../core/pubnub_json_parse.c ../core/pubnub_helper.c pubnub_version_openssl.c ../posix/pubnub_generate_uuid_posix.c pbpal_openssl_blocking_io.c ../lib/base64/pbbase64.c ../core/pubnub_crypto.c ../core/pubnub_coreapi_ex.c ../core/pubnub_free_with_timeout_std.c pbaes256.c ../posix/msstopwatch_monotonic_clock.c ../core/pubnub_url_encode.c +SOURCEFILES = ../core/pubnub_ssl.c ../core/pubnub_pubsubapi.c ../core/pubnub_coreapi.c ../core/pubnub_ccore_pubsub.c ../core/pubnub_ccore.c ../core/pubnub_netcore.c ../lib/sockets/pbpal_resolv_and_connect_sockets.c pbpal_openssl.c pbpal_connect_openssl.c pbpal_add_system_certs_posix.c ../core/pubnub_alloc_std.c ../core/pubnub_assert_std.c ../core/pubnub_generate_uuid.c ../core/pubnub_blocking_io.c ../posix/posix_socket_blocking_io.c ../core/pubnub_timers.c ../core/pubnub_json_parse.c ../core/pubnub_helper.c ../posix/pubnub_version_posix.c ../posix/pubnub_generate_uuid_posix.c pbpal_openssl_blocking_io.c ../lib/base64/pbbase64.c ../core/pubnub_crypto.c ../core/pubnub_coreapi_ex.c ../core/pubnub_free_with_timeout_std.c pbaes256.c ../posix/msstopwatch_monotonic_clock.c ../core/pubnub_url_encode.c -OBJFILES = pubnub_ssl.o pubnub_pubsubapi.o pubnub_coreapi.o pubnub_ccore_pubsub.o pubnub_ccore.o pubnub_netcore.o pbpal_resolv_and_connect_sockets.o pbpal_openssl.o pbpal_connect_openssl.o pbpal_add_system_certs_posix.o pubnub_alloc_std.o pubnub_assert_std.o pubnub_generate_uuid.o pubnub_blocking_io.o posix_socket_blocking_io.o pubnub_timers.o pubnub_json_parse.o pubnub_helper.o pubnub_version_openssl.o pubnub_generate_uuid_posix.o pbpal_openssl_blocking_io.o pbbase64.o pubnub_crypto.o pubnub_coreapi_ex.o pubnub_free_with_timeout_std.o pbaes256.o msstopwatch_monotonic_clock.o pubnub_url_encode.o +OBJFILES = pubnub_ssl.o pubnub_pubsubapi.o pubnub_coreapi.o pubnub_ccore_pubsub.o pubnub_ccore.o pubnub_netcore.o pbpal_resolv_and_connect_sockets.o pbpal_openssl.o pbpal_connect_openssl.o pbpal_add_system_certs_posix.o pubnub_alloc_std.o pubnub_assert_std.o pubnub_generate_uuid.o pubnub_blocking_io.o posix_socket_blocking_io.o pubnub_timers.o pubnub_json_parse.o pubnub_helper.o pubnub_version_posix.o pubnub_generate_uuid_posix.o pbpal_openssl_blocking_io.o pbbase64.o pubnub_crypto.o pubnub_coreapi_ex.o pubnub_free_with_timeout_std.o pbaes256.o msstopwatch_monotonic_clock.o pubnub_url_encode.o ifndef ONLY_PUBSUB_API ONLY_PUBSUB_API = 0 diff --git a/openssl/windows.mk b/openssl/windows.mk index 6d784374..fe82b591 100644 --- a/openssl/windows.mk +++ b/openssl/windows.mk @@ -1,6 +1,6 @@ -SOURCEFILES = ..\core\pubnub_pubsubapi.c ..\core\pubnub_coreapi.c ..\core\pubnub_ccore_pubsub.c ..\core\pubnub_ccore.c ..\core\pubnub_netcore.c ..\lib\sockets\pbpal_resolv_and_connect_sockets.c pbpal_openssl.c pbpal_connect_openssl.c pbpal_add_system_certs_windows.c ..\core\pubnub_alloc_std.c ..\core\pubnub_assert_std.c ..\core\pubnub_generate_uuid.c ..\core\pubnub_blocking_io.c ..\windows\windows_socket_blocking_io.c ..\core\pubnub_free_with_timeout_std.c ..\core\pubnub_timers.c ..\core\pubnub_json_parse.c ..\lib\md5\md5.c ..\core\pubnub_ssl.c ..\core\pubnub_helper.c pubnub_version_openssl.c ..\windows\pubnub_generate_uuid_windows.c pbpal_openssl_blocking_io.c ..\lib\base64\pbbase64.c ..\core\pubnub_crypto.c ..\core\pubnub_coreapi_ex.c pbaes256.c ..\core\c99\snprintf.c ..\lib\miniz\miniz_tinfl.c ..\lib\miniz\miniz_tdef.c ..\lib\miniz\miniz.c ..\lib\pbcrc32.c ..\core\pbgzip_compress.c ..\core\pbgzip_decompress.c ..\core\pubnub_subscribe_v2.c ..\windows\msstopwatch_windows.c ..\core\pubnub_url_encode.c ..\core\pbcc_advanced_history.c ..\core\pubnub_advanced_history.c +SOURCEFILES = ..\core\pubnub_pubsubapi.c ..\core\pubnub_coreapi.c ..\core\pubnub_ccore_pubsub.c ..\core\pubnub_ccore.c ..\core\pubnub_netcore.c ..\lib\sockets\pbpal_resolv_and_connect_sockets.c pbpal_openssl.c pbpal_connect_openssl.c pbpal_add_system_certs_windows.c ..\core\pubnub_alloc_std.c ..\core\pubnub_assert_std.c ..\core\pubnub_generate_uuid.c ..\core\pubnub_blocking_io.c ..\windows\windows_socket_blocking_io.c ..\core\pubnub_free_with_timeout_std.c ..\core\pubnub_timers.c ..\core\pubnub_json_parse.c ..\lib\md5\md5.c ..\core\pubnub_ssl.c ..\core\pubnub_helper.c ..\windows\pubnub_version_windows.c ..\windows\pubnub_generate_uuid_windows.c pbpal_openssl_blocking_io.c ..\lib\base64\pbbase64.c ..\core\pubnub_crypto.c ..\core\pubnub_coreapi_ex.c pbaes256.c ..\core\c99\snprintf.c ..\lib\miniz\miniz_tinfl.c ..\lib\miniz\miniz_tdef.c ..\lib\miniz\miniz.c ..\lib\pbcrc32.c ..\core\pbgzip_compress.c ..\core\pbgzip_decompress.c ..\core\pubnub_subscribe_v2.c ..\windows\msstopwatch_windows.c ..\core\pubnub_url_encode.c ..\core\pbcc_advanced_history.c ..\core\pubnub_advanced_history.c -OBJFILES = pubnub_pubsubapi.obj pubnub_coreapi.obj pubnub_ccore_pubsub.obj pubnub_ccore.obj pubnub_netcore.obj pbpal_resolv_and_connect_sockets.obj pbpal_openssl.obj pbpal_connect_openssl.obj pbpal_add_system_certs_windows.obj pubnub_alloc_std.obj pubnub_assert_std.obj pubnub_generate_uuid.obj pubnub_blocking_io.obj pubnub_free_with_timeout_std.obj pubnub_timers.obj pubnub_json_parse.obj md5.obj pubnub_ssl.obj pubnub_helper.obj pubnub_version_openssl.obj pubnub_generate_uuid_windows.obj pbpal_openssl_blocking_io.obj windows_socket_blocking_io.obj pbbase64.obj pubnub_crypto.obj pubnub_coreapi_ex.obj pbaes256.obj snprintf.obj miniz_tinfl.obj miniz_tdef.obj miniz.obj pbcrc32.obj pbgzip_compress.obj pbgzip_decompress.obj pubnub_subscribe_v2.obj msstopwatch_windows.obj pubnub_url_encode.obj pbcc_advanced_history.obj pubnub_advanced_history.obj +OBJFILES = pubnub_pubsubapi.obj pubnub_coreapi.obj pubnub_ccore_pubsub.obj pubnub_ccore.obj pubnub_netcore.obj pbpal_resolv_and_connect_sockets.obj pbpal_openssl.obj pbpal_connect_openssl.obj pbpal_add_system_certs_windows.obj pubnub_alloc_std.obj pubnub_assert_std.obj pubnub_generate_uuid.obj pubnub_blocking_io.obj pubnub_free_with_timeout_std.obj pubnub_timers.obj pubnub_json_parse.obj md5.obj pubnub_ssl.obj pubnub_helper.obj pubnub_version_windows.obj pubnub_generate_uuid_windows.obj pbpal_openssl_blocking_io.obj windows_socket_blocking_io.obj pbbase64.obj pubnub_crypto.obj pubnub_coreapi_ex.obj pbaes256.obj snprintf.obj miniz_tinfl.obj miniz_tdef.obj miniz.obj pbcrc32.obj pbgzip_compress.obj pbgzip_decompress.obj pubnub_subscribe_v2.obj msstopwatch_windows.obj pubnub_url_encode.obj pbcc_advanced_history.obj pubnub_advanced_history.obj !ifndef OPENSSLPATH OPENSSLPATH=c:\OpenSSL-Win32 diff --git a/posix/pubnub_config.h b/posix/pubnub_config.h index b515214d..a1e70b4e 100644 --- a/posix/pubnub_config.h +++ b/posix/pubnub_config.h @@ -100,9 +100,9 @@ #define PUBNUB_USE_MULTIPLE_ADDRESSES 1 #if PUBNUB_USE_MULTIPLE_ADDRESSES -#define PUBNUB_MAX_IPV4_ADDRESSES 1 +#define PUBNUB_MAX_IPV4_ADDRESSES 2 #if PUBNUB_USE_IPV6 -#define PUBNUB_MAX_IPV6_ADDRESSES 1 +#define PUBNUB_MAX_IPV6_ADDRESSES 2 #endif #endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ diff --git a/posix/pubnub_version_posix.c b/posix/pubnub_version_posix.c index 1b4f38a1..447fa2cf 100644 --- a/posix/pubnub_version_posix.c +++ b/posix/pubnub_version_posix.c @@ -21,6 +21,12 @@ char const *pubnub_version(void) char const *pubnub_uname(void) { - return PUBNUB_SDK_NAME "%2F" PUBNUB_SDK_VERSION; + return PUBNUB_SDK_NAME "-PubNub-C-core%2F" PUBNUB_SDK_VERSION; +} + + +char const *pubnub_uagent(void) +{ + return PUBNUB_SDK_NAME "-PubNub-C-core/" PUBNUB_SDK_VERSION; } diff --git a/qt/pubnub_qt.cpp b/qt/pubnub_qt.cpp index 353a8161..b89e5283 100644 --- a/qt/pubnub_qt.cpp +++ b/qt/pubnub_qt.cpp @@ -1,6 +1,7 @@ /* -*- c-file-style:"stroustrup"; indent-tabs-mode: nil -*- */ extern "C" { +#include "core/pubnub_version_internal.h" #include "core/pubnub_ccore_pubsub.h" #include "core/pubnub_ccore.h" #include "core/pubnub_assert.h" @@ -60,6 +61,36 @@ pubnub_qt::~pubnub_qt() } +static QString GetOsName() + { + #if defined(Q_OS_ANDROID) + return QLatin1String("Android"); + #elif defined(Q_OS_BLACKBERRY) + return QLatin1String("Blackberry"); + #elif defined(Q_OS_IOS) + return QLatin1String("iOS"); + #elif defined(Q_OS_MACOS) + return QLatin1String("macOS"); + #elif defined(Q_OS_TVOS) + return QLatin1String("tvOS"); + #elif defined(Q_OS_WATCHOS) + return QLatin1String("watchOS"); + #elif defined(Q_OS_WINCE) + return QLatin1String("WindowsCE"); + #elif defined(Q_OS_WIN) + return QLatin1String("Windows"); + #elif defined(Q_OS_CYGWIN) + return QLatin1String("Cygwin"); + #elif defined(Q_OS_LINUX) + return QLatin1String("Linux"); + #elif defined(Q_OS_UNIX) + return QLatin1String("Unix"); + #else + return QLatin1String("UnknownOS"); + #endif + } + + pubnub_res pubnub_qt::startRequest(pubnub_res result, pubnub_trans transaction) { if (PNR_STARTED == result) { @@ -73,6 +104,12 @@ pubnub_res pubnub_qt::startRequest(pubnub_res result, pubnub_trans transaction) } d_transaction_timed_out = false; QNetworkRequest req(url); + QString user_agent(GetOsName() + + "-Qt" + + QT_VERSION_STR + + "-PubNub-core/" + + PUBNUB_SDK_VERSION); + req.setRawHeader("User-Agent", user_agent.toLatin1()); if (!d_use_http_keep_alive) { req.setRawHeader("Connection", "Close"); } diff --git a/windows/pubnub_config.h b/windows/pubnub_config.h index ba282d08..2fe860cd 100644 --- a/windows/pubnub_config.h +++ b/windows/pubnub_config.h @@ -101,9 +101,9 @@ #define PUBNUB_USE_MULTIPLE_ADDRESSES 1 #if PUBNUB_USE_MULTIPLE_ADDRESSES -#define PUBNUB_MAX_IPV4_ADDRESSES 1 +#define PUBNUB_MAX_IPV4_ADDRESSES 2 #if PUBNUB_USE_IPV6 -#define PUBNUB_MAX_IPV6_ADDRESSES 1 +#define PUBNUB_MAX_IPV6_ADDRESSES 2 #endif #endif /* PUBNUB_USE_MULTIPLE_ADDRESSES */ diff --git a/windows/pubnub_version_windows.c b/windows/pubnub_version_windows.c index 7c754640..12320d1b 100644 --- a/windows/pubnub_version_windows.c +++ b/windows/pubnub_version_windows.c @@ -21,6 +21,11 @@ char const *pubnub_version(void) char const *pubnub_uname(void) { - return PUBNUB_SDK_NAME "%2F" PUBNUB_SDK_VERSION; + return PUBNUB_SDK_NAME "-PubNub-C-core%2F" PUBNUB_SDK_VERSION; } + +char const *pubnub_uagent(void) +{ + return PUBNUB_SDK_NAME "-PubNub-C-core/" PUBNUB_SDK_VERSION; +} diff --git a/windows/windows-gcc.mk b/windows/windows-gcc.mk index e8dc4dc6..31636f4f 100644 --- a/windows/windows-gcc.mk +++ b/windows/windows-gcc.mk @@ -1,6 +1,22 @@ -SOURCEFILES = ../core/pubnub_pubsubapi.c ../core/pubnub_coreapi.c ../core/pubnub_ccore_pubsub.c ../core/pubnub_ccore.c ../core/pubnub_netcore.c ../lib/sockets/pbpal_sockets.c ../lib/sockets/pbpal_resolv_and_connect_sockets.c ../core/pubnub_alloc_std.c ../core/pubnub_assert_std.c ../core/pubnub_generate_uuid.c ../core/pubnub_blocking_io.c ../lib/base64/pbbase64.c ../core/pubnub_timers.c ../core/pubnub_json_parse.c ../core/pubnub_proxy.c ../core/pubnub_proxy_core.c ../core/pbhttp_digest.c ../lib/md5/md5.c ../core/pbntlm_core.c ../core/pbntlm_packer_sspi.c pubnub_set_proxy_from_system_windows.c ../core/pubnub_helper.c pubnub_version_windows.c pubnub_generate_uuid_windows.c pbpal_windows_blocking_io.c +SOURCEFILES = ../core/pubnub_pubsubapi.c ../core/pubnub_coreapi.c ../core/pubnub_coreapi_ex.c ../core/pubnub_ccore_pubsub.c ../core/pubnub_ccore.c ../core/pubnub_netcore.c ../lib/sockets/pbpal_sockets.c ../lib/sockets/pbpal_resolv_and_connect_sockets.c ../core/pubnub_alloc_std.c ../core/pubnub_assert_std.c ../core/pubnub_generate_uuid.c ../core/pubnub_blocking_io.c ../windows/windows_socket_blocking_io.c ../core/pubnub_free_with_timeout_std.c ../lib/base64/pbbase64.c ../core/pubnub_timers.c ../core/pubnub_json_parse.c ../lib/md5/md5.c ../core/pubnub_helper.c pubnub_version_windows.c pubnub_generate_uuid_windows.c pbpal_windows_blocking_io.c ../core/c99/snprintf.c ../lib/miniz/miniz_tinfl.c ../lib/miniz/miniz_tdef.c ../lib/miniz/miniz.c ../lib/pbcrc32.c ../core/pbgzip_compress.c ../core/pbgzip_decompress.c ../core/pubnub_subscribe_v2.c msstopwatch_windows.c ../core/pubnub_url_encode.c ../core/pbcc_advanced_history.c ../core/pubnub_advanced_history.c -OBJFILES = pubnub_pubsubapi.o pubnub_coreapi.o pubnub_ccore_pubsub.o pubnub_ccore.o pubnub_netcore.o pbpal_sockets.o pbpal_resolv_and_connect_sockets.o pubnub_alloc_std.o pubnub_assert_std.o pubnub_generate_uuid.o pubnub_blocking_io.o pbbase64.o pubnub_timers.o pubnub_json_parse.o pubnub_proxy.o pubnub_proxy_core.o pbhttp_digest.o md5.o pbntlm_core.o pbntlm_packer_sspi.o pubnub_set_proxy_from_system_windows.o pubnub_helper.o pubnub_version_windows.o pubnub_generate_uuid_windows.o pbpal_windows_blocking_io.o +OBJFILES = pubnub_pubsubapi.obj pubnub_coreapi.obj pubnub_coreapi_ex.obj pubnub_ccore_pubsub.obj pubnub_ccore.obj pubnub_netcore.obj pbpal_sockets.obj pbpal_resolv_and_connect_sockets.obj pubnub_alloc_std.obj pubnub_assert_std.obj pubnub_generate_uuid.obj pubnub_blocking_io.obj windows_socket_blocking_io.obj pubnub_free_with_timeout_std.obj pbbase64.obj pubnub_timers.obj pubnub_json_parse.obj md5.obj pubnub_helper.obj pubnub_version_windows.obj pubnub_generate_uuid_windows.obj pbpal_windows_blocking_io.obj snprintf.obj miniz_tinfl.obj miniz_tdef.obj miniz.obj pbcrc32.obj pbgzip_compress.obj pbgzip_decompress.obj pubnub_subscribe_v2.obj msstopwatch_windows.obj pubnub_url_encode.obj pbcc_advanced_history.obj pubnub_advanced_history.obj + + +!ifndef ONLY_PUBSUB_API +ONLY_PUBSUB_API = 0 +!endif + +!ifndef USE_PROXY +USE_PROXY = 1 +!endif + +!if $(USE_PROXY) +PROXY_INTF_SOURCEFILES = ..\core\pubnub_proxy.c ..\core\pubnub_proxy_core.c ..\core\pbhttp_digest.c ..\core\pbntlm_core.c ..\core\pbntlm_packer_sspi.c pubnub_set_proxy_from_system_windows.c +PROXY_INTF_OBJFILES = pubnub_proxy.obj pubnub_proxy_core.obj pbhttp_digest.obj pbntlm_core.obj pbntlm_packer_sspi.obj pubnub_set_proxy_from_system_windows.obj +!endif + +DEFINES=-D PUBNUB_THREADSAFE -D PUBNUB_LOG_LEVEL=PUBNUB_LOG_LEVEL_WARNING -D HAVE_STRERROR_S -D PUBNUB_ONLY_PUBSUB_API=$(ONLY_PUBSUB_API) -D PUBNUB_PROXY_API=$(USE_PROXY) # -D HAVE_STRERROR_R @@ -9,7 +25,7 @@ CFLAGS = -std=c11 -g -Wall -D PUBNUB_THREADSAFE -D PUBNUB_LOG_LEVEL=PUBNUB_LOG_ # -std=c11 enables `%z` and `%ll` in printf() - in general, we're "low" on C11 features # -fsanitize=address Uses the Address Sanitizer (supported by GCC and Clang) -INCLUDES=-I ../core -I . -I fntest -I ../core/fntest -I ../lib/base64 -I ../lib/md5 +INCLUDES=-I .. -I . LIBFILES=-lws2_32 -lrpcrt4 -lsecur32 @@ -23,13 +39,30 @@ all: pubnub_sync_sample.exe cancel_subscribe_sync_sample.exe # pubnub_console_sync.exe #subscribe_publish_callback_sample.exe pubnub_callback_sample.exe pubnub_fntest.exe pubnub_console_callback.exe -pubnub_sync.a : $(SOURCEFILES) ../core/pubnub_ntf_sync.c - "$(CC)" -c $(CFLAGS) $(INCLUDES) $(SOURCEFILES) ../core/pubnub_ntf_sync.c - $(AR) rcs $@ $(OBJFILES) pubnub_ntf_sync.o +SYNC_INTF_SOURCEFILES= ../core/pubnub_ntf_sync.c ../core/pubnub_sync_subscribe_loop.c ../core/srand_from_pubnub_time.c +SYNC_INTF_OBJFILES=pubnub_ntf_sync.obj pubnub_sync_subscribe_loop.obj srand_from_pubnub_time.obj + + +pubnub_sync.a: $(SOURCEFILES) $(PROXY_INTF_SOURCEFILES) $(SYNC_INTF_SOURCEFILES) + "$(CC)" -c $(CFLAGS) $(INCLUDES) $(SOURCEFILES) $(PROXY_INTF_SOURCEFILES) $(SYNC_INTF_SOURCEFILES) + $(AR) rcs $@ $(OBJFILES) $(SYNC_INTF_OBJFILES) $(PROXY_INTF_OBJFILES) + +## +# The socket poller module to use. The `poll` poller doesn't have the +# weird restrictions of `select` poller. OTOH, select() on Windows is +# compatible w/BSD sockets select(), while WSAPoll() has some weird +# differences to poll(). The names are the same until the last `_`, +# then it's `poll` vs `select. +SOCKET_POLLER_C=..\lib\sockets\pbpal_ntf_callback_poller_poll.c +SOCKET_POLLER_OBJ=pbpal_ntf_callback_poller_poll.obj + +CALLBACK_INTF_SOURCEFILES=pubnub_ntf_callback_windows.c pubnub_get_native_socket.c ../core/pubnub_timer_list.c ../lib/sockets/pbpal_adns_sockets.c ../lib/pubnub_dns_codec.c ../core/pubnub_dns_servers.c ../windows/pubnub_dns_system_servers.c ../lib/pubnub_parse_ipv4_addr.c ../lib/pubnub_parse_ipv6_addr.c $(SOCKET_POLLER_C) ../core/pbpal_ntf_callback_queue.c ../core/pbpal_ntf_callback_admin.c ../core/pbpal_ntf_callback_handle_timer_list.c ../core/pubnub_callback_subscribe_loop.c +CALLBACK_INTF_OBJFILES=pubnub_ntf_callback_windows.obj pubnub_get_native_socket.obj pubnub_timer_list.obj pbpal_adns_sockets.obj pubnub_dns_codec.obj pubnub_dns_servers.obj pubnub_dns_system_servers.obj pubnub_parse_ipv4_addr.obj pubnub_parse_ipv6_addr.obj $(SOCKET_POLLER_OBJ) pbpal_ntf_callback_queue.obj pbpal_ntf_callback_admin.obj pbpal_ntf_callback_handle_timer_list.obj pubnub_callback_subscribe_loop.obj + -pubnub_callback.a : $(SOURCEFILES) pubnub_ntf_callback_windows.c pubnub_get_native_socket.c ../core/pubnub_timer_list.c ../lib/sockets/pbpal_adns_sockets.c - "$(CC)" -c $(CFLAGS) -DPUBNUB_CALLBACK_API $(INCLUDES) $(SOURCEFILES) pubnub_ntf_callback_windows.c pubnub_get_native_socket.c ../core/pubnub_timer_list.c ../lib/sockets/pbpal_adns_sockets.c - $(AR) rcs $@ $(OBJFILES) pubnub_ntf_callback_windows.o pubnub_get_native_socket.o pubnub_timer_list.o pbpal_adns_sockets.o +pubnub_callback.a : $(SOURCEFILES) $(PROXY_INTF_SOURCEFILES) $(CALLBACK_INTF_SOURCEFILES) + "$(CC)" -c $(CFLAGS) -DPUBNUB_CALLBACK_API $(INCLUDES) $(SOURCEFILES) $(PROXY_INTF_SOURCEFILES) $(CALLBACK_INTF_SOURCEFILES) + $(AR) rcs $@ $(OBJFILES) $(PROXY_INTF_SOURCEFILES) $(CALLBACK_INTF_SOURCEFILES) pubnub_sync_sample.exe: ../core/samples/pubnub_sync_sample.c pubnub_sync.a "$(CC)" -o $@ $(CFLAGS) $(INCLUDES) ../core/samples/pubnub_sync_sample.c pubnub_sync.a $(LIBFILES)