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)); *p_origin = PUBNUB_ORIGIN_SETTABLE ? pb->origin : PUBNUB_ORIGIN; #if PUBNUB_USE_SSL if (pb->flags.trySSL) { PUBNUB_ASSERT(pb->options.useSSL); *p_port = TLS_PORT; } #endif #if PUBNUB_PROXY_API switch (pb->proxy_type) { case pbproxyHTTP_CONNECT: if (!pb->proxy_tunnel_established) { *p_origin = pb->proxy_hostname; } *p_port = pb->proxy_port; break; case pbproxyHTTP_GET: *p_origin = pb->proxy_hostname; *p_port = pb->proxy_port; PUBNUB_LOG_TRACE("Using proxy: %s : %hu\n", *p_origin, *p_port); break; default: break; } #endif return; }
enum pbpal_resolv_n_connect_result pbpal_check_resolv_and_connect(pubnub_t *pb) { #ifdef PUBNUB_CALLBACK_API struct sockaddr_in dns_server; struct sockaddr_in dest; uint16_t port = HTTP_PORT; pbpal_native_socket_t skt; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); PUBNUB_ASSERT_OPT(pb->state == PBS_WAIT_DNS_RCV); #if PUBNUB_USE_SSL if (pb->flags.trySSL) { PUBNUB_ASSERT(pb->options.useSSL); port = TLS_PORT; } #endif #if PUBNUB_PROXY_API if (pbproxyNONE != pb->proxy_type) { port = pb->proxy_port; } #endif skt = pb->pal.socket; PUBNUB_ASSERT(SOCKET_INVALID != skt); dns_server.sin_family = AF_INET; dns_server.sin_port = htons(DNS_PORT); get_dns_ip(&dns_server); memset(&dest, '\0', sizeof dest); switch (read_dns_response(skt, (struct sockaddr*)&dns_server, &dest)) { case -1: return pbpal_resolv_failed_rcv; case +1: return pbpal_resolv_rcv_wouldblock; case 0: break; } socket_close(skt); return connect_TCP_socket(pb, dest, port); #else PUBNUB_UNUSED(pb); /* Under regular BSD-ish sockets, this function should not be called unless using async DNS, so this is an error */ return pbpal_connect_failed; #endif /* PUBNUB_CALLBACK_API */ }
pubnub_t* pubnub_init(pubnub_t *p, const char *publish_key, const char *subscribe_key) { PUBNUB_ASSERT(pb_valid_ctx_ptr(p)); pubnub_mutex_init(p->monitor); pubnub_mutex_lock(p->monitor); pbcc_init(&p->core, publish_key, subscribe_key); if (PUBNUB_TIMERS_API) { p->transaction_timeout_ms = PUBNUB_DEFAULT_TRANSACTION_TIMER; #if defined(PUBNUB_DEFAULT_CONNECTION_TIMER) p->connection_timeout_s = PUBNUB_DEFAULT_CONNECTION_TIMER; #endif #if defined(PUBNUB_CALLBACK_API) p->previous = p->next = NULL; #endif } #if defined(PUBNUB_CALLBACK_API) p->cb = NULL; p->user_data = NULL; #endif if (PUBNUB_ORIGIN_SETTABLE) { p->origin = PUBNUB_ORIGIN; } p->state = PBS_IDLE; p->trans = PBTT_NONE; pbpal_init(p); pubnub_mutex_unlock(p->monitor); return p; }
enum pubnub_res pbpal_resolv_and_connect(pubnub_t *pb) { struct freertos_sockaddr addr; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); PUBNUB_ASSERT_OPT((pb->state == PBS_IDLE) || (pb->state == PBS_WAIT_DNS)); addr.sin_port = FreeRTOS_htons(HTTP_PORT); addr.sin_addr = FreeRTOS_gethostbyname(PUBNUB_ORIGIN_SETTABLE ? pb->origin : PUBNUB_ORIGIN); if (addr.sin_addr == 0) { return PNR_CONNECT_FAILED; } pb->pal.socket = FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP); if (pb->pal.socket == SOCKET_INVALID) { return PNR_CONNECT_FAILED; } if (FreeRTOS_connect(pb->pal.socket, &addr, sizeof addr) != 0) { FreeRTOS_closesocket(pb->pal.socket); pb->pal.socket = SOCKET_INVALID; return PNR_CONNECT_FAILED; } { TickType_t tmval = pdMS_TO_TICKS(pb->transaction_timeout_ms); FreeRTOS_setsockopt(pb->pal.socket, 0, FREERTOS_SO_RCVTIMEO, &tmval, sizeof tmval); } return PNR_OK; }
void pubnub_set_auth(pubnub_t *pb, const char *auth) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); pbcc_set_auth(&pb->core, auth); pubnub_mutex_unlock(pb->monitor); }
int pubnub_free(pubnub_t* pb) { int result = -1; PUBNUB_ASSERT(check_ctx_ptr(pb)); PUBNUB_LOG_TRACE("pubnub_free(%p)\n", pb); pubnub_mutex_lock(pb->monitor); pbnc_stop(pb, PNR_CANCELLED); if (PBS_IDLE == pb->state) { PUBNUB_LOG_TRACE("pubnub_free(%p) PBS_IDLE\n", pb); pb->state = PBS_NULL; #if defined(PUBNUB_CALLBACK_API) pbntf_requeue_for_processing(pb); pubnub_mutex_unlock(pb->monitor); #else pubnub_mutex_unlock(pb->monitor); pballoc_free_at_last(pb); #endif result = 0; } else { PUBNUB_LOG_TRACE("pubnub_free(%p) pb->state=%d\n", pb, pb->state); pubnub_mutex_unlock(pb->monitor); } return result; }
static void save_socket(struct SocketWatcherData *watcher, pubnub_t *pb) { size_t i; pbpal_native_socket_t sockt = pubnub_get_native_socket(pb); PUBNUB_ASSERT(watcher->apoll_size <= watcher->apoll_cap); if (INVALID_SOCKET == sockt) { return; } for (i = 0; i < watcher->apoll_size; ++i) { PUBNUB_ASSERT_OPT(watcher->apoll[i].fd != sockt); } if (watcher->apoll_size == watcher->apoll_cap) { size_t newcap = watcher->apoll_cap + 2; WSAPOLLFD *npapoll = (WSAPOLLFD*)realloc(watcher->apoll, sizeof watcher->apoll[0] * newcap); if (NULL == npapoll) { return; } else { pubnub_t **npapb = (pubnub_t**)realloc(watcher->apb, sizeof watcher->apb[0] * newcap); watcher->apoll = npapoll; if (NULL == npapb) { return; } watcher->apb = npapb; } watcher->apoll_cap = newcap; } watcher->apoll[watcher->apoll_size].fd = sockt; watcher->apoll[watcher->apoll_size].events = POLLOUT; watcher->apb[watcher->apoll_size] = pb; ++watcher->apoll_size; }
enum pubnub_res pubnub_await(pubnub_t* pb) { pbmsref_t t0; enum pubnub_res result; bool stopped = false; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); t0 = pbms_start(); while (!pbnc_can_start_transaction(pb)) { pbms_t delta; pbnc_fsm(pb); delta = pbms_elapsed(t0); if (delta > pb->transaction_timeout_ms) { if (!stopped) { pbnc_stop(pb, PNR_TIMEOUT); t0 = pbms_start(); stopped = true; } else { break; } } } result = pb->core.last_result; pubnub_mutex_unlock(pb->monitor); return result; }
enum pubnub_res pubnub_get_decrypted(pubnub_t *pb, char const* cipher_key, char *s, size_t *n) { char *msg; size_t msg_len; uint8_t decoded_msg[PUBNUB_BUF_MAXLEN]; pubnub_bymebl_t data = { (uint8_t*)s, *n }; pubnub_bymebl_t buffer = { decoded_msg, PUBNUB_BUF_MAXLEN }; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); PUBNUB_ASSERT_OPT(cipher_key != NULL); PUBNUB_ASSERT_OPT(s != NULL); PUBNUB_ASSERT_OPT(n != NULL); msg = (char*)pubnub_get(pb); if (NULL == msg) { return PNR_INTERNAL_ERROR; } msg_len = strlen(msg); if ((msg[0] != '"') || (msg[msg_len-1] != '"')) { return PNR_FORMAT_ERROR; } msg[msg_len - 1] = '\0'; ++msg; pubnub_json_string_unescape_slash(msg); if (0 != pubnub_decrypt_buffered(cipher_key, msg, &data, &buffer)) { return PNR_INTERNAL_ERROR; } *n = data.size; data.ptr[data.size] = '\0'; return PNR_OK; }
pubnub_t *pubnub_timer_list_as_time_goes_by(pubnub_t **pplist, int time_passed_ms) { pubnub_t *list; pubnub_t *expired_list = NULL; PUBNUB_ASSERT_OPT(pplist != NULL); PUBNUB_ASSERT_OPT(time_passed_ms > 0); list = *pplist; if (NULL == list) { return NULL; } if (list->timeout_left_ms > time_passed_ms) { list->timeout_left_ms -= time_passed_ms; return NULL; } expired_list = list; while (list->timeout_left_ms <= time_passed_ms) { time_passed_ms -= list->timeout_left_ms; if (NULL == list->next) { *pplist = NULL; return expired_list; } list = list->next; } list->timeout_left_ms -= time_passed_ms; PUBNUB_ASSERT(list->previous != NULL); list->previous->next = NULL; list->previous = NULL; *pplist = list; return expired_list; }
pubnub_bymebl_t pubnub_get_decrypted_alloc(pubnub_t *pb, char const* cipher_key) { char *msg; size_t msg_len; pubnub_bymebl_t result = { NULL, 0 }; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); PUBNUB_ASSERT_OPT(cipher_key != NULL); msg = (char*)pubnub_get(pb); if (NULL == msg) { return result; } msg_len = strlen(msg); if ((msg[0] != '"') || (msg[msg_len-1] != '"')) { return result; } msg[msg_len - 1] = '\0'; ++msg; pubnub_json_string_unescape_slash(msg); result = pubnub_decrypt_alloc(cipher_key, msg); if (NULL != result.ptr) { result.ptr[result.size] = '\0'; } return result; }
enum pubnub_res pubnub_register_callback(pubnub_t *pb, pubnub_callback_t cb, void *user_data) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pb->cb = cb; pb->user_data = user_data; return PNR_OK; }
void pubnub_set_uuid(pubnub_t *pb, const char *uuid) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); pbcc_set_uuid(&pb->core, uuid); pubnub_mutex_unlock(pb->monitor); }
enum pubnub_res pubnub_await(pubnub_t *pb) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); while (pb->state != PBS_IDLE) { pbnc_fsm(pb); } return pb->core.last_result; }
char const *pubnub_get_origin(pubnub_t const *pb) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); if (PUBNUB_ORIGIN_SETTABLE) { return pb->origin; } return PUBNUB_ORIGIN; }
void pbpal_ntf_callback_remove_socket(struct pbpal_poll_data* data, pubnub_t* pb) { size_t i; int new_nfds = 0; pbpal_native_socket_t sockt = pubnub_get_native_socket(pb); PUBNUB_ASSERT_OPT(data != NULL); if (INVALID_SOCKET == sockt) { return; } PUBNUB_ASSERT(FD_ISSET(sockt, &data->exceptfds)); PUBNUB_ASSERT_EX(we_ve_got_ya(data, pb)); for (i = 0; i < data->size; ++i) { pbpal_native_socket_t i_sckt = data->asocket[i]; PUBNUB_ASSERT(pubnub_get_native_socket(data->apb[i]) == data->asocket[i]); if ((int)i_sckt > new_nfds) { new_nfds = i_sckt; } if (data->apb[i] == pb) { size_t to_move = data->size - i - 1; if (to_move > 0) { memmove(data->apb + i, data->apb + i + 1, sizeof data->apb[0] * to_move); memmove(data->asocket + i, data->asocket + i + 1, sizeof data->asocket[0] * to_move); } --data->size; break; } } FD_CLR(sockt, &data->exceptfds); FD_CLR(sockt, &data->writefds); FD_CLR(sockt, &data->readfds); for (; i < data->size; ++i) { pbpal_native_socket_t i_sckt = data->asocket[i]; PUBNUB_ASSERT(pubnub_get_native_socket(data->apb[i]) == data->asocket[i]); if ((int)i_sckt > new_nfds) { new_nfds = i_sckt; } } data->nfds = new_nfds; }
void pubnub_cancel(pubnub_t *pb) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); pbnc_stop(pb, PNR_CANCELLED); pubnub_mutex_unlock(pb->monitor); }
enum pubnub_res pubnub_last_result(pubnub_t const *pb) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); if (pb->state != PBS_IDLE) { pbnc_fsm((pubnub_t*)pb); } return pb->core.last_result; }
int pubnub_free(pubnub_t *pb) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); if (PBS_IDLE == pb->state) { pb->state = PBS_NULL; return 0; } return -1; }
int pubnub_last_http_code(pubnub_t *pb) { int result; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); result = pb->http_code; pubnub_mutex_unlock(pb->monitor); return result; }
char const *pubnub_get(pubnub_t *pb) { char const *result; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); result = pbcc_get_msg(&pb->core); pubnub_mutex_unlock(pb->monitor); return result; }
char const *pubnub_last_time_token(pubnub_t *pb) { char const *result; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); result = pb->core.timetoken; pubnub_mutex_unlock(pb->monitor); return result; }
int pubnub_origin_set(pubnub_t *pb, char const *origin) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); if (PUBNUB_ORIGIN_SETTABLE) { if (NULL == origin) { origin = PUBNUB_ORIGIN; } pb->origin = origin; return 0; } return -1; }
void pbpal_ntf_callback_save_socket(struct pbpal_poll_data* data, pubnub_t* pb) { pbpal_native_socket_t sockt = pubnub_get_native_socket(pb); PUBNUB_ASSERT_OPT(data != NULL); if (INVALID_SOCKET == sockt) { return; } PUBNUB_ASSERT(!FD_ISSET(sockt, &data->exceptfds)); PUBNUB_ASSERT(!FD_ISSET(sockt, &data->writefds)); PUBNUB_ASSERT(!FD_ISSET(sockt, &data->readfds)); PUBNUB_ASSERT_EX(!we_ve_got_ya(data, pb)); if ((int)sockt > data->nfds) { data->nfds = sockt; } FD_SET(sockt, &data->exceptfds); FD_SET(sockt, &data->writefds); data->apb[data->size] = pb; data->asocket[data->size] = sockt; ++data->size; }
char const *pubnub_get_origin(pubnub_t *pb) { PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); if (PUBNUB_ORIGIN_SETTABLE) { char const *result; pubnub_mutex_lock(pb->monitor); result = pb->origin; pubnub_mutex_unlock(pb->monitor); return result; } return PUBNUB_ORIGIN; }
enum pubnub_res pubnub_await(pubnub_t *pb) { enum pubnub_res result; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); while (pb->state != PBS_IDLE) { pbnc_fsm(pb); } result = pb->core.last_result; pubnub_mutex_unlock(pb->monitor); return result; }
static void remove_socket(struct SocketWatcherData *watcher, pubnub_t *pb) { size_t i; pbpal_native_socket_t sockt = pubnub_get_native_socket(pb); PUBNUB_ASSERT(watcher->apoll_size <= watcher->apoll_cap); if (INVALID_SOCKET == sockt) { return; } for (i = 0; i < watcher->apoll_size; ++i) { if (watcher->apoll[i].fd == sockt) { size_t to_move = watcher->apoll_size - i - 1; PUBNUB_ASSERT(watcher->apb[i] == pb); if (to_move > 0) { memmove(watcher->apoll + i, watcher->apoll + i + 1, sizeof watcher->apoll[0] * to_move); memmove(watcher->apb + i, watcher->apb + i + 1, sizeof watcher->apb[0] * to_move); } --watcher->apoll_size; break; } } }
enum pubnub_res pubnub_last_result(pubnub_t* pb) { enum pubnub_res result; PUBNUB_ASSERT(pb_valid_ctx_ptr(pb)); pubnub_mutex_lock(pb->monitor); if (!pbnc_can_start_transaction(pb)) { pbnc_fsm((pubnub_t*)pb); } result = pb->core.last_result; pubnub_mutex_unlock(pb->monitor); return result; }
pubnub_t *pubnub_timer_list_add(pubnub_t *list, pubnub_t *to_add) { int timeout_to_add_ms = to_add->transaction_timeout_ms; pubnub_t *pbp; PUBNUB_ASSERT_OPT(to_add != NULL); if (NULL == list) { list = to_add; to_add->previous = to_add->next = NULL; to_add->timeout_left_ms = timeout_to_add_ms; return list; } PUBNUB_ASSERT_OPT(list != to_add); if (timeout_to_add_ms < list->timeout_left_ms) { list->timeout_left_ms -= timeout_to_add_ms; to_add->next = list; to_add->previous = NULL; list->previous = to_add; to_add->timeout_left_ms = timeout_to_add_ms; return to_add; } pbp = list; while (timeout_to_add_ms >= pbp->timeout_left_ms) { timeout_to_add_ms -= pbp->timeout_left_ms; if (NULL == pbp->next) { pbp->next = to_add; to_add->previous = pbp; to_add->next = NULL; to_add->timeout_left_ms = timeout_to_add_ms; return list; } pbp = pbp->next; PUBNUB_ASSERT_OPT(pbp != to_add); } pbp->timeout_left_ms -= timeout_to_add_ms; to_add->next = pbp; to_add->previous = pbp->previous; PUBNUB_ASSERT(NULL != pbp->previous); pbp->previous->next = to_add; pbp->previous = to_add; to_add->timeout_left_ms = timeout_to_add_ms; return list; }
bool pnfntst_got_message_on_channel(pubnub_t *p, char const *message, char const *channel) { char const *msg; char const *chan; PUBNUB_ASSERT(pb_valid_ctx_ptr(p)); PUBNUB_ASSERT_OPT(NULL != message); PUBNUB_ASSERT_OPT(NULL != channel); msg = pubnub_get(p); chan = pubnub_get_channel(p); if ((NULL == msg) || (NULL == chan)) { return false; } return (strcmp(msg, message) == 0) && (strcmp(chan, channel) == 0); }