Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Websocket.cpp Source File

Websocket.cpp

00001 #define __DEBUG__ 4 //Maximum verbosity
00002 #ifndef __MODULE__
00003 #define __MODULE__ "Websocket.cpp"
00004 #endif
00005 
00006 #include "core/fwk.h"
00007 
00008 #include "Websocket.h"
00009 #include <string>
00010 
00011 
00012 Websocket::Websocket(char * url) : m_sockHandle(-1) {
00013     //server_ip = NULL;
00014 
00015     std::memset(&m_sockAddr, 0, sizeof(struct sockaddr_in));
00016 
00017     fillFields(url);
00018 }
00019 
00020 
00021 void Websocket::fillFields(char * url) {
00022     char *res = NULL;
00023     char *res1 = NULL;
00024 
00025     char buf[50];
00026     strcpy(buf, url);
00027 
00028     res = strtok(buf, ":");
00029     if (strcmp(res, "ws")) {
00030 #ifdef DEBUG
00031         printf("\r\nFormat error: please use: \"ws://ip-or-domain[:port]/path\"\r\n\r\n");
00032 #endif
00033     } else {
00034         //ip_domain and port
00035         res = strtok(NULL, "/");
00036 
00037         //path
00038         res1 = strtok(NULL, " ");
00039         if (res1 != NULL) {
00040             path = res1;
00041         }
00042 
00043         //ip_domain
00044         res = strtok(res, ":");
00045 
00046         //port
00047         res1 = strtok(NULL, " ");
00048         //port
00049         if (res1 != NULL) {
00050             port = res1;
00051         } else {
00052             port = "80";
00053         }
00054 
00055         if (res != NULL) {
00056             ip_domain = res;
00057 
00058             //if we use ethernet, we must decode ip address or use dnsresolver
00059             strcpy(buf, res);
00060 
00061             //we try to decode the ip address
00062             if (buf[0] >= '0' && buf[0] <= '9') {
00063                 res = strtok(buf, ".");
00064                 int i = 0;
00065                 int ip[4];
00066                 while (res != NULL) {
00067                     ip[i] = atoi(res);
00068                     res = strtok(NULL, ".");
00069                     i++;
00070                 }
00071                 //server_ip = new IpAddr(ip[0], ip[1], ip[2], ip[3]);
00072                 m_sockAddr.sin_addr.s_addr = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | ip[3]; //Could do this easier if using inet_pton()
00073 
00074             }
00075         }
00076     }
00077 }
00078 
00079 
00080 bool Websocket::connect() {
00081     char cmd[192];
00082 
00083     //Resolve DNS if needed
00084     if(m_sockAddr.sin_addr.s_addr == 0)
00085     {
00086       DBG("Resolving DNS socket");
00087       struct hostent *server = socket::gethostbyname(ip_domain.c_str());
00088       if(server == NULL)
00089       {
00090         return false;
00091       }
00092       memcpy((char*)&m_sockAddr.sin_addr.s_addr, (char*)server->h_addr_list[0], server->h_length);
00093     }
00094 
00095     m_sockAddr.sin_family = AF_INET;
00096     m_sockAddr.sin_port = htons(atoi(port.c_str()));
00097 
00098     //Create socket
00099     DBG("Creating socket");
00100     m_sockHandle = socket::socket(AF_INET, SOCK_STREAM, 0);
00101     if (m_sockHandle < 0)
00102     {
00103       ERR("Could not create socket");
00104       return false;
00105     }
00106     DBG("Handle is %d",m_sockHandle);
00107 
00108     //Connect
00109     DBG("Connecting socket to %s:%d", inet_ntoa(m_sockAddr.sin_addr), ntohs(m_sockAddr.sin_port));
00110     int ret = socket::connect(m_sockHandle, (const struct sockaddr *)&m_sockAddr, sizeof(m_sockAddr));
00111     if (ret < 0)
00112     {
00113       socket::close(m_sockHandle);
00114       ERR("Could not connect");
00115       return false;
00116     }
00117 
00118     m_connected = true;
00119 
00120     DBG("Sending HTTP request");
00121     //send websocket HTTP header
00122     sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
00123     write((uint8_t*)cmd, strlen(cmd));
00124 
00125     sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
00126     write((uint8_t*)cmd, strlen(cmd));
00127 
00128     sprintf(cmd, "Upgrade: WebSocket\r\n");
00129     write((uint8_t*)cmd, strlen(cmd));
00130 
00131     sprintf(cmd, "Connection: Upgrade\r\n");
00132     write((uint8_t*)cmd, strlen(cmd));
00133 
00134 //    socket::send(m_sockHandle, "Origin: null\r\n", strlen("Origin: null\r\n"), 0);
00135 
00136     sprintf(cmd, "Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n");
00137     write((uint8_t*)cmd, strlen(cmd));
00138 
00139     sprintf(cmd, "Sec-WebSocket-Version: 13\r\n\r\n");
00140     ret = write((uint8_t*)cmd, strlen(cmd));
00141     if(ret < 0)
00142     {
00143       close();
00144       ERR("Could not send request");
00145       m_connected = false;
00146       return false;
00147     }
00148 
00149     DBG("Waiting for answer");
00150     ret = read((uint8_t*)cmd, 0, 192);
00151     if(ret < 0)
00152     {
00153       close();
00154       ERR("Could not receive answer");
00155       m_connected = false;
00156       return false;
00157     }
00158     cmd[ret] = '\0';
00159 
00160     DBG("Comparing answer");
00161     if( strstr(cmd, "Sec-WebSocket-Accept: DdLWT/1JcX+nQFHebYP+rqEx5xI=") == NULL )
00162     {
00163       ERR("Wrong answer from server, got \"%s\" instead", cmd);
00164       do{
00165         ret = read((uint8_t*)cmd, 0, 192);
00166         if(ret < 0)
00167         {
00168           ERR("Could not receive answer");
00169           return false;
00170         }
00171         cmd[ret] = '\0';
00172         printf("%s",cmd);
00173       } while(ret > 0);
00174       close();
00175       m_connected = false;
00176       return false;
00177     }
00178     DBG("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain.c_str(), this->path.c_str(), this->port.c_str());
00179     return true;
00180 }
00181 
00182 void Websocket::sendLength(uint32_t len) {
00183     if (len < 126) {
00184         sendChar(len | (1<<7));
00185     } else if (len < 65535) {
00186         sendChar(126 | (1<<7));
00187         sendChar(len & 0xff);
00188         sendChar((len >> 8) & 0xff);
00189     } else {
00190         sendChar(127 | (1<<7));
00191         for (int i = 0; i < 8; i++) {
00192             sendChar((len >> i*8) & 0xff);
00193         }
00194     }
00195 }
00196 
00197 void Websocket::sendChar(uint8_t c) {
00198     write(&c, 1);
00199 }
00200 
00201 bool Websocket::readChar(uint8_t* pC, bool block)
00202 {
00203     int ret = read(pC, 1, block?36000000:3000);
00204     if(ret < 0)
00205     {
00206       return false;
00207     }
00208     return true;
00209 }
00210 
00211 void Websocket::sendOpcode(uint8_t opcode) {
00212     sendChar(0x80 | (opcode & 0x0f));
00213 }
00214 
00215 void Websocket::sendMask() {
00216     for (int i = 0; i < 4; i++) {
00217         sendChar(0);
00218     }
00219 }
00220 
00221 void Websocket::send(char * str) {
00222     sendOpcode(0x01);
00223     sendLength(strlen(str));
00224     sendMask();
00225 
00226     write((uint8_t*)str, strlen(str));
00227 }
00228 
00229 
00230 
00231 bool Websocket::read(char * message) {
00232     int i = 0;
00233     //int length_buffer = 0;
00234     uint32_t len_msg;
00235     char opcode = 0;
00236     uint8_t c;
00237     char mask[4] = {0, 0, 0, 0};
00238     Timer tmr;
00239 
00240     //length_buffer = wifi->readable();
00241 
00242     // read the opcode
00243     tmr.start();
00244     while (true) {
00245         if (tmr.read() > 3) {
00246             return false;
00247         }
00248         if(!readChar((uint8_t*)&c, false))
00249         {
00250           return false;
00251         }
00252 
00253         opcode = c;
00254         if (opcode == 0x81) {
00255             break;
00256         }
00257     }
00258 #ifdef DEBUG
00259     printf("opcode: 0x%X\r\n", opcode);
00260 #endif
00261     readChar((uint8_t*)&c);
00262     len_msg = c & 0x7f;
00263     if (len_msg == 126) {
00264         readChar((uint8_t*)&c);
00265         len_msg = c;
00266         readChar((uint8_t*)&c);
00267         len_msg += c << 8;
00268     } else if (len_msg == 127) {
00269         len_msg = 0;
00270         for (i = 0; i < 8; i++) {
00271             readChar((uint8_t*)&c);
00272             len_msg += c << i*8;
00273         }
00274     }
00275     if(len_msg == 0) {
00276         return false;
00277     }
00278 #ifdef DEBUG
00279     printf("length: %d\r\n", len_msg);
00280 #endif
00281     if ((len_msg & 0x80)) {
00282         for (i = 0; i < 4; i++)
00283             readChar((uint8_t*)&c);
00284             mask[i] = c;
00285     }
00286 
00287 
00288 
00289     for (i = 0; i < len_msg; i++) {
00290         readChar((uint8_t*)&c);
00291         message[i] = c ^ mask[i % 4];
00292     }
00293 
00294     message[len_msg] = 0;
00295     return true;
00296 }
00297 
00298 bool Websocket::close() {
00299     if((m_sockHandle < 0) || !m_connected)
00300     {
00301       return false;
00302     }
00303     m_connected = false;
00304     int ret = socket::close(m_sockHandle);
00305     if (ret < 0)
00306     {
00307       ERR("Could not disconnect");
00308       return false;
00309     }
00310     return true;
00311 }
00312 
00313 
00314 
00315 bool Websocket::connected() {
00316     return m_connected;
00317 }
00318 
00319 std::string Websocket::getPath() {
00320     return path;
00321 }
00322 
00323 int Websocket::waitReadable(uint32_t timeout)
00324 {
00325   //Creating FS set
00326   fd_set socksSet;
00327   FD_ZERO(&socksSet);
00328   FD_SET(m_sockHandle, &socksSet);
00329   struct timeval t_val;
00330   t_val.tv_sec = timeout / 1000;
00331   t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000;
00332   int ret = socket::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val);
00333   if(ret <= 0 || !FD_ISSET(m_sockHandle, &socksSet))
00334   {
00335     return -1; //Timeout
00336   }
00337   return 0;
00338 }
00339 
00340 int Websocket::waitWriteable(uint32_t timeout)
00341 {
00342   //Creating FS set
00343   fd_set socksSet;
00344   FD_ZERO(&socksSet);
00345   FD_SET(m_sockHandle, &socksSet);
00346   struct timeval t_val;
00347   t_val.tv_sec = timeout / 1000;
00348   t_val.tv_usec = (timeout - (t_val.tv_sec * 1000)) * 1000;
00349   int ret = socket::select(FD_SETSIZE, NULL, &socksSet, NULL, &t_val);
00350   if(ret <= 0 || !FD_ISSET(m_sockHandle, &socksSet))
00351   {
00352     return -1; //Timeout
00353   }
00354   return 0;
00355 }
00356 
00357 int Websocket::read(uint8_t* buf, int minLen, int maxLen, uint32_t timeout)
00358 {
00359   if(!m_connected)
00360   {
00361     return -1;
00362   }
00363   int readLen = 0;
00364   do
00365   {
00366     int ret = waitReadable(timeout);
00367     if(ret == -1)
00368     {
00369       WARN("Wait readable returned %d",ret);
00370       close();
00371       return -1;
00372     }
00373     ret = socket::recv(m_sockHandle, buf + readLen, maxLen - readLen, 0/*MSG_DONTWAIT*/);
00374     if(ret > 0)
00375     {
00376       readLen += ret;
00377     }
00378     else if(ret==0) //Connection closed
00379     {
00380       WARN("Recv returned %d",ret);
00381       return readLen;
00382     }
00383     else
00384     {
00385       WARN("Recv returned %d",ret);
00386       close();
00387       return -1;
00388     }
00389   } while(readLen < minLen);
00390   return readLen;
00391 }
00392 
00393 int Websocket::write(uint8_t* buf, int len, uint32_t timeout)
00394 {
00395   if(!m_connected)
00396   {
00397     return -1;
00398   }
00399   int writtenLen = 0;
00400   do
00401   {
00402     int ret = waitWriteable(timeout);
00403     if(ret == -1)
00404     {
00405       WARN("Wait writeable returned %d",ret);
00406       close();
00407       return -1;
00408     }
00409     ret = socket::send(m_sockHandle, buf + writtenLen, len - writtenLen, 0/*MSG_DONTWAIT*/); //FIXME Probably DO WAIT to avoid overflow
00410     if(ret > 0)
00411     {
00412       writtenLen += ret;
00413     }
00414     else if(ret==0) //Connection closed
00415     {
00416       WARN("Send returned %d",ret);
00417       return writtenLen;
00418     }
00419     else
00420     {
00421       WARN("Send returned %d",ret);
00422       close(); //Must reset
00423       return -1;
00424     }
00425   } while(writtenLen < len);
00426   return writtenLen;
00427 }
00428 
00429 void Websocket::timeoutHandler()
00430 {
00431 
00432 }