Client of WebSocket protocol
Fork of WebSocketClient by
Websocket.cpp@8:c9da00db9d33, 2017-02-24 (annotated)
- Committer:
- mauricioaschmitz
- Date:
- Fri Feb 24 20:06:49 2017 +0000
- Revision:
- 8:c9da00db9d33
- Parent:
- 7:4567996414a5
Added project prtgmdWebSocketClient
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
samux | 3:9589afa4712e | 1 | #include "Websocket.h" |
mauricioaschmitz | 8:c9da00db9d33 | 2 | #include "Pmed_reset.h" |
mauricioaschmitz | 8:c9da00db9d33 | 3 | #include "Log.h" |
samux | 3:9589afa4712e | 4 | |
samux | 7:4567996414a5 | 5 | #define MAX_TRY_WRITE 20 |
samux | 7:4567996414a5 | 6 | #define MAX_TRY_READ 10 |
mauricioaschmitz | 8:c9da00db9d33 | 7 | #define MAX_TRY_CONNECT 50 |
mauricioaschmitz | 8:c9da00db9d33 | 8 | #define WAIT_CONNECT_TIME 10000 |
samux | 3:9589afa4712e | 9 | |
samux | 3:9589afa4712e | 10 | //Debug is disabled by default |
samux | 3:9589afa4712e | 11 | #if 0 |
samux | 3:9589afa4712e | 12 | #define DBG(x, ...) std::printf("[WebSocket : DBG]"x"\r\n", ##__VA_ARGS__); |
samux | 3:9589afa4712e | 13 | #define WARN(x, ...) std::printf("[WebSocket : WARN]"x"\r\n", ##__VA_ARGS__); |
samux | 3:9589afa4712e | 14 | #define ERR(x, ...) std::printf("[WebSocket : ERR]"x"\r\n", ##__VA_ARGS__); |
samux | 3:9589afa4712e | 15 | #else |
samux | 3:9589afa4712e | 16 | #define DBG(x, ...) |
samux | 3:9589afa4712e | 17 | #define WARN(x, ...) |
samux | 3:9589afa4712e | 18 | #define ERR(x, ...) |
samux | 3:9589afa4712e | 19 | #endif |
samux | 3:9589afa4712e | 20 | |
mauricioaschmitz | 8:c9da00db9d33 | 21 | #define INFO(x, ...) printf("[WebSocket : INFO]"x"\r\n", ##__VA_ARGS__); |
mauricioaschmitz | 8:c9da00db9d33 | 22 | |
mauricioaschmitz | 8:c9da00db9d33 | 23 | char * Websocket::captureMessage; |
mauricioaschmitz | 8:c9da00db9d33 | 24 | bool Websocket::haveMessage; |
mauricioaschmitz | 8:c9da00db9d33 | 25 | bool Websocket::isConect; |
mauricioaschmitz | 8:c9da00db9d33 | 26 | bool disconnectedWS = false; |
samux | 3:9589afa4712e | 27 | |
mauricioaschmitz | 8:c9da00db9d33 | 28 | void Websocket::Websocket_Thread(void const *arg) |
mauricioaschmitz | 8:c9da00db9d33 | 29 | { |
mauricioaschmitz | 8:c9da00db9d33 | 30 | //Log::writeEntry("WebSocket Thread Start"); |
mauricioaschmitz | 8:c9da00db9d33 | 31 | printf("Thread WebSocket Iniciada\r\n"); |
mauricioaschmitz | 8:c9da00db9d33 | 32 | int i = 0, f = 0; |
mauricioaschmitz | 8:c9da00db9d33 | 33 | char *comando = NULL; |
mauricioaschmitz | 8:c9da00db9d33 | 34 | char *tomada = NULL; |
mauricioaschmitz | 8:c9da00db9d33 | 35 | char *canal = NULL; |
mauricioaschmitz | 8:c9da00db9d33 | 36 | char *limite = NULL; |
mauricioaschmitz | 8:c9da00db9d33 | 37 | char server[30]; |
mauricioaschmitz | 8:c9da00db9d33 | 38 | char buffer[1024] = {}; |
mauricioaschmitz | 8:c9da00db9d33 | 39 | //bool external = false; |
mauricioaschmitz | 8:c9da00db9d33 | 40 | strcpy(server, "ws://"); |
mauricioaschmitz | 8:c9da00db9d33 | 41 | strcat(server, Settings::get_networkServer()); |
mauricioaschmitz | 8:c9da00db9d33 | 42 | strcat(server, ":8080"); |
mauricioaschmitz | 8:c9da00db9d33 | 43 | |
mauricioaschmitz | 8:c9da00db9d33 | 44 | //printf("Servidor WS: %s", server); |
mauricioaschmitz | 8:c9da00db9d33 | 45 | |
mauricioaschmitz | 8:c9da00db9d33 | 46 | Websocket ws(server); |
mauricioaschmitz | 8:c9da00db9d33 | 47 | |
mauricioaschmitz | 8:c9da00db9d33 | 48 | while(1){ |
mauricioaschmitz | 8:c9da00db9d33 | 49 | if(ws.is_connected()){ |
mauricioaschmitz | 8:c9da00db9d33 | 50 | if (f == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 51 | //Log::writeEntry("WebSocket Conectado."); |
mauricioaschmitz | 8:c9da00db9d33 | 52 | //printf("\nMensagem do MBED para servidor WebSocket em PHP\n\n"); |
mauricioaschmitz | 8:c9da00db9d33 | 53 | //ws.send("#*MBEDStart*#Mensagem do MBED para servidor WebSocket em PHP\n"); //mensagem para registrar login do mbed no banco de dados (ainda por implementar) |
mauricioaschmitz | 8:c9da00db9d33 | 54 | f = 1; |
mauricioaschmitz | 8:c9da00db9d33 | 55 | } |
mauricioaschmitz | 8:c9da00db9d33 | 56 | if(disconnectedWS != false){ |
mauricioaschmitz | 8:c9da00db9d33 | 57 | disconnectedWS = false; |
mauricioaschmitz | 8:c9da00db9d33 | 58 | } |
mauricioaschmitz | 8:c9da00db9d33 | 59 | if(haveMessage){ |
mauricioaschmitz | 8:c9da00db9d33 | 60 | ws.send(captureMessage); |
mauricioaschmitz | 8:c9da00db9d33 | 61 | haveMessage = false; |
mauricioaschmitz | 8:c9da00db9d33 | 62 | captureMessage = NULL; |
mauricioaschmitz | 8:c9da00db9d33 | 63 | } |
mauricioaschmitz | 8:c9da00db9d33 | 64 | if (ws.read(buffer)) { |
mauricioaschmitz | 8:c9da00db9d33 | 65 | //ws.send("#*MBEDTest*#"); |
mauricioaschmitz | 8:c9da00db9d33 | 66 | //printf("Recebido Mensagem WebSocket: %s\r\n", buffer); |
mauricioaschmitz | 8:c9da00db9d33 | 67 | comando = strtok(buffer, ":"); |
mauricioaschmitz | 8:c9da00db9d33 | 68 | if(strcmp(comando, "test") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 69 | //printf("\r\nRecebido por WebSocket o Comando de Teste."); |
mauricioaschmitz | 8:c9da00db9d33 | 70 | ws.send("#*MBEDTest*#"); |
mauricioaschmitz | 8:c9da00db9d33 | 71 | //Log::writeEntry("Recebido por WebSocket o Comando de Teste."); |
mauricioaschmitz | 8:c9da00db9d33 | 72 | } |
mauricioaschmitz | 8:c9da00db9d33 | 73 | if(strcmp(comando, "capture") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 74 | tomada = strtok(NULL, ":"); |
mauricioaschmitz | 8:c9da00db9d33 | 75 | canal = strtok(NULL, " "); |
mauricioaschmitz | 8:c9da00db9d33 | 76 | /* |
mauricioaschmitz | 8:c9da00db9d33 | 77 | printf("Comando: %s\n", comando); |
mauricioaschmitz | 8:c9da00db9d33 | 78 | printf("Tomada: %s\n", tomada); |
mauricioaschmitz | 8:c9da00db9d33 | 79 | printf("Canal: %s\n", canal); |
mauricioaschmitz | 8:c9da00db9d33 | 80 | printf("Tamanho da string: %d\n", strlen(buffer)); |
mauricioaschmitz | 8:c9da00db9d33 | 81 | */ |
mauricioaschmitz | 8:c9da00db9d33 | 82 | |
mauricioaschmitz | 8:c9da00db9d33 | 83 | EventDetector::externalCapture(atoi(tomada), canal[0]); |
mauricioaschmitz | 8:c9da00db9d33 | 84 | } |
mauricioaschmitz | 8:c9da00db9d33 | 85 | if(strcmp(comando, "reset") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 86 | Pmed_reset("Reiniciando o MBED por WebSocket."); |
mauricioaschmitz | 8:c9da00db9d33 | 87 | } |
mauricioaschmitz | 8:c9da00db9d33 | 88 | |
mauricioaschmitz | 8:c9da00db9d33 | 89 | if(strcmp(comando, "setLimit") == 0 || strcmp(comando, "setStandByLimit") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 90 | tomada = strtok(NULL, ":"); |
mauricioaschmitz | 8:c9da00db9d33 | 91 | canal = strtok(NULL, ":"); |
mauricioaschmitz | 8:c9da00db9d33 | 92 | limite = strtok(NULL, " "); |
mauricioaschmitz | 8:c9da00db9d33 | 93 | for(i=0; (unsigned)i < _PRTGMD_SETTINGS_MAX_NUMBER_OF_OUTLETS_; i++){ |
mauricioaschmitz | 8:c9da00db9d33 | 94 | if(atoi(tomada) == Settings::get_outlet(i)){ |
mauricioaschmitz | 8:c9da00db9d33 | 95 | if(strcmp(comando, "setLimit") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 96 | if(strcmp(canal, "p") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 97 | printf("Entrou canal fase e setou limite %s para tomada %s\r\n", limite, tomada); |
mauricioaschmitz | 8:c9da00db9d33 | 98 | Settings::set_limit(i*2,strtod(limite, NULL)); |
mauricioaschmitz | 8:c9da00db9d33 | 99 | } |
mauricioaschmitz | 8:c9da00db9d33 | 100 | if(strcmp(canal, "d") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 101 | printf("Entrou canal fuga e setou limite %s para tomada %s\r\n", limite, tomada); |
mauricioaschmitz | 8:c9da00db9d33 | 102 | Settings::set_limit(i*2+1,strtod(limite, NULL)); |
mauricioaschmitz | 8:c9da00db9d33 | 103 | } |
mauricioaschmitz | 8:c9da00db9d33 | 104 | } |
mauricioaschmitz | 8:c9da00db9d33 | 105 | if(strcmp(comando, "setStandByLimit") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 106 | if(strcmp(canal, "p") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 107 | printf("Entrou canal StandBy de fase e setou limite %s para tomada %s\r\n", limite, tomada); |
mauricioaschmitz | 8:c9da00db9d33 | 108 | Settings::set_standbyLimit(i*2,strtod(limite, NULL)); |
mauricioaschmitz | 8:c9da00db9d33 | 109 | } |
mauricioaschmitz | 8:c9da00db9d33 | 110 | if(strcmp(canal, "d") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 111 | printf("Entrou canal StandBy de fuga e setou limite %s para tomada %s\r\n", limite, tomada); |
mauricioaschmitz | 8:c9da00db9d33 | 112 | Settings::set_standbyLimit(i*2+1,strtod(limite, NULL)); |
mauricioaschmitz | 8:c9da00db9d33 | 113 | } |
mauricioaschmitz | 8:c9da00db9d33 | 114 | } |
mauricioaschmitz | 8:c9da00db9d33 | 115 | break; |
mauricioaschmitz | 8:c9da00db9d33 | 116 | }else{ |
mauricioaschmitz | 8:c9da00db9d33 | 117 | if(i == _PRTGMD_SETTINGS_MAX_NUMBER_OF_OUTLETS_ - 1){ |
mauricioaschmitz | 8:c9da00db9d33 | 118 | printf("Tomada %d nao encontrada para atualizar limite!\r\n", atoi(tomada)); |
mauricioaschmitz | 8:c9da00db9d33 | 119 | } |
mauricioaschmitz | 8:c9da00db9d33 | 120 | } |
mauricioaschmitz | 8:c9da00db9d33 | 121 | } |
mauricioaschmitz | 8:c9da00db9d33 | 122 | //printf("Comando: %s\n", comando); |
mauricioaschmitz | 8:c9da00db9d33 | 123 | //printf("Tomada: %d\n", atoi(tomada)); |
mauricioaschmitz | 8:c9da00db9d33 | 124 | //printf("Canal: %s\n", canal); |
mauricioaschmitz | 8:c9da00db9d33 | 125 | //printf("Limite: %f\n", strtod(limite, NULL)); |
mauricioaschmitz | 8:c9da00db9d33 | 126 | } |
mauricioaschmitz | 8:c9da00db9d33 | 127 | /* |
mauricioaschmitz | 8:c9da00db9d33 | 128 | if(strcmp(comando, "iniciar") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 129 | printf("\n\nChegou o Iniciar!!!\n\n"); |
mauricioaschmitz | 8:c9da00db9d33 | 130 | external = true; |
mauricioaschmitz | 8:c9da00db9d33 | 131 | } |
mauricioaschmitz | 8:c9da00db9d33 | 132 | if(strcmp(comando, "parar") == 0){ |
mauricioaschmitz | 8:c9da00db9d33 | 133 | printf("\n\nChegou o Parar!!!\n\n"); |
mauricioaschmitz | 8:c9da00db9d33 | 134 | external = false; |
mauricioaschmitz | 8:c9da00db9d33 | 135 | } |
mauricioaschmitz | 8:c9da00db9d33 | 136 | if(external){ |
mauricioaschmitz | 8:c9da00db9d33 | 137 | |
mauricioaschmitz | 8:c9da00db9d33 | 138 | }*/ |
mauricioaschmitz | 8:c9da00db9d33 | 139 | } |
mauricioaschmitz | 8:c9da00db9d33 | 140 | /* |
mauricioaschmitz | 8:c9da00db9d33 | 141 | if (!ws.is_connected()){ |
mauricioaschmitz | 8:c9da00db9d33 | 142 | printf("Caiu a conexao!!!\n"); |
mauricioaschmitz | 8:c9da00db9d33 | 143 | Thread::wait(Settings::get_delayTry()); |
mauricioaschmitz | 8:c9da00db9d33 | 144 | for(int i=0; i < MAX_TRY_CONNECT; i++){ |
mauricioaschmitz | 8:c9da00db9d33 | 145 | Thread::wait(Settings::get_delayTry()); |
mauricioaschmitz | 8:c9da00db9d33 | 146 | //if(ws.connect()){ |
mauricioaschmitz | 8:c9da00db9d33 | 147 | // break; |
mauricioaschmitz | 8:c9da00db9d33 | 148 | //} |
mauricioaschmitz | 8:c9da00db9d33 | 149 | } |
mauricioaschmitz | 8:c9da00db9d33 | 150 | //Websocket ws("ws://192.168.103.101:8080"); |
mauricioaschmitz | 8:c9da00db9d33 | 151 | ws.connect(); |
mauricioaschmitz | 8:c9da00db9d33 | 152 | }*/ |
mauricioaschmitz | 8:c9da00db9d33 | 153 | }else{ |
mauricioaschmitz | 8:c9da00db9d33 | 154 | if(!disconnectedWS){ |
mauricioaschmitz | 8:c9da00db9d33 | 155 | if(ws.close()){ |
mauricioaschmitz | 8:c9da00db9d33 | 156 | disconnectedWS = true; |
mauricioaschmitz | 8:c9da00db9d33 | 157 | Log::writeEntry("WebSocket Desconectado."); |
mauricioaschmitz | 8:c9da00db9d33 | 158 | } |
mauricioaschmitz | 8:c9da00db9d33 | 159 | } |
mauricioaschmitz | 8:c9da00db9d33 | 160 | Thread::wait(WAIT_CONNECT_TIME); |
mauricioaschmitz | 8:c9da00db9d33 | 161 | if(ws.connect()){ |
mauricioaschmitz | 8:c9da00db9d33 | 162 | //Log::writeEntry("WebSocket Conectado."); |
mauricioaschmitz | 8:c9da00db9d33 | 163 | printf("Thread WebSocket Conectou no Servidor %s\r\n", Settings::get_networkServer()); |
mauricioaschmitz | 8:c9da00db9d33 | 164 | } |
mauricioaschmitz | 8:c9da00db9d33 | 165 | //Thread::wait(10000); |
mauricioaschmitz | 8:c9da00db9d33 | 166 | } |
mauricioaschmitz | 8:c9da00db9d33 | 167 | } |
mauricioaschmitz | 8:c9da00db9d33 | 168 | |
mauricioaschmitz | 8:c9da00db9d33 | 169 | } |
mauricioaschmitz | 8:c9da00db9d33 | 170 | |
mauricioaschmitz | 8:c9da00db9d33 | 171 | Websocket::Websocket(char const * url) { |
samux | 3:9589afa4712e | 172 | fillFields(url); |
samux | 3:9589afa4712e | 173 | socket.set_blocking(false, 400); |
samux | 3:9589afa4712e | 174 | } |
samux | 3:9589afa4712e | 175 | |
mauricioaschmitz | 8:c9da00db9d33 | 176 | bool Websocket::wsIsConnected(){ |
mauricioaschmitz | 8:c9da00db9d33 | 177 | return isConect; |
mauricioaschmitz | 8:c9da00db9d33 | 178 | } |
mauricioaschmitz | 8:c9da00db9d33 | 179 | |
mauricioaschmitz | 8:c9da00db9d33 | 180 | void Websocket::fillFields(char const * url) { |
donatien | 6:86e89a0369b9 | 181 | int ret = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); |
donatien | 6:86e89a0369b9 | 182 | if(ret) |
donatien | 6:86e89a0369b9 | 183 | { |
donatien | 6:86e89a0369b9 | 184 | ERR("URL parsing failed; please use: \"ws://ip-or-domain[:port]/path\""); |
donatien | 6:86e89a0369b9 | 185 | return; |
donatien | 6:86e89a0369b9 | 186 | } |
samux | 3:9589afa4712e | 187 | |
donatien | 6:86e89a0369b9 | 188 | if(port == 0) //TODO do handle WSS->443 |
donatien | 6:86e89a0369b9 | 189 | { |
donatien | 6:86e89a0369b9 | 190 | port = 80; |
donatien | 6:86e89a0369b9 | 191 | } |
donatien | 6:86e89a0369b9 | 192 | |
donatien | 6:86e89a0369b9 | 193 | if(strcmp(scheme, "ws")) |
donatien | 6:86e89a0369b9 | 194 | { |
donatien | 6:86e89a0369b9 | 195 | ERR("Wrong scheme, please use \"ws\" instead"); |
donatien | 6:86e89a0369b9 | 196 | } |
donatien | 6:86e89a0369b9 | 197 | } |
samux | 3:9589afa4712e | 198 | |
donatien | 6:86e89a0369b9 | 199 | int Websocket::parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen) //Parse URL |
donatien | 6:86e89a0369b9 | 200 | { |
donatien | 6:86e89a0369b9 | 201 | char* schemePtr = (char*) url; |
donatien | 6:86e89a0369b9 | 202 | char* hostPtr = (char*) strstr(url, "://"); |
donatien | 6:86e89a0369b9 | 203 | if(hostPtr == NULL) |
donatien | 6:86e89a0369b9 | 204 | { |
donatien | 6:86e89a0369b9 | 205 | WARN("Could not find host"); |
donatien | 6:86e89a0369b9 | 206 | return -1; //URL is invalid |
donatien | 6:86e89a0369b9 | 207 | } |
donatien | 6:86e89a0369b9 | 208 | |
donatien | 6:86e89a0369b9 | 209 | if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char |
donatien | 6:86e89a0369b9 | 210 | { |
donatien | 6:86e89a0369b9 | 211 | WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1); |
donatien | 6:86e89a0369b9 | 212 | return -1; |
donatien | 6:86e89a0369b9 | 213 | } |
donatien | 6:86e89a0369b9 | 214 | memcpy(scheme, schemePtr, hostPtr - schemePtr); |
donatien | 6:86e89a0369b9 | 215 | scheme[hostPtr - schemePtr] = '\0'; |
donatien | 6:86e89a0369b9 | 216 | |
donatien | 6:86e89a0369b9 | 217 | hostPtr+=3; |
donatien | 6:86e89a0369b9 | 218 | |
donatien | 6:86e89a0369b9 | 219 | size_t hostLen = 0; |
samux | 3:9589afa4712e | 220 | |
donatien | 6:86e89a0369b9 | 221 | char* portPtr = strchr(hostPtr, ':'); |
donatien | 6:86e89a0369b9 | 222 | if( portPtr != NULL ) |
donatien | 6:86e89a0369b9 | 223 | { |
donatien | 6:86e89a0369b9 | 224 | hostLen = portPtr - hostPtr; |
donatien | 6:86e89a0369b9 | 225 | portPtr++; |
donatien | 6:86e89a0369b9 | 226 | if( sscanf(portPtr, "%hu", port) != 1) |
donatien | 6:86e89a0369b9 | 227 | { |
donatien | 6:86e89a0369b9 | 228 | WARN("Could not find port"); |
donatien | 6:86e89a0369b9 | 229 | return -1; |
donatien | 6:86e89a0369b9 | 230 | } |
donatien | 6:86e89a0369b9 | 231 | } |
donatien | 6:86e89a0369b9 | 232 | else |
donatien | 6:86e89a0369b9 | 233 | { |
donatien | 6:86e89a0369b9 | 234 | *port=0; |
donatien | 6:86e89a0369b9 | 235 | } |
donatien | 6:86e89a0369b9 | 236 | char* pathPtr = strchr(hostPtr, '/'); |
donatien | 6:86e89a0369b9 | 237 | if( hostLen == 0 ) |
donatien | 6:86e89a0369b9 | 238 | { |
donatien | 6:86e89a0369b9 | 239 | hostLen = pathPtr - hostPtr; |
donatien | 6:86e89a0369b9 | 240 | } |
samux | 3:9589afa4712e | 241 | |
donatien | 6:86e89a0369b9 | 242 | if( maxHostLen < hostLen + 1 ) //including NULL-terminating char |
donatien | 6:86e89a0369b9 | 243 | { |
donatien | 6:86e89a0369b9 | 244 | WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1); |
donatien | 6:86e89a0369b9 | 245 | return -1; |
donatien | 6:86e89a0369b9 | 246 | } |
donatien | 6:86e89a0369b9 | 247 | memcpy(host, hostPtr, hostLen); |
donatien | 6:86e89a0369b9 | 248 | host[hostLen] = '\0'; |
samux | 3:9589afa4712e | 249 | |
donatien | 6:86e89a0369b9 | 250 | size_t pathLen; |
donatien | 6:86e89a0369b9 | 251 | char* fragmentPtr = strchr(hostPtr, '#'); |
donatien | 6:86e89a0369b9 | 252 | if(fragmentPtr != NULL) |
donatien | 6:86e89a0369b9 | 253 | { |
donatien | 6:86e89a0369b9 | 254 | pathLen = fragmentPtr - pathPtr; |
donatien | 6:86e89a0369b9 | 255 | } |
donatien | 6:86e89a0369b9 | 256 | else |
donatien | 6:86e89a0369b9 | 257 | { |
donatien | 6:86e89a0369b9 | 258 | pathLen = strlen(pathPtr); |
donatien | 6:86e89a0369b9 | 259 | } |
donatien | 6:86e89a0369b9 | 260 | |
donatien | 6:86e89a0369b9 | 261 | if( maxPathLen < pathLen + 1 ) //including NULL-terminating char |
donatien | 6:86e89a0369b9 | 262 | { |
donatien | 6:86e89a0369b9 | 263 | WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1); |
donatien | 6:86e89a0369b9 | 264 | return -1; |
donatien | 6:86e89a0369b9 | 265 | } |
donatien | 6:86e89a0369b9 | 266 | memcpy(path, pathPtr, pathLen); |
donatien | 6:86e89a0369b9 | 267 | path[pathLen] = '\0'; |
donatien | 6:86e89a0369b9 | 268 | |
donatien | 6:86e89a0369b9 | 269 | return 0; |
samux | 3:9589afa4712e | 270 | } |
samux | 3:9589afa4712e | 271 | |
samux | 3:9589afa4712e | 272 | |
samux | 3:9589afa4712e | 273 | bool Websocket::connect() { |
samux | 3:9589afa4712e | 274 | char cmd[200]; |
samux | 3:9589afa4712e | 275 | |
donatien | 6:86e89a0369b9 | 276 | while (socket.connect(host, port) < 0) { |
donatien | 6:86e89a0369b9 | 277 | ERR("Unable to connect to (%s) on port (%d)", host, port); |
mauricioaschmitz | 8:c9da00db9d33 | 278 | Thread::wait(200); |
donatien | 6:86e89a0369b9 | 279 | return false; |
samux | 3:9589afa4712e | 280 | } |
samux | 3:9589afa4712e | 281 | |
samux | 3:9589afa4712e | 282 | // sent http header to upgrade to the ws protocol |
donatien | 6:86e89a0369b9 | 283 | sprintf(cmd, "GET %s HTTP/1.1\r\n", path); |
samux | 3:9589afa4712e | 284 | write(cmd, strlen(cmd)); |
donatien | 6:86e89a0369b9 | 285 | |
donatien | 6:86e89a0369b9 | 286 | sprintf(cmd, "Host: %s:%d\r\n", host, port); |
samux | 3:9589afa4712e | 287 | write(cmd, strlen(cmd)); |
samux | 3:9589afa4712e | 288 | |
samux | 3:9589afa4712e | 289 | sprintf(cmd, "Upgrade: WebSocket\r\n"); |
samux | 3:9589afa4712e | 290 | write(cmd, strlen(cmd)); |
samux | 3:9589afa4712e | 291 | |
samux | 3:9589afa4712e | 292 | sprintf(cmd, "Connection: Upgrade\r\n"); |
samux | 3:9589afa4712e | 293 | write(cmd, strlen(cmd)); |
samux | 3:9589afa4712e | 294 | |
samux | 3:9589afa4712e | 295 | sprintf(cmd, "Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n"); |
samux | 3:9589afa4712e | 296 | write(cmd, strlen(cmd)); |
samux | 3:9589afa4712e | 297 | |
samux | 3:9589afa4712e | 298 | sprintf(cmd, "Sec-WebSocket-Version: 13\r\n\r\n"); |
samux | 3:9589afa4712e | 299 | int ret = write(cmd, strlen(cmd)); |
mauricioaschmitz | 8:c9da00db9d33 | 300 | if ((unsigned)ret != strlen(cmd)) { |
samux | 3:9589afa4712e | 301 | close(); |
samux | 3:9589afa4712e | 302 | ERR("Could not send request"); |
samux | 3:9589afa4712e | 303 | return false; |
samux | 3:9589afa4712e | 304 | } |
mauricioaschmitz | 8:c9da00db9d33 | 305 | |
samux | 3:9589afa4712e | 306 | ret = read(cmd, 200, 100); |
samux | 3:9589afa4712e | 307 | if (ret < 0) { |
samux | 3:9589afa4712e | 308 | close(); |
samux | 3:9589afa4712e | 309 | ERR("Could not receive answer\r\n"); |
samux | 3:9589afa4712e | 310 | return false; |
samux | 3:9589afa4712e | 311 | } |
samux | 3:9589afa4712e | 312 | cmd[ret] = '\0'; |
samux | 3:9589afa4712e | 313 | DBG("recv: %s\r\n", cmd); |
samux | 3:9589afa4712e | 314 | |
samux | 3:9589afa4712e | 315 | if ( strstr(cmd, "DdLWT/1JcX+nQFHebYP+rqEx5xI=") == NULL ) { |
samux | 3:9589afa4712e | 316 | ERR("Wrong answer from server, got \"%s\" instead\r\n", cmd); |
samux | 3:9589afa4712e | 317 | do { |
samux | 3:9589afa4712e | 318 | ret = read(cmd, 200, 100); |
samux | 3:9589afa4712e | 319 | if (ret < 0) { |
samux | 3:9589afa4712e | 320 | ERR("Could not receive answer\r\n"); |
samux | 3:9589afa4712e | 321 | return false; |
samux | 3:9589afa4712e | 322 | } |
samux | 3:9589afa4712e | 323 | cmd[ret] = '\0'; |
samux | 3:9589afa4712e | 324 | printf("%s",cmd); |
samux | 3:9589afa4712e | 325 | } while (ret > 0); |
samux | 3:9589afa4712e | 326 | close(); |
samux | 3:9589afa4712e | 327 | return false; |
samux | 3:9589afa4712e | 328 | } |
mauricioaschmitz | 8:c9da00db9d33 | 329 | |
mauricioaschmitz | 8:c9da00db9d33 | 330 | //INFO("\r\nhost: %s\r\npath: %s\r\nport: %d\r\n\r\n", host, path, port); |
samux | 3:9589afa4712e | 331 | return true; |
samux | 3:9589afa4712e | 332 | } |
samux | 3:9589afa4712e | 333 | |
samux | 4:466f90b7849a | 334 | int Websocket::sendLength(uint32_t len, char * msg) { |
samux | 3:9589afa4712e | 335 | |
samux | 3:9589afa4712e | 336 | if (len < 126) { |
samux | 4:466f90b7849a | 337 | msg[0] = len | (1<<7); |
samux | 3:9589afa4712e | 338 | return 1; |
samux | 3:9589afa4712e | 339 | } else if (len < 65535) { |
samux | 4:466f90b7849a | 340 | msg[0] = 126 | (1<<7); |
samux | 4:466f90b7849a | 341 | msg[1] = (len >> 8) & 0xff; |
samux | 4:466f90b7849a | 342 | msg[2] = len & 0xff; |
samux | 3:9589afa4712e | 343 | return 3; |
samux | 3:9589afa4712e | 344 | } else { |
samux | 4:466f90b7849a | 345 | msg[0] = 127 | (1<<7); |
samux | 3:9589afa4712e | 346 | for (int i = 0; i < 8; i++) { |
samux | 4:466f90b7849a | 347 | msg[i+1] = (len >> i*8) & 0xff; |
samux | 3:9589afa4712e | 348 | } |
samux | 3:9589afa4712e | 349 | return 9; |
samux | 3:9589afa4712e | 350 | } |
samux | 3:9589afa4712e | 351 | } |
samux | 3:9589afa4712e | 352 | |
samux | 3:9589afa4712e | 353 | int Websocket::readChar(char * pC, bool block) { |
samux | 3:9589afa4712e | 354 | return read(pC, 1, 1); |
samux | 3:9589afa4712e | 355 | } |
samux | 3:9589afa4712e | 356 | |
samux | 4:466f90b7849a | 357 | int Websocket::sendOpcode(uint8_t opcode, char * msg) { |
samux | 4:466f90b7849a | 358 | msg[0] = 0x80 | (opcode & 0x0f); |
samux | 4:466f90b7849a | 359 | return 1; |
samux | 3:9589afa4712e | 360 | } |
samux | 3:9589afa4712e | 361 | |
samux | 4:466f90b7849a | 362 | int Websocket::sendMask(char * msg) { |
samux | 3:9589afa4712e | 363 | for (int i = 0; i < 4; i++) { |
samux | 4:466f90b7849a | 364 | msg[i] = 0; |
samux | 3:9589afa4712e | 365 | } |
samux | 3:9589afa4712e | 366 | return 4; |
samux | 3:9589afa4712e | 367 | } |
samux | 3:9589afa4712e | 368 | |
samux | 3:9589afa4712e | 369 | int Websocket::send(char * str) { |
samux | 4:466f90b7849a | 370 | char msg[strlen(str) + 15]; |
samux | 4:466f90b7849a | 371 | int idx = 0; |
samux | 4:466f90b7849a | 372 | idx = sendOpcode(0x01, msg); |
samux | 4:466f90b7849a | 373 | idx += sendLength(strlen(str), msg + idx); |
samux | 4:466f90b7849a | 374 | idx += sendMask(msg + idx); |
samux | 4:466f90b7849a | 375 | memcpy(msg+idx, str, strlen(str)); |
samux | 4:466f90b7849a | 376 | int res = write(msg, idx + strlen(str)); |
samux | 3:9589afa4712e | 377 | return res; |
samux | 3:9589afa4712e | 378 | } |
samux | 3:9589afa4712e | 379 | |
samux | 3:9589afa4712e | 380 | |
samux | 3:9589afa4712e | 381 | bool Websocket::read(char * message) { |
samux | 3:9589afa4712e | 382 | int i = 0; |
samux | 3:9589afa4712e | 383 | uint32_t len_msg; |
samux | 3:9589afa4712e | 384 | char opcode = 0; |
samux | 3:9589afa4712e | 385 | char c; |
samux | 3:9589afa4712e | 386 | char mask[4] = {0, 0, 0, 0}; |
samux | 3:9589afa4712e | 387 | bool is_masked = false; |
samux | 3:9589afa4712e | 388 | Timer tmr; |
samux | 3:9589afa4712e | 389 | |
samux | 3:9589afa4712e | 390 | // read the opcode |
samux | 3:9589afa4712e | 391 | tmr.start(); |
samux | 3:9589afa4712e | 392 | while (true) { |
samux | 3:9589afa4712e | 393 | if (tmr.read() > 3) { |
samux | 3:9589afa4712e | 394 | DBG("timeout ws\r\n"); |
samux | 3:9589afa4712e | 395 | return false; |
samux | 3:9589afa4712e | 396 | } |
donatien | 5:bb09d7a6c92f | 397 | |
donatien | 5:bb09d7a6c92f | 398 | if(!socket.is_connected()) |
donatien | 5:bb09d7a6c92f | 399 | { |
donatien | 5:bb09d7a6c92f | 400 | WARN("Connection was closed by server"); |
donatien | 5:bb09d7a6c92f | 401 | return false; |
donatien | 5:bb09d7a6c92f | 402 | } |
samux | 3:9589afa4712e | 403 | |
samux | 3:9589afa4712e | 404 | socket.set_blocking(false, 1); |
samux | 3:9589afa4712e | 405 | if (socket.receive(&opcode, 1) != 1) { |
samux | 3:9589afa4712e | 406 | socket.set_blocking(false, 2000); |
samux | 3:9589afa4712e | 407 | return false; |
samux | 3:9589afa4712e | 408 | } |
samux | 3:9589afa4712e | 409 | |
samux | 3:9589afa4712e | 410 | socket.set_blocking(false, 2000); |
samux | 3:9589afa4712e | 411 | |
samux | 3:9589afa4712e | 412 | if (opcode == 0x81) |
samux | 3:9589afa4712e | 413 | break; |
samux | 3:9589afa4712e | 414 | } |
samux | 3:9589afa4712e | 415 | DBG("opcode: 0x%X\r\n", opcode); |
samux | 3:9589afa4712e | 416 | |
samux | 3:9589afa4712e | 417 | readChar(&c); |
samux | 3:9589afa4712e | 418 | len_msg = c & 0x7f; |
samux | 3:9589afa4712e | 419 | is_masked = c & 0x80; |
samux | 3:9589afa4712e | 420 | if (len_msg == 126) { |
samux | 3:9589afa4712e | 421 | readChar(&c); |
samux | 3:9589afa4712e | 422 | len_msg = c << 8; |
samux | 3:9589afa4712e | 423 | readChar(&c); |
samux | 3:9589afa4712e | 424 | len_msg += c; |
samux | 3:9589afa4712e | 425 | } else if (len_msg == 127) { |
samux | 3:9589afa4712e | 426 | len_msg = 0; |
samux | 3:9589afa4712e | 427 | for (int i = 0; i < 8; i++) { |
samux | 3:9589afa4712e | 428 | readChar(&c); |
samux | 3:9589afa4712e | 429 | len_msg += (c << (7-i)*8); |
samux | 3:9589afa4712e | 430 | } |
samux | 3:9589afa4712e | 431 | } |
samux | 3:9589afa4712e | 432 | |
samux | 3:9589afa4712e | 433 | if (len_msg == 0) { |
samux | 3:9589afa4712e | 434 | return false; |
samux | 3:9589afa4712e | 435 | } |
samux | 3:9589afa4712e | 436 | DBG("length: %d\r\n", len_msg); |
samux | 3:9589afa4712e | 437 | |
samux | 3:9589afa4712e | 438 | if (is_masked) { |
samux | 3:9589afa4712e | 439 | for (i = 0; i < 4; i++) |
samux | 3:9589afa4712e | 440 | readChar(&c); |
samux | 3:9589afa4712e | 441 | mask[i] = c; |
samux | 3:9589afa4712e | 442 | } |
samux | 3:9589afa4712e | 443 | |
samux | 3:9589afa4712e | 444 | int nb = read(message, len_msg, len_msg); |
samux | 3:9589afa4712e | 445 | if (nb != len_msg) |
samux | 3:9589afa4712e | 446 | return false; |
samux | 3:9589afa4712e | 447 | |
mauricioaschmitz | 8:c9da00db9d33 | 448 | for (i = 0; (unsigned)i < len_msg; i++) { |
samux | 3:9589afa4712e | 449 | message[i] = message[i] ^ mask[i % 4]; |
samux | 3:9589afa4712e | 450 | } |
samux | 3:9589afa4712e | 451 | |
samux | 3:9589afa4712e | 452 | message[len_msg] = '\0'; |
samux | 3:9589afa4712e | 453 | |
samux | 3:9589afa4712e | 454 | return true; |
samux | 3:9589afa4712e | 455 | } |
samux | 3:9589afa4712e | 456 | |
samux | 3:9589afa4712e | 457 | bool Websocket::close() { |
mauricioaschmitz | 8:c9da00db9d33 | 458 | //if (!is_connected()) |
mauricioaschmitz | 8:c9da00db9d33 | 459 | //return false; |
samux | 3:9589afa4712e | 460 | |
mauricioaschmitz | 8:c9da00db9d33 | 461 | int ret = socket.close(true); |
samux | 3:9589afa4712e | 462 | if (ret < 0) { |
samux | 3:9589afa4712e | 463 | ERR("Could not disconnect"); |
samux | 3:9589afa4712e | 464 | return false; |
samux | 3:9589afa4712e | 465 | } |
samux | 3:9589afa4712e | 466 | return true; |
samux | 3:9589afa4712e | 467 | } |
samux | 3:9589afa4712e | 468 | |
samux | 3:9589afa4712e | 469 | bool Websocket::is_connected() { |
mauricioaschmitz | 8:c9da00db9d33 | 470 | isConect = socket.is_connected(); |
samux | 3:9589afa4712e | 471 | return socket.is_connected(); |
samux | 3:9589afa4712e | 472 | } |
samux | 3:9589afa4712e | 473 | |
donatien | 6:86e89a0369b9 | 474 | char* Websocket::getPath() { |
samux | 3:9589afa4712e | 475 | return path; |
samux | 3:9589afa4712e | 476 | } |
samux | 3:9589afa4712e | 477 | |
samux | 3:9589afa4712e | 478 | int Websocket::write(char * str, int len) { |
samux | 3:9589afa4712e | 479 | int res = 0, idx = 0; |
samux | 3:9589afa4712e | 480 | |
samux | 3:9589afa4712e | 481 | for (int j = 0; j < MAX_TRY_WRITE; j++) { |
donatien | 5:bb09d7a6c92f | 482 | |
donatien | 5:bb09d7a6c92f | 483 | if(!socket.is_connected()) |
donatien | 5:bb09d7a6c92f | 484 | { |
donatien | 5:bb09d7a6c92f | 485 | WARN("Connection was closed by server"); |
donatien | 5:bb09d7a6c92f | 486 | break; |
donatien | 5:bb09d7a6c92f | 487 | } |
samux | 3:9589afa4712e | 488 | |
samux | 3:9589afa4712e | 489 | if ((res = socket.send_all(str + idx, len - idx)) == -1) |
samux | 3:9589afa4712e | 490 | continue; |
samux | 3:9589afa4712e | 491 | |
samux | 3:9589afa4712e | 492 | idx += res; |
samux | 3:9589afa4712e | 493 | |
samux | 3:9589afa4712e | 494 | if (idx == len) |
samux | 3:9589afa4712e | 495 | return len; |
samux | 3:9589afa4712e | 496 | } |
samux | 3:9589afa4712e | 497 | |
samux | 3:9589afa4712e | 498 | return (idx == 0) ? -1 : idx; |
samux | 3:9589afa4712e | 499 | } |
samux | 3:9589afa4712e | 500 | |
samux | 3:9589afa4712e | 501 | int Websocket::read(char * str, int len, int min_len) { |
samux | 3:9589afa4712e | 502 | int res = 0, idx = 0; |
samux | 3:9589afa4712e | 503 | |
samux | 3:9589afa4712e | 504 | for (int j = 0; j < MAX_TRY_WRITE; j++) { |
samux | 3:9589afa4712e | 505 | |
samux | 3:9589afa4712e | 506 | if ((res = socket.receive_all(str + idx, len - idx)) == -1) |
samux | 3:9589afa4712e | 507 | continue; |
samux | 3:9589afa4712e | 508 | |
samux | 3:9589afa4712e | 509 | idx += res; |
samux | 3:9589afa4712e | 510 | |
samux | 3:9589afa4712e | 511 | if (idx == len || (min_len != -1 && idx > min_len)) |
samux | 3:9589afa4712e | 512 | return idx; |
samux | 3:9589afa4712e | 513 | } |
samux | 3:9589afa4712e | 514 | |
samux | 3:9589afa4712e | 515 | return (idx == 0) ? -1 : idx; |
samux | 3:9589afa4712e | 516 | } |