SocketIO is a compatibility library on top of the MBED Websockets API. Currently the broadcast paradigm is supported. There is much more to the SocketIO spec that could be built into this API. Have fun!
Dependents: df-2013-thermostat-handson df-2013-minihack-thermostat-complete df-2013-minihack-thermostat df-2013-thermostat-remotes ... more
SocketIO.cpp@11:b32005b69b5c, 2013-11-08 (annotated)
- Committer:
- ansond
- Date:
- Fri Nov 08 20:10:26 2013 +0000
- Revision:
- 11:b32005b69b5c
- Parent:
- 9:4f02450a402a
- Child:
- 12:8fe60d9ca3bf
fixed buffer overrrun
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ansond | 0:5e68215d973a | 1 | #include "SocketIO.h" |
ansond | 0:5e68215d973a | 2 | |
ansond | 0:5e68215d973a | 3 | // constructor |
ansond | 0:5e68215d973a | 4 | SocketIO::SocketIO(char * myurl) { |
ansond | 0:5e68215d973a | 5 | // prepare the sessionkey URL |
ansond | 0:5e68215d973a | 6 | this->prepareSessionKeyURL(myurl, DEFAULT_VERSION); |
ansond | 0:5e68215d973a | 7 | } |
ansond | 0:5e68215d973a | 8 | |
ansond | 0:5e68215d973a | 9 | // constructor |
ansond | 0:5e68215d973a | 10 | SocketIO::SocketIO(char * myurl, int myversion) { |
ansond | 0:5e68215d973a | 11 | // prepare the sessionkey URL |
ansond | 0:5e68215d973a | 12 | this->prepareSessionKeyURL(myurl, myversion); |
ansond | 0:5e68215d973a | 13 | } |
ansond | 0:5e68215d973a | 14 | |
ansond | 0:5e68215d973a | 15 | // connect to the SocketIO server |
ansond | 0:5e68215d973a | 16 | bool SocketIO::connect() { |
ansond | 0:5e68215d973a | 17 | bool connected = this->is_connected(); |
ansond | 0:5e68215d973a | 18 | |
ansond | 0:5e68215d973a | 19 | // make sure we are not already connected |
ansond | 0:5e68215d973a | 20 | if (connected == false) { |
ansond | 0:5e68215d973a | 21 | // first we must acquire the session key |
ansond | 0:5e68215d973a | 22 | bool connected = this->acquireSessionKey(); |
ansond | 0:5e68215d973a | 23 | |
ansond | 0:5e68215d973a | 24 | // next we must create a new URL to connect to with the session key |
ansond | 0:5e68215d973a | 25 | if (connected == true) { |
ansond | 0:5e68215d973a | 26 | // create our session URL |
ansond | 0:5e68215d973a | 27 | this->prepareSessionURL(); |
ansond | 0:5e68215d973a | 28 | |
ansond | 0:5e68215d973a | 29 | // allocate our websocket endpoint |
ansond | 0:5e68215d973a | 30 | this->ws = new Websocket(this->url_session); |
ansond | 0:5e68215d973a | 31 | |
ansond | 0:5e68215d973a | 32 | // connect! |
ansond | 0:5e68215d973a | 33 | connected = this->attemptWebSocketConnect(); |
ansond | 0:5e68215d973a | 34 | } |
ansond | 0:5e68215d973a | 35 | } |
ansond | 0:5e68215d973a | 36 | |
ansond | 0:5e68215d973a | 37 | // return our connection status |
ansond | 0:5e68215d973a | 38 | return connected; |
ansond | 0:5e68215d973a | 39 | } |
ansond | 0:5e68215d973a | 40 | |
ansond | 0:5e68215d973a | 41 | // gracefully disconnect from the SocketIO server |
ansond | 0:5e68215d973a | 42 | bool SocketIO::close() { |
ansond | 0:5e68215d973a | 43 | bool closed = false; |
ansond | 0:5e68215d973a | 44 | |
ansond | 0:5e68215d973a | 45 | // if we are connected lets disconnect |
ansond | 0:5e68215d973a | 46 | if (this->ws != NULL) { |
ansond | 2:2979735cb379 | 47 | this->ws->send("0::"); |
ansond | 0:5e68215d973a | 48 | this->ws->close(); |
ansond | 0:5e68215d973a | 49 | closed = this->ws->is_connected(); |
ansond | 0:5e68215d973a | 50 | } |
ansond | 0:5e68215d973a | 51 | |
ansond | 0:5e68215d973a | 52 | // now clean up memory |
ansond | 0:5e68215d973a | 53 | if (this->ws != NULL) delete this->ws; |
ansond | 0:5e68215d973a | 54 | if (this->url_session != NULL) delete this->url_session; |
ansond | 0:5e68215d973a | 55 | if (this->url_session_key != NULL) delete this->url_session_key; |
ansond | 0:5e68215d973a | 56 | if (this->session_key != NULL) delete this->session_key; |
ansond | 0:5e68215d973a | 57 | if (this->ws_channel != NULL) delete this->ws_channel; |
ansond | 0:5e68215d973a | 58 | |
ansond | 0:5e68215d973a | 59 | // return our status |
ansond | 0:5e68215d973a | 60 | return closed; |
ansond | 0:5e68215d973a | 61 | } |
ansond | 0:5e68215d973a | 62 | |
ansond | 0:5e68215d973a | 63 | // emit a message (broadcast) to the SocketIO server |
ansond | 0:5e68215d973a | 64 | int SocketIO::emit(char *name, char * args) { |
ansond | 0:5e68215d973a | 65 | int bytesSent = 0; |
ansond | 0:5e68215d973a | 66 | |
ansond | 0:5e68215d973a | 67 | // only emit if we are connected |
ansond | 0:5e68215d973a | 68 | if (this->is_connected() == true) { |
ansond | 0:5e68215d973a | 69 | // prepare the JSON message for SocketIO |
ansond | 11:b32005b69b5c | 70 | char buffer[512]; |
ansond | 0:5e68215d973a | 71 | char *json = this->prepareSocketIOJSONMessage(name,args,buffer); |
ansond | 0:5e68215d973a | 72 | |
ansond | 3:529ce2bcfe77 | 73 | // send a heartbeat |
ansond | 9:4f02450a402a | 74 | bytesSent = this->ws->send("2::"); |
ansond | 3:529ce2bcfe77 | 75 | |
ansond | 0:5e68215d973a | 76 | // send the message |
ansond | 9:4f02450a402a | 77 | if (bytesSent > 0) bytesSent = this->ws->send(json); |
ansond | 0:5e68215d973a | 78 | } |
ansond | 0:5e68215d973a | 79 | |
ansond | 0:5e68215d973a | 80 | return bytesSent; |
ansond | 0:5e68215d973a | 81 | } |
ansond | 0:5e68215d973a | 82 | |
ansond | 0:5e68215d973a | 83 | // read a message from the SocketIO server |
ansond | 0:5e68215d973a | 84 | bool SocketIO::read(char * message) { |
ansond | 0:5e68215d973a | 85 | bool didRead = false; |
ansond | 0:5e68215d973a | 86 | |
ansond | 0:5e68215d973a | 87 | // only read if we are connected |
ansond | 0:5e68215d973a | 88 | if (this->is_connected() == true && message != NULL) { |
ansond | 0:5e68215d973a | 89 | // attempt a read |
ansond | 0:5e68215d973a | 90 | didRead = this->ws->read(message); |
ansond | 0:5e68215d973a | 91 | } |
ansond | 0:5e68215d973a | 92 | |
ansond | 0:5e68215d973a | 93 | // return our status |
ansond | 0:5e68215d973a | 94 | return didRead; |
ansond | 0:5e68215d973a | 95 | } |
ansond | 0:5e68215d973a | 96 | |
ansond | 0:5e68215d973a | 97 | // Are we connected? |
ansond | 0:5e68215d973a | 98 | bool SocketIO::is_connected() { |
ansond | 0:5e68215d973a | 99 | bool isConnected = false; |
ansond | 0:5e68215d973a | 100 | |
ansond | 0:5e68215d973a | 101 | // if we have an endpoint - get its connection status |
ansond | 0:5e68215d973a | 102 | if (this->ws != NULL) isConnected = this->ws->is_connected(); |
ansond | 0:5e68215d973a | 103 | |
ansond | 0:5e68215d973a | 104 | return isConnected; |
ansond | 0:5e68215d973a | 105 | } |
ansond | 0:5e68215d973a | 106 | |
ansond | 0:5e68215d973a | 107 | // Private Methods |
ansond | 0:5e68215d973a | 108 | |
ansond | 0:5e68215d973a | 109 | // prepare a SocketIO compatible JSON packet |
ansond | 0:5e68215d973a | 110 | char *SocketIO::prepareSocketIOJSONMessage(char *name, char *args, char *buffer) { |
ansond | 7:a9bafd7a45fc | 111 | sprintf(buffer,"5:::{\"name\": \"%s\", \"args\": %s}",name, args); |
ansond | 0:5e68215d973a | 112 | return buffer; |
ansond | 0:5e68215d973a | 113 | } |
ansond | 0:5e68215d973a | 114 | |
ansond | 0:5e68215d973a | 115 | // prepare the session URL |
ansond | 0:5e68215d973a | 116 | void SocketIO::prepareSessionURL() { |
ansond | 0:5e68215d973a | 117 | // allocate the buffer |
ansond | 0:5e68215d973a | 118 | this->url_session = new char[256]; |
ansond | 0:5e68215d973a | 119 | |
ansond | 0:5e68215d973a | 120 | // fill the buffer |
ansond | 6:f71f8a61dc98 | 121 | sprintf(this->url_session,"ws://%s/socket.io/%d/%s",this->url,this->version,this->session_key); |
ansond | 0:5e68215d973a | 122 | } |
ansond | 0:5e68215d973a | 123 | |
ansond | 0:5e68215d973a | 124 | // attempt a connection via websockets |
ansond | 0:5e68215d973a | 125 | bool SocketIO::attemptWebSocketConnect() { |
ansond | 0:5e68215d973a | 126 | // attempt connect |
ansond | 0:5e68215d973a | 127 | int status = 0; |
ansond | 0:5e68215d973a | 128 | for(int i=0;i<10;++i) { |
ansond | 0:5e68215d973a | 129 | status = this->ws->connect(); |
ansond | 0:5e68215d973a | 130 | if (status != 0) i = 10; |
ansond | 0:5e68215d973a | 131 | } |
ansond | 0:5e68215d973a | 132 | |
ansond | 0:5e68215d973a | 133 | // set the socket.io connect command |
ansond | 0:5e68215d973a | 134 | if (this->ws->is_connected()) this->ws->send("1::"); |
ansond | 0:5e68215d973a | 135 | |
ansond | 0:5e68215d973a | 136 | // return connection status |
ansond | 0:5e68215d973a | 137 | return this->is_connected(); |
ansond | 0:5e68215d973a | 138 | } |
ansond | 0:5e68215d973a | 139 | |
ansond | 0:5e68215d973a | 140 | // prepare the session key URL |
ansond | 0:5e68215d973a | 141 | void SocketIO::prepareSessionKeyURL(char *myurl, int myversion) { |
ansond | 0:5e68215d973a | 142 | // save the base URL |
ansond | 0:5e68215d973a | 143 | this->url = myurl; |
ansond | 0:5e68215d973a | 144 | |
ansond | 0:5e68215d973a | 145 | // set our version |
ansond | 0:5e68215d973a | 146 | this->version = myversion; |
ansond | 0:5e68215d973a | 147 | |
ansond | 0:5e68215d973a | 148 | // build out the session key URL |
ansond | 0:5e68215d973a | 149 | this->url_session_key = new char[256]; |
ansond | 0:5e68215d973a | 150 | time_t seconds = time(NULL); |
ansond | 0:5e68215d973a | 151 | sprintf(this->url_session_key,"http://%s/socket.io/%d/?t=%d",this->url,this->version,seconds); |
ansond | 0:5e68215d973a | 152 | |
ansond | 0:5e68215d973a | 153 | // setup the session key and channel buffers |
ansond | 0:5e68215d973a | 154 | this->session_key = new char[128]; |
ansond | 0:5e68215d973a | 155 | this->ws_channel = new char[128]; |
ansond | 0:5e68215d973a | 156 | } |
ansond | 0:5e68215d973a | 157 | |
ansond | 0:5e68215d973a | 158 | // parse the socket.io session key |
ansond | 0:5e68215d973a | 159 | void SocketIO::parseSessionKey(char *response, char *sessionkey, char *channel) { |
ansond | 0:5e68215d973a | 160 | int val1 = 0; |
ansond | 0:5e68215d973a | 161 | int val2 = 0; |
ansond | 0:5e68215d973a | 162 | |
ansond | 0:5e68215d973a | 163 | // convert ":" to " " |
ansond | 0:5e68215d973a | 164 | for(int i=0;i<strlen(response);++i) if (response[i] == ':') response[i] = ' '; |
ansond | 0:5e68215d973a | 165 | |
ansond | 0:5e68215d973a | 166 | // format: Session_ID YY ZZ CHANNEL |
ansond | 0:5e68215d973a | 167 | char t_sessionkey[128]; |
ansond | 5:912301390ce1 | 168 | sscanf(response,"%s %d %d %s",t_sessionkey,&val1,&val2,channel); |
ansond | 0:5e68215d973a | 169 | |
ansond | 0:5e68215d973a | 170 | // create |
ansond | 5:912301390ce1 | 171 | sprintf(sessionkey,"%s/%s",channel,t_sessionkey); |
ansond | 0:5e68215d973a | 172 | } |
ansond | 0:5e68215d973a | 173 | |
ansond | 0:5e68215d973a | 174 | // acquire the session key for our session |
ansond | 0:5e68215d973a | 175 | bool SocketIO::acquireSessionKey() { |
ansond | 0:5e68215d973a | 176 | bool haveKey = false; |
ansond | 0:5e68215d973a | 177 | HTTPClient http; |
ansond | 0:5e68215d973a | 178 | char response[513]; |
ansond | 0:5e68215d973a | 179 | |
ansond | 0:5e68215d973a | 180 | // make sure we have buffers |
ansond | 0:5e68215d973a | 181 | if (this->session_key != NULL && this->ws_channel != NULL) { |
ansond | 0:5e68215d973a | 182 | // request our session key |
ansond | 0:5e68215d973a | 183 | int nread = http.get(this->url_session_key,response,512); |
ansond | 0:5e68215d973a | 184 | |
ansond | 0:5e68215d973a | 185 | // parse the session key |
ansond | 0:5e68215d973a | 186 | if (!nread) |
ansond | 0:5e68215d973a | 187 | // parse into the session key |
ansond | 0:5e68215d973a | 188 | this->parseSessionKey(response,this->session_key,this->ws_channel); |
ansond | 0:5e68215d973a | 189 | |
ansond | 0:5e68215d973a | 190 | // update our status |
ansond | 0:5e68215d973a | 191 | if (strlen(this->session_key) > 0) haveKey = true; |
ansond | 0:5e68215d973a | 192 | } |
ansond | 0:5e68215d973a | 193 | |
ansond | 0:5e68215d973a | 194 | // return status |
ansond | 0:5e68215d973a | 195 | return haveKey; |
ansond | 0:5e68215d973a | 196 | } |