Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.
HTTPRequestDispatcher.cpp
00001 00002 /* 00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a copy 00006 of this software and associated documentation files (the "Software"), to deal 00007 in the Software without restriction, including without limitation the rights 00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00009 copies of the Software, and to permit persons to whom the Software is 00010 furnished to do so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in 00013 all copies or substantial portions of the Software. 00014 00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00021 THE SOFTWARE. 00022 */ 00023 00024 #include "HTTPRequestDispatcher.h" 00025 #include "HTTPRequestHandler.h" 00026 #include <string.h> 00027 00028 //#define __DEBUG 00029 #include "dbg/dbg.h" 00030 00031 HTTPRequestDispatcher::HTTPRequestDispatcher(HTTPServer* pSvr, TCPSocket* pTCPSocket) : NetService(), m_pSvr(pSvr), m_pTCPSocket(pTCPSocket), m_watchdog(), m_closed(false) 00032 { 00033 m_pTCPSocket->setOnEvent(this, &HTTPRequestDispatcher::onTCPSocketEvent); 00034 m_watchdog.attach_us<HTTPRequestDispatcher>(this, &HTTPRequestDispatcher::onTimeout, HTTP_REQUEST_TIMEOUT * 1000); 00035 } 00036 00037 HTTPRequestDispatcher::~HTTPRequestDispatcher() 00038 { 00039 close(); 00040 } 00041 00042 void HTTPRequestDispatcher::dispatchRequest() 00043 { 00044 string rootPath; 00045 string fullPath; 00046 string meth; 00047 HTTP_METH methCode; 00048 00049 DBG("Dispatching req\r\n"); 00050 00051 if( !getRequest(&rootPath, &fullPath, &meth ) ) 00052 { 00053 close(); 00054 return; //Invalid request 00055 } 00056 00057 if( !meth.compare("GET") ) 00058 { 00059 methCode = HTTP_GET; 00060 } 00061 else if( !meth.compare("POST") ) 00062 { 00063 methCode = HTTP_POST; 00064 } 00065 else if( !meth.compare("HEAD") ) 00066 { 00067 methCode = HTTP_HEAD; 00068 } 00069 else 00070 { 00071 close(); //Parse error 00072 return; 00073 } 00074 00075 DBG("Looking for a handler\r\n"); 00076 00077 map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*) >::iterator it; 00078 it = m_pSvr->m_lpHandlers.find(rootPath); //We are friends so we can do that 00079 if(it == m_pSvr->m_lpHandlers.end()) 00080 { 00081 it = m_pSvr->m_lpHandlers.find(""); //Use default handler if it exists 00082 } 00083 if(it == m_pSvr->m_lpHandlers.end()) 00084 { 00085 close(); //No handler found 00086 return; 00087 } 00088 00089 DBG("Handler found.\r\n"); 00090 00091 HTTPRequestHandler* pHdlr = (*it).second(rootPath.c_str(), fullPath.c_str(), m_pTCPSocket); 00092 m_pTCPSocket = NULL; //We don't own it anymore 00093 00094 switch(methCode) 00095 { 00096 case HTTP_GET: 00097 pHdlr->doGet(); 00098 break; 00099 case HTTP_POST: 00100 pHdlr->doPost(); 00101 break; 00102 case HTTP_HEAD: 00103 pHdlr->doHead(); 00104 break; 00105 } 00106 00107 DBG("Req handled (or being handled)\r\n"); 00108 close(); 00109 } 00110 00111 void HTTPRequestDispatcher::close() //Close socket and destroy data 00112 { 00113 if(m_closed) 00114 return; 00115 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else 00116 m_watchdog.detach(); 00117 if(m_pTCPSocket) //m_pTCPSocket Should only be destroyed if ownership not passed to an handler 00118 { 00119 m_pTCPSocket->resetOnEvent(); 00120 m_pTCPSocket->close(); 00121 delete m_pTCPSocket; //This fn might have been called by this socket (through an event), so DO NOT DESTROY IT HERE 00122 } 00123 NetService::close(); 00124 } 00125 00126 00127 void HTTPRequestDispatcher::onTimeout() //Connection has timed out 00128 { 00129 close(); 00130 } 00131 00132 bool HTTPRequestDispatcher::getRequest(string* rootPath, string* fullPath, string* meth) 00133 { 00134 char req[128]; 00135 char c_path[128]; 00136 char c_meth[128]; 00137 const int maxLen = 128; 00138 char* p = req; 00139 //Read Line 00140 int ret; 00141 int len = 0; 00142 for(int i = 0; i < maxLen - 1; i++) 00143 { 00144 ret = m_pTCPSocket->recv(p, 1); 00145 if(!ret) 00146 { 00147 break; 00148 } 00149 if( (len > 1) && *(p-1)=='\r' && *p=='\n' ) 00150 { 00151 p--; 00152 len-=2; 00153 break; 00154 } 00155 else if( *p=='\n' ) 00156 { 00157 len--; 00158 break; 00159 } 00160 p++; 00161 len++; 00162 } 00163 *p = 0; 00164 00165 DBG("Parsing request : %s\r\n", req); 00166 00167 ret = sscanf(req, "%s %s HTTP/%*d.%*d", c_meth, c_path); 00168 if(ret !=2) 00169 return false; 00170 00171 *meth = string(c_meth); 00172 *fullPath = string(c_path); 00173 00174 c_path[0]= '/'; 00175 ret = sscanf(req, "%*s /%[^/ ]%*s HTTP/%*d.%*d", c_path+1); 00176 if(ret !=1) 00177 { 00178 //This is the root path 00179 } 00180 00181 *rootPath = string(c_path); 00182 00183 DBG("Parse OK :\r\nRoot Path : %s\r\nFull Path : %s\r\nMethod Path : %s\r\n", rootPath->c_str(), fullPath->c_str(), meth->c_str()); 00184 00185 return true; 00186 00187 } 00188 00189 00190 void HTTPRequestDispatcher::onTCPSocketEvent(TCPSocketEvent e) 00191 { 00192 00193 DBG("Event %d\r\n", e); 00194 00195 if(m_closed) 00196 { 00197 DBG("WARN: Discarded\r\n"); 00198 return; 00199 } 00200 00201 switch(e) 00202 { 00203 case TCPSOCKET_READABLE: 00204 m_watchdog.detach(); 00205 m_pTCPSocket->resetOnEvent(); 00206 //Req arrived, dispatch : 00207 dispatchRequest(); 00208 break; 00209 case TCPSOCKET_CONTIMEOUT: 00210 case TCPSOCKET_CONRST: 00211 case TCPSOCKET_CONABRT: 00212 case TCPSOCKET_ERROR: 00213 case TCPSOCKET_DISCONNECTED: 00214 close(); 00215 break; 00216 } 00217 00218 }
Generated on Tue Jul 12 2022 21:10:25 by 1.7.2