http://mbed.org/users/okini3939/notebook/comet_websocket/

Dependencies:   EthernetNetIf mbed RingBuffer MbedJSONValue

Committer:
okini3939
Date:
Sat Nov 19 16:19:50 2011 +0000
Revision:
0:632cb8c03ca3

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 0:632cb8c03ca3 1 /*
okini3939 0:632cb8c03ca3 2 * mbed pseudo Comet HTTP Client
okini3939 0:632cb8c03ca3 3 * Copyright (c) 2011 Hiroshi Suga
okini3939 0:632cb8c03ca3 4 * Released under the MIT License: http://mbed.org/license/mit
okini3939 0:632cb8c03ca3 5 */
okini3939 0:632cb8c03ca3 6
okini3939 0:632cb8c03ca3 7 /** @file
okini3939 0:632cb8c03ca3 8 * @brief pseudo Comet HTTP Client
okini3939 0:632cb8c03ca3 9 */
okini3939 0:632cb8c03ca3 10
okini3939 0:632cb8c03ca3 11 #include "mbed.h"
okini3939 0:632cb8c03ca3 12 #include "EthernetNetIf.h"
okini3939 0:632cb8c03ca3 13 #include "TCPSocket.h"
okini3939 0:632cb8c03ca3 14 #include "DNSRequest.h"
okini3939 0:632cb8c03ca3 15 #include "RingBuffer.h"
okini3939 0:632cb8c03ca3 16 #include "CometClient.h"
okini3939 0:632cb8c03ca3 17 #include <ctype.h>
okini3939 0:632cb8c03ca3 18
okini3939 0:632cb8c03ca3 19 #define DEBUG
okini3939 0:632cb8c03ca3 20 #include "dbg.h"
okini3939 0:632cb8c03ca3 21
okini3939 0:632cb8c03ca3 22
okini3939 0:632cb8c03ca3 23 static TCPSocket *http;
okini3939 0:632cb8c03ca3 24 static volatile int tcp_ready = 0, tcp_readable = 0, tcp_writable = 0;
okini3939 0:632cb8c03ca3 25 static volatile int tcp_busy = 0, mode = 0;
okini3939 0:632cb8c03ca3 26 static volatile int dns_status = 0;
okini3939 0:632cb8c03ca3 27 static Host remote;
okini3939 0:632cb8c03ca3 28 static RingBuffer fifo(1500);
okini3939 0:632cb8c03ca3 29 static char remoteuri[100];
okini3939 0:632cb8c03ca3 30
okini3939 0:632cb8c03ca3 31
okini3939 0:632cb8c03ca3 32 // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
okini3939 0:632cb8c03ca3 33 int base64enc(const char *input, unsigned int length, char *output, int len) {
okini3939 0:632cb8c03ca3 34 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
okini3939 0:632cb8c03ca3 35 unsigned int c, c1, c2, c3;
okini3939 0:632cb8c03ca3 36
okini3939 0:632cb8c03ca3 37 if (len < ((((length-1)/3)+1)<<2)) return -1;
okini3939 0:632cb8c03ca3 38 for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
okini3939 0:632cb8c03ca3 39 c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
okini3939 0:632cb8c03ca3 40 c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
okini3939 0:632cb8c03ca3 41 c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;
okini3939 0:632cb8c03ca3 42
okini3939 0:632cb8c03ca3 43 c = ((c1 & 0xFC) >> 2);
okini3939 0:632cb8c03ca3 44 output[j+0] = base64[c];
okini3939 0:632cb8c03ca3 45 c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
okini3939 0:632cb8c03ca3 46 output[j+1] = base64[c];
okini3939 0:632cb8c03ca3 47 c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
okini3939 0:632cb8c03ca3 48 output[j+2] = (length>i+1)?base64[c]:'=';
okini3939 0:632cb8c03ca3 49 c = (c3 & 0x3F);
okini3939 0:632cb8c03ca3 50 output[j+3] = (length>i+2)?base64[c]:'=';
okini3939 0:632cb8c03ca3 51 }
okini3939 0:632cb8c03ca3 52 output[(((length-1)/3)+1)<<2] = '\0';
okini3939 0:632cb8c03ca3 53 return 0;
okini3939 0:632cb8c03ca3 54 }
okini3939 0:632cb8c03ca3 55
okini3939 0:632cb8c03ca3 56 // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
okini3939 0:632cb8c03ca3 57 int urlencode(char *str, char *buf, int len) {
okini3939 0:632cb8c03ca3 58 static const char to_hex[] = "0123456789ABCDEF";
okini3939 0:632cb8c03ca3 59 // char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf;
okini3939 0:632cb8c03ca3 60 char *pstr = str, *pbuf = buf;
okini3939 0:632cb8c03ca3 61
okini3939 0:632cb8c03ca3 62 if (len < (strlen(str) * 3 + 1)) return -1;
okini3939 0:632cb8c03ca3 63 while (*pstr) {
okini3939 0:632cb8c03ca3 64 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') {
okini3939 0:632cb8c03ca3 65 *pbuf++ = *pstr;
okini3939 0:632cb8c03ca3 66 } else if (*pstr == ' ') {
okini3939 0:632cb8c03ca3 67 *pbuf++ = '+';
okini3939 0:632cb8c03ca3 68 } else {
okini3939 0:632cb8c03ca3 69 *pbuf++ = '%';
okini3939 0:632cb8c03ca3 70 *pbuf++ = to_hex[(*pstr >> 4) & 0x0f];
okini3939 0:632cb8c03ca3 71 *pbuf++ = to_hex[*pstr & 0x0f];
okini3939 0:632cb8c03ca3 72 }
okini3939 0:632cb8c03ca3 73 pstr++;
okini3939 0:632cb8c03ca3 74 }
okini3939 0:632cb8c03ca3 75 *pbuf = '\0';
okini3939 0:632cb8c03ca3 76 return 0;
okini3939 0:632cb8c03ca3 77 }
okini3939 0:632cb8c03ca3 78
okini3939 0:632cb8c03ca3 79
okini3939 0:632cb8c03ca3 80 void isr_http (TCPSocketEvent e) {
okini3939 0:632cb8c03ca3 81
okini3939 0:632cb8c03ca3 82 DBG("http(%d)\r\n", e);
okini3939 0:632cb8c03ca3 83 switch(e) {
okini3939 0:632cb8c03ca3 84 case TCPSOCKET_CONNECTED:
okini3939 0:632cb8c03ca3 85 tcp_ready = 1;
okini3939 0:632cb8c03ca3 86 tcp_busy = 0;
okini3939 0:632cb8c03ca3 87 mode = 0;
okini3939 0:632cb8c03ca3 88 break;
okini3939 0:632cb8c03ca3 89
okini3939 0:632cb8c03ca3 90 case TCPSOCKET_READABLE: //Incoming data
okini3939 0:632cb8c03ca3 91 {
okini3939 0:632cb8c03ca3 92 char buf[1500];
okini3939 0:632cb8c03ca3 93 int i = 0, len;
okini3939 0:632cb8c03ca3 94
okini3939 0:632cb8c03ca3 95 len = http->recv(buf, sizeof(buf));
okini3939 0:632cb8c03ca3 96 for (i = 0; i < len; i ++) {
okini3939 0:632cb8c03ca3 97 switch (mode) {
okini3939 0:632cb8c03ca3 98 case 0:
okini3939 0:632cb8c03ca3 99 if (strncmp(buf, "HTTP/", 5) == 0 && atoi(&buf[9]) == 200) {
okini3939 0:632cb8c03ca3 100 mode = 1;
okini3939 0:632cb8c03ca3 101 }
okini3939 0:632cb8c03ca3 102 break;
okini3939 0:632cb8c03ca3 103 case 1:
okini3939 0:632cb8c03ca3 104 case 2:
okini3939 0:632cb8c03ca3 105 if (buf[i] == '\r') {
okini3939 0:632cb8c03ca3 106 mode ++;
okini3939 0:632cb8c03ca3 107 } else
okini3939 0:632cb8c03ca3 108 if (buf[i] == '\n') {
okini3939 0:632cb8c03ca3 109 } else {
okini3939 0:632cb8c03ca3 110 mode = 1;
okini3939 0:632cb8c03ca3 111 }
okini3939 0:632cb8c03ca3 112 break;
okini3939 0:632cb8c03ca3 113 case 3:
okini3939 0:632cb8c03ca3 114 if (buf[i] == 0x7f) {
okini3939 0:632cb8c03ca3 115 mode = 4;
okini3939 0:632cb8c03ca3 116 }
okini3939 0:632cb8c03ca3 117 break;
okini3939 0:632cb8c03ca3 118 case 4:
okini3939 0:632cb8c03ca3 119 fifo.put(buf[i]);
okini3939 0:632cb8c03ca3 120 break;
okini3939 0:632cb8c03ca3 121 }
okini3939 0:632cb8c03ca3 122 }
okini3939 0:632cb8c03ca3 123 } // Incoming data
okini3939 0:632cb8c03ca3 124 tcp_readable = 1;
okini3939 0:632cb8c03ca3 125 break;
okini3939 0:632cb8c03ca3 126
okini3939 0:632cb8c03ca3 127 case TCPSOCKET_WRITEABLE: //We can send data
okini3939 0:632cb8c03ca3 128 tcp_writable = 1;
okini3939 0:632cb8c03ca3 129 break;
okini3939 0:632cb8c03ca3 130
okini3939 0:632cb8c03ca3 131 case TCPSOCKET_CONTIMEOUT:
okini3939 0:632cb8c03ca3 132 case TCPSOCKET_CONRST:
okini3939 0:632cb8c03ca3 133 case TCPSOCKET_CONABRT:
okini3939 0:632cb8c03ca3 134 case TCPSOCKET_ERROR:
okini3939 0:632cb8c03ca3 135 case TCPSOCKET_DISCONNECTED:
okini3939 0:632cb8c03ca3 136 http->close();
okini3939 0:632cb8c03ca3 137 tcp_ready = 0;
okini3939 0:632cb8c03ca3 138 tcp_readable = 0;
okini3939 0:632cb8c03ca3 139 tcp_writable = 0;
okini3939 0:632cb8c03ca3 140 tcp_busy = 0;
okini3939 0:632cb8c03ca3 141 break;
okini3939 0:632cb8c03ca3 142 }
okini3939 0:632cb8c03ca3 143 }
okini3939 0:632cb8c03ca3 144
okini3939 0:632cb8c03ca3 145 void createauth (char *user, char *pwd, char *buf, int len) {
okini3939 0:632cb8c03ca3 146 char tmp[80];
okini3939 0:632cb8c03ca3 147
okini3939 0:632cb8c03ca3 148 strncpy(buf, "Authorization: Basic ", len);
okini3939 0:632cb8c03ca3 149 snprintf(tmp, sizeof(tmp), "%s:%s", user, pwd);
okini3939 0:632cb8c03ca3 150 base64enc(tmp, strlen(tmp), &buf[strlen(buf)], len - strlen(buf));
okini3939 0:632cb8c03ca3 151 strncat(buf, "\r\n", len - strlen(buf));
okini3939 0:632cb8c03ca3 152 }
okini3939 0:632cb8c03ca3 153
okini3939 0:632cb8c03ca3 154 void isr_dns (DNSReply r) {
okini3939 0:632cb8c03ca3 155
okini3939 0:632cb8c03ca3 156 DBG("dns(%d)\r\n", r);
okini3939 0:632cb8c03ca3 157 if (DNS_FOUND) {
okini3939 0:632cb8c03ca3 158 dns_status = 1;
okini3939 0:632cb8c03ca3 159 } else {
okini3939 0:632cb8c03ca3 160 dns_status = -1;
okini3939 0:632cb8c03ca3 161 }
okini3939 0:632cb8c03ca3 162 }
okini3939 0:632cb8c03ca3 163
okini3939 0:632cb8c03ca3 164 void pollComet () {
okini3939 0:632cb8c03ca3 165 Net::poll();
okini3939 0:632cb8c03ca3 166
okini3939 0:632cb8c03ca3 167 if (! tcp_ready && ! tcp_busy) {
okini3939 0:632cb8c03ca3 168 tcp_busy = 1;
okini3939 0:632cb8c03ca3 169 openComet(NULL, NULL, NULL, NULL);
okini3939 0:632cb8c03ca3 170 }
okini3939 0:632cb8c03ca3 171 }
okini3939 0:632cb8c03ca3 172
okini3939 0:632cb8c03ca3 173 int recvComet (char *buf, int size) {
okini3939 0:632cb8c03ca3 174 int i, len;
okini3939 0:632cb8c03ca3 175
okini3939 0:632cb8c03ca3 176 len = fifo.use();
okini3939 0:632cb8c03ca3 177 if (len == 0) return 0;
okini3939 0:632cb8c03ca3 178 DBG("readComet %d\r\n", len);
okini3939 0:632cb8c03ca3 179 if (len > size) len = size;
okini3939 0:632cb8c03ca3 180
okini3939 0:632cb8c03ca3 181 for (i = 0; i < len; i ++) {
okini3939 0:632cb8c03ca3 182 if (fifo.get(&buf[i])) break;
okini3939 0:632cb8c03ca3 183 }
okini3939 0:632cb8c03ca3 184 tcp_readable = 0;
okini3939 0:632cb8c03ca3 185 return len;
okini3939 0:632cb8c03ca3 186 }
okini3939 0:632cb8c03ca3 187
okini3939 0:632cb8c03ca3 188 int sendComet (char *buf) {
okini3939 0:632cb8c03ca3 189 while (tcp_busy) {
okini3939 0:632cb8c03ca3 190 Net::poll();
okini3939 0:632cb8c03ca3 191 }
okini3939 0:632cb8c03ca3 192
okini3939 0:632cb8c03ca3 193 tcp_busy = 1;
okini3939 0:632cb8c03ca3 194 if (tcp_ready) {
okini3939 0:632cb8c03ca3 195 DBG("sendComet close\r\n");
okini3939 0:632cb8c03ca3 196 http->close();
okini3939 0:632cb8c03ca3 197 }
okini3939 0:632cb8c03ca3 198 DBG("sendComet open\r\n");
okini3939 0:632cb8c03ca3 199 openComet(NULL, NULL, NULL, buf);
okini3939 0:632cb8c03ca3 200 return 0;
okini3939 0:632cb8c03ca3 201 }
okini3939 0:632cb8c03ca3 202
okini3939 0:632cb8c03ca3 203 int openComet (Host *host, char *uri, char *head, char *body) {
okini3939 0:632cb8c03ca3 204 TCPSocketErr err;
okini3939 0:632cb8c03ca3 205 Timer timeout;
okini3939 0:632cb8c03ca3 206 char buf[1500];
okini3939 0:632cb8c03ca3 207
okini3939 0:632cb8c03ca3 208 tcp_busy = 1;
okini3939 0:632cb8c03ca3 209 if (host) {
okini3939 0:632cb8c03ca3 210 http = new TCPSocket;
okini3939 0:632cb8c03ca3 211 http->setOnEvent(isr_http);
okini3939 0:632cb8c03ca3 212
okini3939 0:632cb8c03ca3 213 // connect
okini3939 0:632cb8c03ca3 214 if (host->getIp().isNull()) {
okini3939 0:632cb8c03ca3 215 // resolv
okini3939 0:632cb8c03ca3 216 DNSRequest dns;
okini3939 0:632cb8c03ca3 217 dns_status = 0;
okini3939 0:632cb8c03ca3 218 dns.setOnReply(isr_dns);
okini3939 0:632cb8c03ca3 219 if (dns.resolve(host) != DNS_OK) goto exit;
okini3939 0:632cb8c03ca3 220 timeout.reset();
okini3939 0:632cb8c03ca3 221 timeout.start();
okini3939 0:632cb8c03ca3 222 while (timeout.read_ms() < HTTP_TIMEOUT) {
okini3939 0:632cb8c03ca3 223 if (dns_status) break;
okini3939 0:632cb8c03ca3 224 Net::poll();
okini3939 0:632cb8c03ca3 225 }
okini3939 0:632cb8c03ca3 226 timeout.stop();
okini3939 0:632cb8c03ca3 227 if (dns_status <= 0) goto exit;
okini3939 0:632cb8c03ca3 228 DBG("%s [%d.%d.%d.%d]\r\n", host->getName(), (unsigned char)host->getIp()[0], (unsigned char)host->getIp()[1], (unsigned char)host->getIp()[2], (unsigned char)host->getIp()[3]);
okini3939 0:632cb8c03ca3 229 }
okini3939 0:632cb8c03ca3 230 if (! host->getPort()) {
okini3939 0:632cb8c03ca3 231 host->setPort(HTTP_PORT);
okini3939 0:632cb8c03ca3 232 }
okini3939 0:632cb8c03ca3 233
okini3939 0:632cb8c03ca3 234 remote = *host;
okini3939 0:632cb8c03ca3 235 strncpy(remoteuri, uri, sizeof(remoteuri));
okini3939 0:632cb8c03ca3 236 } // if (host)
okini3939 0:632cb8c03ca3 237
okini3939 0:632cb8c03ca3 238 err = http->connect(remote);
okini3939 0:632cb8c03ca3 239 if (err != TCPSOCKET_OK) goto exit;
okini3939 0:632cb8c03ca3 240
okini3939 0:632cb8c03ca3 241 // wait connect
okini3939 0:632cb8c03ca3 242 timeout.reset();
okini3939 0:632cb8c03ca3 243 timeout.start();
okini3939 0:632cb8c03ca3 244 while (timeout.read_ms() < HTTP_TIMEOUT) {
okini3939 0:632cb8c03ca3 245 if (tcp_ready) break;
okini3939 0:632cb8c03ca3 246 Net::poll();
okini3939 0:632cb8c03ca3 247 }
okini3939 0:632cb8c03ca3 248 timeout.stop();
okini3939 0:632cb8c03ca3 249 if (! tcp_ready) goto exit;
okini3939 0:632cb8c03ca3 250
okini3939 0:632cb8c03ca3 251 // send request
okini3939 0:632cb8c03ca3 252 http->send("POST ", 5);
okini3939 0:632cb8c03ca3 253 http->send(remoteuri, strlen(remoteuri));
okini3939 0:632cb8c03ca3 254 http->send(" HTTP/1.1\r\nHost: ", 17);
okini3939 0:632cb8c03ca3 255 http->send(remote.getName(), strlen(remote.getName()));
okini3939 0:632cb8c03ca3 256 http->send("\r\n", 2);
okini3939 0:632cb8c03ca3 257 http->send("Connection: close\r\n", 19);
okini3939 0:632cb8c03ca3 258 http->send("Content-type: application/x-www-form-urlencoded\r\n", 49);
okini3939 0:632cb8c03ca3 259 if (head) {
okini3939 0:632cb8c03ca3 260 http->send(head, strlen(head));
okini3939 0:632cb8c03ca3 261 }
okini3939 0:632cb8c03ca3 262 sprintf(buf, "Content-Length: %d\r\n", strlen(body));
okini3939 0:632cb8c03ca3 263 http->send(buf, strlen(buf));
okini3939 0:632cb8c03ca3 264 http->send("\r\n", 2);
okini3939 0:632cb8c03ca3 265
okini3939 0:632cb8c03ca3 266 // post method
okini3939 0:632cb8c03ca3 267 if (body) {
okini3939 0:632cb8c03ca3 268 http->send(body, strlen(body));
okini3939 0:632cb8c03ca3 269 }
okini3939 0:632cb8c03ca3 270
okini3939 0:632cb8c03ca3 271 Net::poll();
okini3939 0:632cb8c03ca3 272 return 0;
okini3939 0:632cb8c03ca3 273
okini3939 0:632cb8c03ca3 274 exit:
okini3939 0:632cb8c03ca3 275 http->resetOnEvent();
okini3939 0:632cb8c03ca3 276 http->close();
okini3939 0:632cb8c03ca3 277 delete http;
okini3939 0:632cb8c03ca3 278
okini3939 0:632cb8c03ca3 279 return -1;
okini3939 0:632cb8c03ca3 280 }