Modified PubNub library to better utilize low bandwidth connections like a GSM modem. Instead of 10 socket connections sending 3 bytes only one is made and it sends all 30 bytes at the same time.

Fork of PubNub by PubNub

Committer:
embeddedartists
Date:
Wed Oct 01 11:36:11 2014 +0000
Revision:
7:55eb53c78b47
Parent:
6:09d0a383fdde
Modified PubNub library to better utilize low bandwidth connections like a GSM modem. Instead of 10 sockets connections sending 3 bytes only one is made and it sends all 30 bytes at the same time.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pasky 0:9858347c382d 1 #include <cstring>
pasky 0:9858347c382d 2
pasky 0:9858347c382d 3 #include "mbed.h"
mazgch 6:09d0a383fdde 4 #include "TCPSocketConnection.h"
pasky 0:9858347c382d 5
pasky 0:9858347c382d 6 #include "PubNub.h"
pasky 0:9858347c382d 7
pasky 0:9858347c382d 8
pasky 0:9858347c382d 9 #define DBG if (0) // change to if (1) to enable debug prints on USB serial
pasky 0:9858347c382d 10
embeddedartists 7:55eb53c78b47 11 //#define USE_ORIGINAL_CODE
pasky 0:9858347c382d 12
pasky 0:9858347c382d 13 /* We roll our own HTTP communication stack as donatien's HTTPClient has
pasky 0:9858347c382d 14 * some hard limits on URL length and this will allow a more frugal RAM
pasky 0:9858347c382d 15 * usage for us. */
pasky 0:9858347c382d 16
pasky 0:9858347c382d 17 /* Also, we pass messages as serialized JSON strings instead of parsed
pasky 0:9858347c382d 18 * structures. The available JSON parsers (picojson in particular) are
pasky 0:9858347c382d 19 * heavy on many tiny memory allocations, which can get very troublesome
pasky 0:9858347c382d 20 * with mbed's malloc() - we get very high memory fragmentation. In many
pasky 0:9858347c382d 21 * cases, working with raw JSON is just fine, and in our demo example,
pasky 0:9858347c382d 22 * we still show picojson usage for end-user parsing of complex incoming
pasky 0:9858347c382d 23 * messages. */
pasky 0:9858347c382d 24
embeddedartists 7:55eb53c78b47 25 #include "rtos.h"
embeddedartists 7:55eb53c78b47 26
embeddedartists 7:55eb53c78b47 27 void pnub_err_handler(PubNubRes code, int line);
embeddedartists 7:55eb53c78b47 28 extern Serial pc;
embeddedartists 7:55eb53c78b47 29 extern Mutex stdio_mutex;
embeddedartists 7:55eb53c78b47 30 #define safe_printf(...) do { \
embeddedartists 7:55eb53c78b47 31 stdio_mutex.lock(); \
embeddedartists 7:55eb53c78b47 32 pc.printf(__VA_ARGS__); \
embeddedartists 7:55eb53c78b47 33 stdio_mutex.unlock(); \
embeddedartists 7:55eb53c78b47 34 } while(0)
embeddedartists 7:55eb53c78b47 35
embeddedartists 7:55eb53c78b47 36 #define PNUB_RETURN_STAT(__stat) do { \
embeddedartists 7:55eb53c78b47 37 if ((__stat) != PNR_OK) { \
embeddedartists 7:55eb53c78b47 38 pnub_err_handler((__stat), __LINE__); \
embeddedartists 7:55eb53c78b47 39 } \
embeddedartists 7:55eb53c78b47 40 return (__stat); \
embeddedartists 7:55eb53c78b47 41 } while(0)
embeddedartists 7:55eb53c78b47 42
pasky 0:9858347c382d 43
pasky 0:9858347c382d 44 /** Custom no-frills HTTP stream. */
pasky 0:9858347c382d 45
pasky 0:9858347c382d 46 class PubNubHTTP: public TCPSocketConnection {
pasky 0:9858347c382d 47 public:
pasky 0:9858347c382d 48 /* Connect http socket to origin. */
pasky 0:9858347c382d 49 PubNubRes http_connect(const char *hostname);
pasky 0:9858347c382d 50
pasky 0:9858347c382d 51 /* These methods are used to send the request type and URL. */
pasky 0:9858347c382d 52 /* Send a given NUL-terminated string over the http socket. */
pasky 0:9858347c382d 53 void sendstr(const char *string);
pasky 0:9858347c382d 54 /* Send a given NUL-terminated string over the http socket, URL encoded. */
pasky 0:9858347c382d 55 void sendstr_urlenc(const char *string);
embeddedartists 7:55eb53c78b47 56 /* URL encode a given NUL-terminated string into the given buffer. */
embeddedartists 7:55eb53c78b47 57 void prepare_urlenc(const char *string, char* buff);
pasky 0:9858347c382d 58
pasky 0:9858347c382d 59 /* A common HTTP request "bottom half" - send the rest of headers
pasky 0:9858347c382d 60 * and wait for reply + receive. */
pasky 0:9858347c382d 61 PubNubRes http_request_bh(const char *host, char **reply, int *replylen);
pasky 0:9858347c382d 62
pasky 0:9858347c382d 63 protected:
pasky 0:9858347c382d 64 /* These methods represent sub-stages of http_request_bh().
pasky 0:9858347c382d 65 * They share the state of m_replybuf and m_replylen. */
pasky 0:9858347c382d 66 PubNubRes http_send_headers(const char *host);
pasky 0:9858347c382d 67 PubNubRes http_recv_headers();
pasky 0:9858347c382d 68 PubNubRes http_recv_content();
pasky 0:9858347c382d 69
pasky 0:9858347c382d 70 char *m_replybuf;
pasky 0:9858347c382d 71 int m_replylen;
pasky 0:9858347c382d 72 int m_content_length;
pasky 0:9858347c382d 73 };
pasky 0:9858347c382d 74
pasky 0:9858347c382d 75 PubNubRes
pasky 0:9858347c382d 76 PubNubHTTP::http_connect(const char *hostname)
pasky 0:9858347c382d 77 {
pasky 0:9858347c382d 78 int ret = connect(hostname, 80);
pasky 0:9858347c382d 79 if (ret < 0) {
pasky 0:9858347c382d 80 close();
embeddedartists 7:55eb53c78b47 81 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 82 safe_printf("http_connect(%s): ret = %d\n", hostname, ret);
embeddedartists 7:55eb53c78b47 83 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 84 }
pasky 0:9858347c382d 85 return PNR_OK;
pasky 0:9858347c382d 86 }
pasky 0:9858347c382d 87
pasky 0:9858347c382d 88 void
pasky 0:9858347c382d 89 PubNubHTTP::sendstr(const char *s)
pasky 0:9858347c382d 90 {
pasky 0:9858347c382d 91 send_all((char *) s, strlen(s));
pasky 0:9858347c382d 92 }
pasky 0:9858347c382d 93
pasky 0:9858347c382d 94 void
pasky 0:9858347c382d 95 PubNubHTTP::sendstr_urlenc(const char *s)
pasky 0:9858347c382d 96 {
pasky 0:9858347c382d 97 while (s[0]) {
pasky 0:9858347c382d 98 /* RFC 3986 Unreserved characters plus few
pasky 0:9858347c382d 99 * safe reserved ones. */
pasky 0:9858347c382d 100 size_t okspan = strspn(s, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~" ",=:;@[]");
pasky 0:9858347c382d 101 if (okspan > 0) {
pasky 0:9858347c382d 102 send_all((char *) s, okspan);
pasky 0:9858347c382d 103 s += okspan;
pasky 0:9858347c382d 104 }
pasky 0:9858347c382d 105 if (s[0]) {
pasky 0:9858347c382d 106 /* %-encode a non-ok character. */
pasky 0:9858347c382d 107 char enc[3] = {'%'};
pasky 0:9858347c382d 108 enc[1] = "0123456789ABCDEF"[s[0] / 16];
pasky 0:9858347c382d 109 enc[2] = "0123456789ABCDEF"[s[0] % 16];
pasky 0:9858347c382d 110 send_all((char *) enc, 3);
pasky 0:9858347c382d 111 s++;
pasky 0:9858347c382d 112 }
pasky 0:9858347c382d 113 }
pasky 0:9858347c382d 114 }
pasky 0:9858347c382d 115
embeddedartists 7:55eb53c78b47 116 void
embeddedartists 7:55eb53c78b47 117 PubNubHTTP::prepare_urlenc(const char *s, char* buff)
embeddedartists 7:55eb53c78b47 118 {
embeddedartists 7:55eb53c78b47 119 char* b = buff;
embeddedartists 7:55eb53c78b47 120 while (s[0]) {
embeddedartists 7:55eb53c78b47 121 /* RFC 3986 Unreserved characters plus few
embeddedartists 7:55eb53c78b47 122 * safe reserved ones. */
embeddedartists 7:55eb53c78b47 123 size_t okspan = strspn(s, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~" ",=:;@[]");
embeddedartists 7:55eb53c78b47 124 if (okspan > 0) {
embeddedartists 7:55eb53c78b47 125 strncpy(b, s, okspan);
embeddedartists 7:55eb53c78b47 126 b += okspan;
embeddedartists 7:55eb53c78b47 127 //send_all((char *) s, okspan);
embeddedartists 7:55eb53c78b47 128 s += okspan;
embeddedartists 7:55eb53c78b47 129 }
embeddedartists 7:55eb53c78b47 130 if (s[0]) {
embeddedartists 7:55eb53c78b47 131 /* %-encode a non-ok character. */
embeddedartists 7:55eb53c78b47 132 *b++ = '%';
embeddedartists 7:55eb53c78b47 133 *b++ = "0123456789ABCDEF"[s[0] / 16];
embeddedartists 7:55eb53c78b47 134 *b++ = "0123456789ABCDEF"[s[0] % 16];
embeddedartists 7:55eb53c78b47 135 //send_all((char *) enc, 3);
embeddedartists 7:55eb53c78b47 136 s++;
embeddedartists 7:55eb53c78b47 137 }
embeddedartists 7:55eb53c78b47 138 }
embeddedartists 7:55eb53c78b47 139 *b = '\0';
embeddedartists 7:55eb53c78b47 140 }
embeddedartists 7:55eb53c78b47 141
pasky 0:9858347c382d 142 PubNubRes
pasky 0:9858347c382d 143 PubNubHTTP::http_request_bh(const char *host, char **reply, int *replylen)
pasky 0:9858347c382d 144 {
pasky 0:9858347c382d 145 m_replybuf = NULL;
pasky 0:9858347c382d 146 m_replylen = 0;
pasky 0:9858347c382d 147
pasky 0:9858347c382d 148 PubNubRes res;
pasky 0:9858347c382d 149 res = http_send_headers(host);
pasky 0:9858347c382d 150 if (res != PNR_OK) {
pasky 0:9858347c382d 151 close();
embeddedartists 7:55eb53c78b47 152 //return res;
embeddedartists 7:55eb53c78b47 153 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 154 }
pasky 0:9858347c382d 155
pasky 0:9858347c382d 156 res = http_recv_headers();
pasky 0:9858347c382d 157 if (res != PNR_OK) {
pasky 0:9858347c382d 158 if (m_replybuf) free(m_replybuf);
pasky 0:9858347c382d 159 close();
embeddedartists 7:55eb53c78b47 160 //return res;
embeddedartists 7:55eb53c78b47 161 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 162 }
pasky 0:9858347c382d 163
pasky 0:9858347c382d 164 res = http_recv_content();
pasky 0:9858347c382d 165 if (res != PNR_OK) {
pasky 0:9858347c382d 166 if (m_replybuf) free(m_replybuf);
pasky 0:9858347c382d 167 close();
embeddedartists 7:55eb53c78b47 168 //return res;
embeddedartists 7:55eb53c78b47 169 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 170 }
pasky 0:9858347c382d 171
pasky 0:9858347c382d 172 close();
pasky 0:9858347c382d 173 *reply = (char *) realloc(m_replybuf, m_replylen);
pasky 0:9858347c382d 174 *replylen = m_replylen;
pasky 0:9858347c382d 175 return PNR_OK;
pasky 0:9858347c382d 176 }
pasky 0:9858347c382d 177
pasky 0:9858347c382d 178 PubNubRes
pasky 0:9858347c382d 179 PubNubHTTP::http_send_headers(const char *host)
pasky 0:9858347c382d 180 {
embeddedartists 7:55eb53c78b47 181 #ifdef USE_ORIGINAL_CODE
pasky 0:9858347c382d 182 /* Finish the first line of the request. */
pasky 0:9858347c382d 183 sendstr(" HTTP/1.1\r\n");
pasky 0:9858347c382d 184 /* Finish HTTP request. */
pasky 0:9858347c382d 185 sendstr("Host: ");
pasky 0:9858347c382d 186 sendstr(host);
pasky 0:9858347c382d 187 sendstr("\r\nUser-Agent: PubNub-mbed/0.1\r\nConnection: close\r\n\r\n");
pasky 0:9858347c382d 188 if (!is_connected())
embeddedartists 7:55eb53c78b47 189 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 190 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 191 return PNR_OK;
embeddedartists 7:55eb53c78b47 192 #else
embeddedartists 7:55eb53c78b47 193 char buff[200];
embeddedartists 7:55eb53c78b47 194 snprintf(buff, 200, " HTTP/1.1\r\nHost: %s\r\nUser-Agent: PubNub-mbed/0.1\r\nConnection: close\r\n\r\n", host);
embeddedartists 7:55eb53c78b47 195 sendstr(buff);
embeddedartists 7:55eb53c78b47 196 if (!is_connected())
embeddedartists 7:55eb53c78b47 197 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 198 PNUB_RETURN_STAT(PNR_IO_ERROR);
embeddedartists 7:55eb53c78b47 199 return PNR_OK;
embeddedartists 7:55eb53c78b47 200 #endif
pasky 0:9858347c382d 201 }
pasky 0:9858347c382d 202
pasky 0:9858347c382d 203 PubNubRes
pasky 0:9858347c382d 204 PubNubHTTP::http_recv_headers()
pasky 0:9858347c382d 205 {
pasky 0:9858347c382d 206 /* Now, read HTTP reply. */
pasky 0:9858347c382d 207 m_replybuf = (char *) malloc(PUBNUB_REPLY_MAXLEN+1);
pasky 0:9858347c382d 208
pasky 0:9858347c382d 209 /* First, receive headers. */
pasky 0:9858347c382d 210 /* XXX: For now, we assume complete headers will fit in m_replybuf. */
pasky 0:9858347c382d 211 m_replylen = receive_all(m_replybuf, PUBNUB_REPLY_MAXLEN);
pasky 0:9858347c382d 212 if (m_replylen < 0)
embeddedartists 7:55eb53c78b47 213 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 214 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 215 m_replybuf[m_replylen] = 0;
pasky 0:9858347c382d 216
pasky 0:9858347c382d 217 char *bufptr = m_replybuf;
pasky 0:9858347c382d 218
pasky 0:9858347c382d 219 /* Parse the first line. */
pasky 0:9858347c382d 220 if (strncmp(bufptr, "HTTP/1.", 7) || !bufptr[7] || !bufptr[8])
embeddedartists 7:55eb53c78b47 221 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 222 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 223 int http_code = atoi(bufptr+9);
pasky 0:9858347c382d 224 if (http_code / 100 != 2)
embeddedartists 7:55eb53c78b47 225 //return PNR_HTTP_ERROR;
embeddedartists 7:55eb53c78b47 226 PNUB_RETURN_STAT(PNR_HTTP_ERROR);
pasky 0:9858347c382d 227 bufptr = strstr(bufptr, "\r\n");
pasky 0:9858347c382d 228 if (!bufptr)
embeddedartists 7:55eb53c78b47 229 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 230 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 231 bufptr += 2;
pasky 0:9858347c382d 232
pasky 0:9858347c382d 233 /* Parse the rest of the lines. */
pasky 0:9858347c382d 234 m_content_length = 0;
pasky 0:9858347c382d 235 bool is_chunked = false;
pasky 0:9858347c382d 236 char *newline;
pasky 0:9858347c382d 237 for (;; bufptr = newline+2) {
pasky 0:9858347c382d 238 newline = strstr(bufptr, "\r\n");
pasky 0:9858347c382d 239 if (!newline)
embeddedartists 7:55eb53c78b47 240 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 241 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 242 *newline = 0;
pasky 0:9858347c382d 243
pasky 0:9858347c382d 244 char h_chunked[] = "Transfer-Encoding: chunked";
pasky 0:9858347c382d 245 char h_length[] = "Content-Length: ";
pasky 0:9858347c382d 246 if (*bufptr == 0) {
pasky 0:9858347c382d 247 /* Empty line. End of headers. */
pasky 0:9858347c382d 248 bufptr += 2;
pasky 0:9858347c382d 249 break;
pasky 0:9858347c382d 250 } else if (!strncmp(bufptr, h_chunked, sizeof(h_chunked)-1)) {
pasky 0:9858347c382d 251 /* Transfer-Encoding: chunked */
pasky 0:9858347c382d 252 is_chunked = true;
pasky 0:9858347c382d 253 } else if (!strncmp(bufptr, h_length, sizeof(h_length)-1)) {
pasky 0:9858347c382d 254 /* Content-Length: ... */
pasky 0:9858347c382d 255 m_content_length = atoi(bufptr + sizeof(h_length)-1);
pasky 0:9858347c382d 256 }
pasky 0:9858347c382d 257 }
pasky 0:9858347c382d 258
pasky 0:9858347c382d 259 /* Possibly process a chunk header. */
pasky 0:9858347c382d 260 if (is_chunked) {
pasky 0:9858347c382d 261 m_content_length = atoi(bufptr);
pasky 0:9858347c382d 262 bufptr = strstr(bufptr, "\r\n");
pasky 0:9858347c382d 263 if (!bufptr)
embeddedartists 7:55eb53c78b47 264 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 265 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 266 bufptr += 2;
pasky 0:9858347c382d 267 }
pasky 0:9858347c382d 268
pasky 0:9858347c382d 269 /* Consolidate the buffer. */
pasky 0:9858347c382d 270 m_replylen -= bufptr - m_replybuf;
pasky 0:9858347c382d 271 memmove(m_replybuf, bufptr, m_replylen);
pasky 0:9858347c382d 272
pasky 0:9858347c382d 273 return PNR_OK;
pasky 0:9858347c382d 274 }
pasky 0:9858347c382d 275
pasky 0:9858347c382d 276 PubNubRes
pasky 0:9858347c382d 277 PubNubHTTP::http_recv_content()
pasky 0:9858347c382d 278 {
pasky 0:9858347c382d 279 /* Now, we are ready to process data! */
pasky 0:9858347c382d 280
pasky 0:9858347c382d 281 if (m_content_length > PUBNUB_REPLY_MAXLEN) {
pasky 0:9858347c382d 282 /* XXX: Actually, too much data, sorry. */
pasky 0:9858347c382d 283 DBG printf("too much data\r\n");
embeddedartists 7:55eb53c78b47 284 //return PNR_FORMAT_ERROR;
embeddedartists 7:55eb53c78b47 285 PNUB_RETURN_STAT(PNR_FORMAT_ERROR);
pasky 0:9858347c382d 286 }
pasky 0:9858347c382d 287
pasky 0:9858347c382d 288 if (m_replylen < m_content_length) {
pasky 0:9858347c382d 289 /* More data coming. */
pasky 0:9858347c382d 290 int recv2len = receive_all(m_replybuf + m_replylen, PUBNUB_REPLY_MAXLEN - m_replylen);
pasky 0:9858347c382d 291 if (recv2len < 0)
embeddedartists 7:55eb53c78b47 292 //return PNR_IO_ERROR;
embeddedartists 7:55eb53c78b47 293 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 294 m_replylen += recv2len;
pasky 0:9858347c382d 295 }
pasky 0:9858347c382d 296
pasky 0:9858347c382d 297 if (m_replylen < m_content_length)
embeddedartists 7:55eb53c78b47 298 //return PNR_IO_ERROR; /* Incomplete data. */
embeddedartists 7:55eb53c78b47 299 PNUB_RETURN_STAT(PNR_IO_ERROR);
pasky 0:9858347c382d 300 return PNR_OK;
pasky 0:9858347c382d 301 }
pasky 0:9858347c382d 302
pasky 0:9858347c382d 303
pasky 0:9858347c382d 304 /** Some utility routines. */
pasky 0:9858347c382d 305
pasky 0:9858347c382d 306 /* Split a JSON array (with arbitrary contents) to multiple NUL-terminated
pasky 0:9858347c382d 307 * C strings. */
pasky 0:9858347c382d 308 static PubNubRes
pasky 0:9858347c382d 309 split_array(char *buf, int len)
pasky 0:9858347c382d 310 {
pasky 0:9858347c382d 311 bool escaped = false, in_string = false;
pasky 0:9858347c382d 312 int bracket_level = 0;
pasky 0:9858347c382d 313 for (int i = 0; i < len; i++) {
pasky 0:9858347c382d 314 if (escaped) {
pasky 0:9858347c382d 315 escaped = false;
pasky 0:9858347c382d 316 } else if (in_string) {
pasky 0:9858347c382d 317 switch (buf[i]) {
pasky 0:9858347c382d 318 case '\\': escaped = true; break;
pasky 0:9858347c382d 319 case '"': in_string = false; break;
pasky 0:9858347c382d 320 default: break;
pasky 0:9858347c382d 321 }
pasky 0:9858347c382d 322 } else {
pasky 0:9858347c382d 323 switch (buf[i]) {
pasky 0:9858347c382d 324 case '"': in_string = true; break;
pasky 0:9858347c382d 325 case '[': case '{': bracket_level++; break;
pasky 0:9858347c382d 326 case ']': case '}': bracket_level--; break;
pasky 0:9858347c382d 327 /* if at root, split! */
pasky 0:9858347c382d 328 case ',': if (bracket_level == 0) buf[i] = 0; break;
pasky 0:9858347c382d 329 default: break;
pasky 0:9858347c382d 330 }
pasky 0:9858347c382d 331 }
pasky 0:9858347c382d 332 }
pasky 0:9858347c382d 333 DBG printf("parse %d %d %d\r\n", escaped, in_string, bracket_level);
pasky 0:9858347c382d 334 if (escaped || in_string || bracket_level > 0)
embeddedartists 7:55eb53c78b47 335 //return PNR_FORMAT_ERROR;
embeddedartists 7:55eb53c78b47 336 PNUB_RETURN_STAT(PNR_FORMAT_ERROR);
pasky 0:9858347c382d 337 return PNR_OK;
pasky 0:9858347c382d 338 }
pasky 0:9858347c382d 339
pasky 0:9858347c382d 340
pasky 0:9858347c382d 341 /** PubNub API. */
pasky 0:9858347c382d 342
pasky 0:9858347c382d 343 PubNub::PubNub(const char *publish_key_, const char *subscribe_key_, const char *origin_) :
pasky 0:9858347c382d 344 m_publish_key(publish_key_), m_subscribe_key(subscribe_key_), m_origin(origin_),
pasky 0:9858347c382d 345 m_replybuf(NULL), m_replylen(0)
pasky 0:9858347c382d 346 {
pasky 0:9858347c382d 347 strcpy(m_timetoken, "0");
pasky 0:9858347c382d 348 }
pasky 0:9858347c382d 349
pasky 0:9858347c382d 350 PubNub::~PubNub()
pasky 0:9858347c382d 351 {
pasky 0:9858347c382d 352 if (m_replybuf)
pasky 0:9858347c382d 353 free(m_replybuf);
pasky 0:9858347c382d 354 }
pasky 0:9858347c382d 355
pasky 0:9858347c382d 356 const char *
pasky 0:9858347c382d 357 PubNub::origin_hostname()
pasky 0:9858347c382d 358 {
pasky 0:9858347c382d 359 /* TODO: More generic URL handling */
pasky 0:9858347c382d 360 return m_origin + strlen("http://");
pasky 0:9858347c382d 361 }
pasky 0:9858347c382d 362
pasky 0:9858347c382d 363
pasky 0:9858347c382d 364 PubNubRes
pasky 0:9858347c382d 365 PubNub::publish(const char *channel, const char *message, char **reply)
pasky 0:9858347c382d 366 {
pasky 0:9858347c382d 367 PubNubHTTP http;
pasky 0:9858347c382d 368 PubNubRes res = http.http_connect(origin_hostname());
pasky 0:9858347c382d 369 if (res != PNR_OK)
embeddedartists 7:55eb53c78b47 370 //return res;
embeddedartists 7:55eb53c78b47 371 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 372
embeddedartists 7:55eb53c78b47 373 #ifdef USE_ORIGINAL_CODE
pasky 0:9858347c382d 374 http.sendstr("GET /publish/");
pasky 0:9858347c382d 375 http.sendstr(m_publish_key);
pasky 0:9858347c382d 376 http.sendstr("/");
pasky 0:9858347c382d 377 http.sendstr(m_subscribe_key);
pasky 0:9858347c382d 378 http.sendstr("/0/");
pasky 0:9858347c382d 379 http.sendstr(channel);
pasky 0:9858347c382d 380 http.sendstr("/0/");
pasky 0:9858347c382d 381 http.sendstr_urlenc(message);
embeddedartists 7:55eb53c78b47 382 #else
embeddedartists 7:55eb53c78b47 383 char* buff = (char*)malloc(2000);
embeddedartists 7:55eb53c78b47 384 int len = sprintf(buff, "GET /publish/%s/%s/0/%s/0/",m_publish_key,m_subscribe_key,channel);
embeddedartists 7:55eb53c78b47 385 http.prepare_urlenc(message, buff+len);
embeddedartists 7:55eb53c78b47 386 http.sendstr(buff);
embeddedartists 7:55eb53c78b47 387 free(buff);
embeddedartists 7:55eb53c78b47 388 #endif
pasky 0:9858347c382d 389
pasky 0:9858347c382d 390 char *locreply;
pasky 0:9858347c382d 391 if (!reply)
pasky 0:9858347c382d 392 reply = &locreply;
pasky 0:9858347c382d 393 int replylen;
pasky 0:9858347c382d 394
pasky 0:9858347c382d 395 res = http.http_request_bh(origin_hostname(), reply, &replylen);
pasky 0:9858347c382d 396 if (res != PNR_OK)
embeddedartists 7:55eb53c78b47 397 //return res;
embeddedartists 7:55eb53c78b47 398 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 399 bool success = (*reply)[1] == '1' && (*reply)[2] == ',';
pasky 0:9858347c382d 400 if (reply == &locreply)
pasky 0:9858347c382d 401 free(locreply);
embeddedartists 7:55eb53c78b47 402 //return success ? PNR_OK : PNR_PUBNUB_ERROR;
embeddedartists 7:55eb53c78b47 403 PNUB_RETURN_STAT(success ? PNR_OK : PNR_PUBNUB_ERROR);
pasky 0:9858347c382d 404 }
pasky 0:9858347c382d 405
embeddedartists 7:55eb53c78b47 406 PubNubRes
embeddedartists 7:55eb53c78b47 407 PubNub::publish_urlenc(const char *channel, const char *message, char **reply)
embeddedartists 7:55eb53c78b47 408 {
embeddedartists 7:55eb53c78b47 409 PubNubHTTP http;
embeddedartists 7:55eb53c78b47 410 PubNubRes res = http.http_connect(origin_hostname());
embeddedartists 7:55eb53c78b47 411 if (res != PNR_OK)
embeddedartists 7:55eb53c78b47 412 //return res;
embeddedartists 7:55eb53c78b47 413 PNUB_RETURN_STAT(res);
embeddedartists 7:55eb53c78b47 414
embeddedartists 7:55eb53c78b47 415 #ifdef USE_ORIGINAL_CODE
embeddedartists 7:55eb53c78b47 416 http.sendstr("GET /publish/");
embeddedartists 7:55eb53c78b47 417 http.sendstr(m_publish_key);
embeddedartists 7:55eb53c78b47 418 http.sendstr("/");
embeddedartists 7:55eb53c78b47 419 http.sendstr(m_subscribe_key);
embeddedartists 7:55eb53c78b47 420 http.sendstr("/0/");
embeddedartists 7:55eb53c78b47 421 http.sendstr(channel);
embeddedartists 7:55eb53c78b47 422 http.sendstr("/0/");
embeddedartists 7:55eb53c78b47 423 http.sendstr_urlenc(message);
embeddedartists 7:55eb53c78b47 424 #else
embeddedartists 7:55eb53c78b47 425 char* buff = (char*)malloc(2000);
embeddedartists 7:55eb53c78b47 426 /*int len = */sprintf(buff, "GET /publish/%s/%s/0/%s/0/%s",m_publish_key,m_subscribe_key,channel,message);
embeddedartists 7:55eb53c78b47 427 //http.prepare_urlenc(message, buff+len);
embeddedartists 7:55eb53c78b47 428 http.sendstr(buff);
embeddedartists 7:55eb53c78b47 429 free(buff);
embeddedartists 7:55eb53c78b47 430 #endif
embeddedartists 7:55eb53c78b47 431
embeddedartists 7:55eb53c78b47 432 char *locreply;
embeddedartists 7:55eb53c78b47 433 if (!reply)
embeddedartists 7:55eb53c78b47 434 reply = &locreply;
embeddedartists 7:55eb53c78b47 435 int replylen;
embeddedartists 7:55eb53c78b47 436
embeddedartists 7:55eb53c78b47 437 res = http.http_request_bh(origin_hostname(), reply, &replylen);
embeddedartists 7:55eb53c78b47 438 if (res != PNR_OK)
embeddedartists 7:55eb53c78b47 439 //return res;
embeddedartists 7:55eb53c78b47 440 PNUB_RETURN_STAT(res);
embeddedartists 7:55eb53c78b47 441 bool success = (*reply)[1] == '1' && (*reply)[2] == ',';
embeddedartists 7:55eb53c78b47 442 if (reply == &locreply)
embeddedartists 7:55eb53c78b47 443 free(locreply);
embeddedartists 7:55eb53c78b47 444 //return success ? PNR_OK : PNR_PUBNUB_ERROR;
embeddedartists 7:55eb53c78b47 445 PNUB_RETURN_STAT(success ? PNR_OK : PNR_PUBNUB_ERROR);
embeddedartists 7:55eb53c78b47 446 }
pasky 0:9858347c382d 447
pasky 0:9858347c382d 448 PubNubRes
pasky 0:9858347c382d 449 PubNub::subscribe(const char *channel, char **reply)
pasky 0:9858347c382d 450 {
pasky 0:9858347c382d 451 if (m_replybuf) {
pasky 0:9858347c382d 452 int prevlen = strlen(m_replybuf);
pasky 0:9858347c382d 453 //DBG printf("reply (%s) %d > %d: %d\r\n", m_replybuf, prevlen, m_replylen);
pasky 0:9858347c382d 454 if (prevlen < m_replylen) {
pasky 0:9858347c382d 455 /* Next message from stash-away buffer. */
pasky 0:9858347c382d 456 /* XXX: We can be either memory-frugal or CPU-frugal
pasky 0:9858347c382d 457 * here. We choose to be memory-frugal by copying
pasky 0:9858347c382d 458 * over messages many times, but we may want to make
pasky 0:9858347c382d 459 * this configurable. */
pasky 0:9858347c382d 460 m_replylen -= prevlen + 1;
pasky 0:9858347c382d 461 memmove(m_replybuf, m_replybuf + prevlen + 1, m_replylen);
pasky 0:9858347c382d 462 m_replybuf = (char *) realloc(m_replybuf, m_replylen);
pasky 0:9858347c382d 463 *reply = m_replybuf;
pasky 0:9858347c382d 464 return PNR_OK;
pasky 0:9858347c382d 465
pasky 0:9858347c382d 466 } else {
pasky 0:9858347c382d 467 /* That's all. free() and fetch new messages. */
pasky 0:9858347c382d 468 free(m_replybuf);
pasky 0:9858347c382d 469 m_replybuf = NULL;
pasky 0:9858347c382d 470 m_replylen = 0;
pasky 0:9858347c382d 471 }
pasky 0:9858347c382d 472 }
pasky 0:9858347c382d 473
pasky 0:9858347c382d 474 PubNubHTTP http;
pasky 0:9858347c382d 475 PubNubRes res;
pasky 0:9858347c382d 476 res = http.http_connect(origin_hostname());
pasky 0:9858347c382d 477 if (res != PNR_OK)
embeddedartists 7:55eb53c78b47 478 //return res;
embeddedartists 7:55eb53c78b47 479 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 480
embeddedartists 7:55eb53c78b47 481 #ifdef USE_ORIGINAL_CODE
pasky 0:9858347c382d 482 http.sendstr("GET /subscribe/");
pasky 0:9858347c382d 483 http.sendstr(m_subscribe_key);
pasky 0:9858347c382d 484 http.sendstr("/");
pasky 0:9858347c382d 485 http.sendstr(channel);
pasky 0:9858347c382d 486 http.sendstr("/0/");
pasky 0:9858347c382d 487 http.sendstr(m_timetoken);
embeddedartists 7:55eb53c78b47 488 #else
embeddedartists 7:55eb53c78b47 489 char buff[200];
embeddedartists 7:55eb53c78b47 490 snprintf(buff, 200, "GET /subscribe/%s/%s/0/%s", m_subscribe_key, channel, m_timetoken);
embeddedartists 7:55eb53c78b47 491 http.sendstr(buff);
embeddedartists 7:55eb53c78b47 492 #endif
pasky 0:9858347c382d 493
pasky 0:9858347c382d 494 char *replybuf = NULL;
pasky 0:9858347c382d 495 int replylen;
pasky 0:9858347c382d 496 res = http.http_request_bh(origin_hostname(), &replybuf, &replylen);
pasky 0:9858347c382d 497 if (res != PNR_OK)
pasky 0:9858347c382d 498 goto error;
pasky 0:9858347c382d 499
pasky 0:9858347c382d 500 /* Process the reply, sets timetoken and m_replybuf, m_replylen. */
pasky 0:9858347c382d 501 res = subscribe_processjson(replybuf, replylen);
pasky 0:9858347c382d 502 if (res != PNR_OK)
pasky 0:9858347c382d 503 goto error;
pasky 0:9858347c382d 504 replybuf = NULL; // freed by processjosn
pasky 0:9858347c382d 505
pasky 0:9858347c382d 506 /* Split JSON array to messages. */
pasky 0:9858347c382d 507 res = split_array(m_replybuf, m_replylen);
pasky 0:9858347c382d 508 if (res != PNR_OK) {
pasky 0:9858347c382d 509 free(m_replybuf);
pasky 0:9858347c382d 510 goto error;
pasky 0:9858347c382d 511 }
pasky 0:9858347c382d 512
pasky 0:9858347c382d 513 *reply = m_replybuf;
pasky 0:9858347c382d 514 return res;
pasky 0:9858347c382d 515
pasky 0:9858347c382d 516 error:
pasky 0:9858347c382d 517 if (res == PNR_FORMAT_ERROR) {
pasky 0:9858347c382d 518 /* In case of PubNub protocol error, abort an ongoing
pasky 0:9858347c382d 519 * subscribe and start over. This means some messages
pasky 0:9858347c382d 520 * were lost, but allows us to recover from bad
pasky 0:9858347c382d 521 * situations, e.g. too many messages queued or
pasky 0:9858347c382d 522 * unexpected problem caused by a particular message. */
pasky 0:9858347c382d 523 strcpy(m_timetoken, "0");
pasky 0:9858347c382d 524 }
pasky 0:9858347c382d 525 if (reply)
pasky 0:9858347c382d 526 free(reply);
pasky 0:9858347c382d 527 m_replybuf = NULL;
pasky 0:9858347c382d 528 m_replylen = 0;
embeddedartists 7:55eb53c78b47 529 //return res;
embeddedartists 7:55eb53c78b47 530 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 531 }
pasky 0:9858347c382d 532
pasky 0:9858347c382d 533 PubNubRes
pasky 0:9858347c382d 534 PubNub::subscribe_processjson(char *reply, int replylen)
pasky 0:9858347c382d 535 {
pasky 0:9858347c382d 536 if (reply[0] != '[' || reply[replylen-1] != ']'
pasky 0:9858347c382d 537 || reply[replylen-2] != '"') {
pasky 0:9858347c382d 538 DBG printf("bad reply '%s'\r\n", reply);
embeddedartists 7:55eb53c78b47 539 //return PNR_FORMAT_ERROR;
embeddedartists 7:55eb53c78b47 540 PNUB_RETURN_STAT(PNR_FORMAT_ERROR);
pasky 0:9858347c382d 541 }
pasky 0:9858347c382d 542
pasky 0:9858347c382d 543 /* Extract timetoken. */
pasky 0:9858347c382d 544 reply[replylen-2] = 0;
pasky 0:9858347c382d 545 int i;
pasky 0:9858347c382d 546 for (i = replylen-3; i > 0 && i > int(replylen-3 - (sizeof(m_timetoken)-1)); i--)
pasky 0:9858347c382d 547 if (reply[i] == '"')
pasky 0:9858347c382d 548 break;
pasky 0:9858347c382d 549 if (!i || reply[i-1] != ',' || replylen-2 - (i+1) >= 64) {
pasky 0:9858347c382d 550 DBG printf("bad reply '%s'\r\n", reply);
embeddedartists 7:55eb53c78b47 551 //return PNR_FORMAT_ERROR;
embeddedartists 7:55eb53c78b47 552 PNUB_RETURN_STAT(PNR_FORMAT_ERROR);
pasky 0:9858347c382d 553 }
pasky 0:9858347c382d 554 strcpy(m_timetoken, &reply[i+1]);
pasky 0:9858347c382d 555 reply[i-1] = 0; // terminate the [] message array
pasky 0:9858347c382d 556
pasky 0:9858347c382d 557 /* Empty reply? */
pasky 0:9858347c382d 558 if (i == 4) { /* "[[]" */
pasky 0:9858347c382d 559 free(reply);
pasky 0:9858347c382d 560 m_replybuf = NULL;
pasky 0:9858347c382d 561 m_replylen = 0;
pasky 0:9858347c382d 562 return PNR_OK;
pasky 0:9858347c382d 563 }
pasky 0:9858347c382d 564
pasky 0:9858347c382d 565 /* Extract the messages array. */
pasky 0:9858347c382d 566 if (reply[1] != '[' || reply[i-2] != ']') {
pasky 0:9858347c382d 567 DBG printf("bad reply end '%s'\r\n", reply);
embeddedartists 7:55eb53c78b47 568 //return PNR_FORMAT_ERROR;
embeddedartists 7:55eb53c78b47 569 PNUB_RETURN_STAT(PNR_FORMAT_ERROR);
pasky 0:9858347c382d 570 }
pasky 0:9858347c382d 571 reply[i-2] = 0;
pasky 0:9858347c382d 572
pasky 0:9858347c382d 573 /* Shrink memory buffer to bare minimum. */
pasky 0:9858347c382d 574 memmove(reply, reply + 2, i-2-2);
pasky 0:9858347c382d 575 m_replylen = i-2-2;
pasky 0:9858347c382d 576 m_replybuf = (char *) realloc(reply, m_replylen);
pasky 0:9858347c382d 577
pasky 0:9858347c382d 578 return PNR_OK;
pasky 0:9858347c382d 579 }
pasky 0:9858347c382d 580
pasky 0:9858347c382d 581
pasky 0:9858347c382d 582 PubNubRes
pasky 0:9858347c382d 583 PubNub::history(const char *channel, char **reply, int *replysize, int limit)
pasky 0:9858347c382d 584 {
pasky 0:9858347c382d 585 PubNubHTTP http;
pasky 0:9858347c382d 586 PubNubRes res;
pasky 0:9858347c382d 587 res = http.http_connect(origin_hostname());
pasky 0:9858347c382d 588 if (res != PNR_OK)
embeddedartists 7:55eb53c78b47 589 //return res;
embeddedartists 7:55eb53c78b47 590 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 591
embeddedartists 7:55eb53c78b47 592 #ifdef USE_ORIGINAL_CODE
pasky 0:9858347c382d 593 http.sendstr("GET /history/");
pasky 0:9858347c382d 594 http.sendstr(m_subscribe_key);
pasky 0:9858347c382d 595 http.sendstr("/");
pasky 0:9858347c382d 596 http.sendstr(channel);
pasky 0:9858347c382d 597 http.sendstr("/0/");
pasky 0:9858347c382d 598 char limitbuf[8]; snprintf(limitbuf, sizeof(limitbuf), "%d", limit);
pasky 0:9858347c382d 599 http.sendstr(limitbuf);
embeddedartists 7:55eb53c78b47 600 #else
embeddedartists 7:55eb53c78b47 601 char buff[200];
embeddedartists 7:55eb53c78b47 602 snprintf(buff, 200, "GET /history/%s/%s/0/%d", m_subscribe_key, channel, limit);
embeddedartists 7:55eb53c78b47 603 http.sendstr(buff);
embeddedartists 7:55eb53c78b47 604 #endif
pasky 0:9858347c382d 605
pasky 0:9858347c382d 606 char *replybuf = NULL;
pasky 0:9858347c382d 607 int replylen;
pasky 0:9858347c382d 608 res = http.http_request_bh(origin_hostname(), &replybuf, &replylen);
pasky 0:9858347c382d 609 if (res != PNR_OK)
pasky 0:9858347c382d 610 goto error;
pasky 0:9858347c382d 611
pasky 0:9858347c382d 612 /* Extract from the array and split it. */
pasky 0:9858347c382d 613
pasky 0:9858347c382d 614 if (replybuf[0] != '[' || replybuf[replylen-1] != ']') {
pasky 0:9858347c382d 615 res = PNR_FORMAT_ERROR;
pasky 0:9858347c382d 616 goto error;
pasky 0:9858347c382d 617 }
pasky 0:9858347c382d 618
pasky 0:9858347c382d 619 replylen -= 2;
pasky 0:9858347c382d 620 if (replylen == 0) { /* The reply was [] */
pasky 0:9858347c382d 621 free(replybuf);
pasky 0:9858347c382d 622 *reply = NULL;
pasky 0:9858347c382d 623 *replysize = 0;
pasky 0:9858347c382d 624 return PNR_OK;
pasky 0:9858347c382d 625 }
pasky 0:9858347c382d 626
pasky 0:9858347c382d 627 memmove(replybuf, replybuf + 1, replylen);
pasky 0:9858347c382d 628 replybuf[replylen] = 0;
pasky 0:9858347c382d 629
pasky 0:9858347c382d 630 res = split_array(replybuf, replylen);
pasky 0:9858347c382d 631 if (res != PNR_OK)
pasky 0:9858347c382d 632 goto error;
pasky 0:9858347c382d 633
pasky 0:9858347c382d 634 *reply = replybuf;
pasky 0:9858347c382d 635 *replysize = replylen;
pasky 0:9858347c382d 636 return PNR_OK;
pasky 0:9858347c382d 637
pasky 0:9858347c382d 638 error:
pasky 0:9858347c382d 639 free(replybuf);
embeddedartists 7:55eb53c78b47 640 //return res;
embeddedartists 7:55eb53c78b47 641 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 642 }
pasky 0:9858347c382d 643
pasky 0:9858347c382d 644
pasky 0:9858347c382d 645 PubNubRes
pasky 0:9858347c382d 646 PubNub::time(char *ts)
pasky 0:9858347c382d 647 {
pasky 0:9858347c382d 648 PubNubHTTP http;
pasky 0:9858347c382d 649 PubNubRes res = http.http_connect(origin_hostname());
pasky 0:9858347c382d 650 if (res != PNR_OK)
embeddedartists 7:55eb53c78b47 651 //return res;
embeddedartists 7:55eb53c78b47 652 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 653
pasky 0:9858347c382d 654 http.sendstr("GET /time/0");
pasky 0:9858347c382d 655
pasky 0:9858347c382d 656 char *reply;
pasky 0:9858347c382d 657 int replylen;
pasky 0:9858347c382d 658 res = http.http_request_bh(origin_hostname(), &reply, &replylen);
pasky 0:9858347c382d 659 if (res != PNR_OK)
embeddedartists 7:55eb53c78b47 660 //return res;
embeddedartists 7:55eb53c78b47 661 PNUB_RETURN_STAT(res);
pasky 0:9858347c382d 662
pasky 0:9858347c382d 663 if (replylen < 3 || replylen > 32 || reply[0] != '[' || reply[replylen-1] != ']') {
pasky 0:9858347c382d 664 free(reply);
embeddedartists 7:55eb53c78b47 665 //return PNR_FORMAT_ERROR;
embeddedartists 7:55eb53c78b47 666 PNUB_RETURN_STAT(PNR_FORMAT_ERROR);
pasky 0:9858347c382d 667 }
pasky 0:9858347c382d 668
pasky 0:9858347c382d 669 replylen -= 2;
pasky 0:9858347c382d 670 memcpy(ts, reply + 1, replylen);
pasky 0:9858347c382d 671 ts[replylen] = 0;
pasky 0:9858347c382d 672
pasky 0:9858347c382d 673 free(reply);
pasky 0:9858347c382d 674 return PNR_OK;
embeddedartists 7:55eb53c78b47 675 }