mbed_controller / HTTPD

Dependents:   mbed_controller_demo

Fork of HTTPD by Suga koubou

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPD.cpp Source File

HTTPD.cpp

00001 /* Copyright (C) 2013 Hiroshi Suga, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 
00019 #include "HTTPD.h"
00020 
00021 /*
00022 // There was hald fault error of HTTPD with Seeed Arch Max platform
00023 // because of stack overwritten.
00024 // According to the Callgraph report of Keil MDK 4.1,
00025 // the Max Depth is 424 bytes.
00026 HTTPD::daemon(const void*) (Thumb, 110 bytes, Stack size 0 bytes, httpd.o(.text)) 
00027 
00028 [Stack]
00029 
00030 Max Depth = 424 + Unknown Stack Size
00031 Call Chain = HTTPD::daemon(const void*) <-> TCPSocketServer::accept(TCPSocketConnection&) <->
00032 Socket::wait_readable(TimeInterval&) <-> Socket::select(timeval*, bool, bool) <->
00033 lwip_select <-> lwip_selscan <-> sys_arch_unprotect <-> error <-> exit (Cycle)
00034 */
00035 #define DAEMON_STACK_SIZE   512
00036 
00037 HTTPD * HTTPD::_inst;
00038 
00039 HTTPD::HTTPD () {
00040     _inst = this;
00041     memset(_state, 0, sizeof(_state));
00042     _handler_count = 0;
00043 }
00044 
00045 int HTTPD::start (int port) {
00046     int i;
00047 
00048     for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
00049         _state[i].buf = new CircBuffer<char>(HTTPD_BUF_SIZE);
00050         _state[i].thread = new Thread(child, (void*)i, osPriorityNormal, HTTPD_STACK_SIZE);
00051         _state[i].client = new TCPSocketConnection;
00052     }
00053 #ifdef HTTPD_ENABLE_CLOSER
00054     _state[HTTPD_MAX_CLIENTS].thread = new Thread(closer, (void*)HTTPD_MAX_CLIENTS, osPriorityNormal, 128);
00055     _state[HTTPD_MAX_CLIENTS].client = new TCPSocketConnection;
00056 #endif
00057 
00058     _server.bind(port);
00059     _server.listen();
00060     _daemon = new Thread(daemon, NULL, osPriorityNormal, DAEMON_STACK_SIZE);
00061     return 0;
00062 }
00063 
00064 void HTTPD::daemon (void const *args) {
00065     HTTPD *httpd = HTTPD::getInstance();
00066     int i, t = 0;
00067 
00068     INFO("Wait for new connection...\r\n");
00069     for (;;) {
00070         if (t >= 0) {
00071             if (httpd->_server.accept(*httpd->_state[t].client) == 0) {
00072                 INFO("accept %d\r\n", t);
00073                 httpd->_state[t].thread->signal_set(1);
00074             }
00075         } else {
00076 #ifdef HTTPD_ENABLE_CLOSER
00077             if (httpd->_server.accept(*httpd->_state[HTTPD_MAX_CLIENTS].client) == 0) {
00078                 INFO("accept x\r\n");
00079                 httpd->_state[HTTPD_MAX_CLIENTS].thread->signal_set(1);
00080             }
00081 #endif
00082         }
00083 
00084         t = -1;
00085         for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
00086             if (httpd->_state[i].thread->get_state() == Thread::WaitingAnd) {
00087                 if (t < 0) t = i; // next empty thread
00088             }
00089         }
00090     }
00091 }
00092 
00093 void HTTPD::child (void const *arg) {
00094     HTTPD *httpd = HTTPD::getInstance();
00095     int id = (int)arg;
00096     int i, n;
00097     char buf[HTTPD_BUF_SIZE];
00098 
00099     for (;;) {
00100         Thread::signal_wait(1);
00101 
00102         httpd->_state[id].mode = MODE_REQUEST;
00103         httpd->_state[id].buf->flush();
00104         httpd->_state[id].keepalive = 0;
00105         INFO("Connection from %s\r\n", httpd->_state[id].client->get_address());
00106         httpd->_state[id].client->set_blocking(false, HTTPD_TIMEOUT);
00107         for (;;) {
00108             if (! httpd->_state[id].client->is_connected()) break;
00109 
00110             n = httpd->_state[id].client->receive(buf, sizeof(buf)-1);
00111             if (n < 0) break;
00112             buf[n] = 0;
00113 //            DBG("Recv %d '%s'", n, buf);
00114 
00115             for (i = 0; i < n; i ++) {
00116                 httpd->recvData(id, buf[i]);
00117             }
00118         }
00119 
00120         httpd->_state[id].client->close();
00121         INFO("Close %s\r\n", httpd->_state[id].client->get_address());
00122     }
00123 }
00124 
00125 void HTTPD::closer (void const *arg) {
00126     HTTPD *httpd = HTTPD::getInstance();
00127     int id = (int)arg;
00128 
00129     for (;;) {
00130         Thread::signal_wait(1);
00131 
00132         httpd->_state[id].client->close();
00133         INFO("Close %s\r\n", httpd->_state[id].client->get_address());
00134     }
00135 }