Sergei G / NetworkServices

Dependents:   coap-example Borsch coap-example

Fork of NetworkServices by AMETEK Powervar

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 HTTPD * HTTPD::_inst;
00022 
00023 HTTPD::HTTPD () {
00024     _inst = this;
00025     memset(_state, 0, sizeof(_state));
00026     _handler_count = 0;
00027 }
00028 
00029 int HTTPD::start (NetworkStack *ns, int port) {
00030     int i;
00031 
00032     m_ns = ns;
00033     
00034     for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
00035         _state[i].buf = new CircBuffer<char>(HTTPD_BUF_SIZE);
00036         _state[i].thread = new Thread(osPriorityNormal, HTTPD_STACK_SIZE);
00037         _state[i].client = new TCPSocket();
00038         _state[i].thread->start(callback(child, (void*)i));
00039     }
00040     
00041 #ifdef HTTPD_ENABLE_CLOSER
00042     _state[HTTPD_MAX_CLIENTS].thread = new Thread(closer, (void*)HTTPD_MAX_CLIENTS, osPriorityNormal, 128);
00043     _state[HTTPD_MAX_CLIENTS].client = new TCPSocket(m_ns);
00044 #endif
00045 
00046     _server.open(m_ns);
00047     _server.bind(port);
00048     _server.set_blocking(true);
00049     _server.listen();
00050     _daemon = new Thread(osPriorityNormal, HTTPD_STACK_SIZE);
00051     _daemon->start(HTTPD::daemon);
00052     return 0;
00053 }
00054 
00055 void HTTPD::daemon () {
00056     HTTPD *httpd = HTTPD::getInstance();
00057     int i, t = 0;
00058 
00059     INFO("Wait for new connection...\r\n");
00060     for (;;) {
00061         if (t >= 0) {
00062             if (httpd->_server.accept(httpd->_state[t].client) == 0) {
00063                 INFO("accept %d\r\n", t);
00064                 httpd->_state[t].thread->signal_set(1);
00065             }
00066         } else {
00067 #ifdef HTTPD_ENABLE_CLOSER
00068             if (httpd->_server.accept(httpd->_state[HTTPD_MAX_CLIENTS].client) == 0) {
00069                 INFO("accept x\r\n");
00070                 httpd->_state[HTTPD_MAX_CLIENTS].thread->signal_set(1);
00071             }
00072 #endif
00073         }
00074 
00075         t = -1;
00076         for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
00077             if (httpd->_state[i].thread->get_state() == Thread::WaitingAnd) {
00078                 if (t < 0) t = i; // next empty thread
00079             }
00080         }
00081     }
00082 }
00083 
00084 void HTTPD::child (void const *arg) {
00085     HTTPD *httpd = HTTPD::getInstance();
00086     int id = (int)arg;
00087     int i, n;
00088     char buf[HTTPD_BUF_SIZE];
00089 
00090     for (;;) {
00091         Thread::signal_wait(1);
00092         httpd->_state[id].mode = MODE_REQUEST;
00093         httpd->_state[id].buf->flush();
00094         httpd->_state[id].keepalive = 0;
00095         INFO("Connection from client\r\n");
00096 //      INFO("Connection from %s\r\n", httpd->_state[id].client->get_ip_address());
00097 
00098         httpd->_state[id].client->set_blocking(false);
00099         httpd->_state[id].client->set_timeout(HTTPD_TIMEOUT);
00100         
00101         for (;;) {
00102             //if (! httpd->_state[id].client->is_connected()) break;
00103 
00104             n = httpd->_state[id].client->recv(buf, sizeof(buf));
00105             
00106             if (n < 0 ) {
00107                 printf("HTTPD::child breaking n = %d\r\n", n);
00108                 break;
00109             }
00110             buf[n] = 0;
00111             //DBG("Recv %d ", n);
00112             DBG("Recv %d '%s'", n, buf);
00113 
00114             for (i = 0; i < n; i ++) {
00115                 httpd->recvData(id, buf[i]);
00116             }
00117         }
00118 
00119         httpd->_state[id].client->close();
00120         INFO("Closed client connection\r\n");
00121         //INFO("Close %s\r\n", httpd->_state[id].client->get_ip_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("Closed client connection\r\n");
00134         //INFO("Close %s\r\n", httpd->_state[id].client->get_ip_address());
00135     }
00136 }
00137