httpserv.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 by egnite GmbH
00003  * Copyright (C) 2001-2004 by egnite Software GmbH
00004  *
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the copyright holders nor the names of
00017  *    contributors may be used to endorse or promote products derived
00018  *    from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00024  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * For additional information see http://www.ethernut.de/
00034  *
00035  */
00036 
00120 /* 
00121  * Unique MAC address of the Ethernut Board. 
00122  *
00123  * Ignored if EEPROM contains a valid configuration.
00124  */
00125 #define MY_MAC  "\x00\x06\x98\x30\x00\x35"
00126 
00127 /* 
00128  * Unique IP address of the Ethernut Board. 
00129  *
00130  * Ignored if DHCP is used. 
00131  */
00132 #define MY_IPADDR "192.168.192.35"
00133 
00134 /* 
00135  * IP network mask of the Ethernut Board.
00136  *
00137  * Ignored if DHCP is used. 
00138  */
00139 #define MY_IPMASK "255.255.255.0"
00140 
00141 /* 
00142  * Gateway IP address for the Ethernut Board.
00143  *
00144  * Ignored if DHCP is used. 
00145  */
00146 #define MY_IPGATE "192.168.192.1"
00147 
00148 /* ICCAVR Demo is limited. Try to use the bare minimum. */
00149 #if !defined(__IMAGECRAFT__)
00150 
00151 /* Wether we should use DHCP. */
00152 #define USE_DHCP
00153 /* Wether we should run a discovery responder. */
00154 #define USE_DISCOVERY
00155 /* Wether to use PHAT file system. */
00156 //#define USE_PHAT
00157 
00158 #if defined(__ARM__)
00159 /* Wether we should use ASP. */
00160 #define USE_ASP
00161 /* Wether we should use SSI. */
00162 #define USE_SSI
00163 #endif
00164 
00165 #endif /* __IMAGECRAFT__ */
00166 
00167 
00168 #ifdef USE_PHAT
00169 
00170 #if defined(ETHERNUT3)
00171 
00172 /* Ethernut 3 file system. */
00173 #define MY_FSDEV       devPhat0
00174 #define MY_FSDEV_NAME  "PHAT0" 
00175 
00176 /* Ethernut 3 block device interface. */
00177 #define MY_BLKDEV      devNplMmc0
00178 #define MY_BLKDEV_NAME "MMC0"
00179 
00180 #elif defined(AT91SAM7X_EK)
00181 
00182 /* SAM7X-EK file system. */
00183 #define MY_FSDEV       devPhat0
00184 #define MY_FSDEV_NAME  "PHAT0" 
00185 
00186 /* SAM7X-EK block device interface. */
00187 #define MY_BLKDEV      devAt91SpiMmc0
00188 #define MY_BLKDEV_NAME "MMC0"
00189 
00190 #elif defined(AT91SAM9260_EK)
00191 
00192 /* SAM9260-EK file system. */
00193 #define MY_FSDEV       devPhat0
00194 #define MY_FSDEV_NAME  "PHAT0" 
00195 
00196 /* SAM9260-EK block device interface. */
00197 #define MY_BLKDEV      devAt91Mci0
00198 #define MY_BLKDEV_NAME "MCI0"
00199 
00200 #endif
00201 #endif /* USE_PHAT */
00202 
00203 #ifndef MY_FSDEV
00204 #define MY_FSDEV        devUrom
00205 #endif
00206 
00207 #ifdef MY_FSDEV_NAME
00208 #define MY_HTTPROOT     MY_FSDEV_NAME ":/" 
00209 #endif
00210 
00211 
00212 #include <cfg/os.h>
00213 
00214 #include <string.h>
00215 #include <io.h>
00216 #include <fcntl.h>
00217 #include <time.h>
00218 
00219 #include <dev/board.h>
00220 #include <dev/urom.h>
00221 #include <dev/nplmmc.h>
00222 #include <dev/sbimmc.h>
00223 #include <fs/phatfs.h>
00224 
00225 #include <sys/version.h>
00226 #include <sys/thread.h>
00227 #include <sys/timer.h>
00228 #include <sys/heap.h>
00229 #include <sys/confnet.h>
00230 #include <sys/socket.h>
00231 
00232 #include <arpa/inet.h>
00233 #include <net/route.h>
00234 
00235 #include <pro/httpd.h>
00236 #include <pro/dhcp.h>
00237 #include <pro/ssi.h>
00238 #include <pro/asp.h>
00239 #include <pro/discover.h>
00240 
00241 #ifdef NUTDEBUG
00242 #include <sys/osdebug.h>
00243 #include <net/netdebug.h>
00244 #endif
00245 
00246 /* Server thread stack size. */
00247 #ifndef HTTPD_SERVICE_STACK
00248 #if defined(__AVR__)
00249 #define HTTPD_SERVICE_STACK ((580 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
00250 #elif defined(__arm__)
00251 #define HTTPD_SERVICE_STACK ((1024 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
00252 #else
00253 #define HTTPD_SERVICE_STACK  ((2048 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
00254 #endif
00255 #endif
00256 
00257 static char *html_mt = "text/html";
00258 
00259 #ifdef DEV_ETHER
00260 
00261 #if defined(USE_ASP)
00262 /**************************************************************/
00263 /*  ASPCallback                                               */
00264 /*                                                            */
00265 /* This routine must have been registered by                  */
00266 /* NutRegisterAspCallback() and is automatically called by    */
00267 /* NutHttpProcessFileRequest() when the server process a page */
00268 /* with an asp function.                                      */
00269 /*                                                            */
00270 /* Return 0 on success, -1 otherwise.                         */
00271 /**************************************************************/
00272 
00273 
00274 static int ASPCallback (char *pASPFunction, FILE *stream)
00275 {
00276     if (strcmp(pASPFunction, "usr_date") == 0) {
00277         fprintf(stream, "Dummy example: 01.01.2005");
00278         return(0);
00279     }
00280 
00281     if (strcmp(pASPFunction, "usr_time") == 0) {
00282         fprintf(stream, "Dummy example: 12:15:02");
00283         return(0);
00284     }
00285 
00286     return (-1);
00287 }
00288 #endif
00289 
00290 /*
00291  * CGI Sample: Show request parameters.
00292  *
00293  * See httpd.h for REQUEST structure.
00294  *
00295  * This routine must have been registered by NutRegisterCgi() and is
00296  * automatically called by NutHttpProcessRequest() when the client
00297  * request the URL 'cgi-bin/test.cgi'.
00298  */
00299 static int ShowQuery(FILE * stream, REQUEST * req)
00300 {
00301     char *cp;
00302     /*
00303      * This may look a little bit weird if you are not used to C programming
00304      * for flash microcontrollers. The special type 'prog_char' forces the
00305      * string literals to be placed in flash ROM. This saves us a lot of
00306      * precious RAM.
00307      */
00308     static prog_char head[] = "<HTML><HEAD><TITLE>Parameters</TITLE></HEAD><BODY><H1>Parameters</H1>";
00309     static prog_char foot[] = "</BODY></HTML>";
00310     static prog_char req_fmt[] = "Method: %s<BR>\r\nVersion: HTTP/%d.%d<BR>\r\nContent length: %ld<BR>\r\n";
00311     static prog_char url_fmt[] = "URL: %s<BR>\r\n";
00312     static prog_char query_fmt[] = "Argument: %s<BR>\r\n";
00313     static prog_char type_fmt[] = "Content type: %s<BR>\r\n";
00314     static prog_char cookie_fmt[] = "Cookie: %s<BR>\r\n";
00315     static prog_char auth_fmt[] = "Auth info: %s<BR>\r\n";
00316     static prog_char agent_fmt[] = "User agent: %s<BR>\r\n";
00317 
00318     /* These useful API calls create a HTTP response for us. */
00319     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00320     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00321 
00322     /* Send HTML header. */
00323     fputs_P(head, stream);
00324 
00325     /*
00326      * Send request parameters.
00327      */
00328     switch (req->req_method) {
00329     case METHOD_GET:
00330         cp = "GET";
00331         break;
00332     case METHOD_POST:
00333         cp = "POST";
00334         break;
00335     case METHOD_HEAD:
00336         cp = "HEAD";
00337         break;
00338     default:
00339         cp = "UNKNOWN";
00340         break;
00341     }
00342     fprintf_P(stream, req_fmt, cp, req->req_version / 10, req->req_version % 10, req->req_length);
00343     if (req->req_url)
00344         fprintf_P(stream, url_fmt, req->req_url);
00345     if (req->req_query)
00346         fprintf_P(stream, query_fmt, req->req_query);
00347     if (req->req_type)
00348         fprintf_P(stream, type_fmt, req->req_type);
00349     if (req->req_cookie)
00350         fprintf_P(stream, cookie_fmt, req->req_cookie);
00351     if (req->req_auth)
00352         fprintf_P(stream, auth_fmt, req->req_auth);
00353     if (req->req_agent)
00354         fprintf_P(stream, agent_fmt, req->req_agent);
00355 
00356     /* Send HTML footer and flush output buffer. */
00357     fputs_P(foot, stream);
00358     fflush(stream);
00359 
00360     return 0;
00361 }
00362 
00363 /*
00364  * CGI Sample: Show list of threads.
00365  *
00366  * This routine must have been registered by NutRegisterCgi() and is
00367  * automatically called by NutHttpProcessRequest() when the client
00368  * request the URL 'cgi-bin/threads.cgi'.
00369  */
00370 static int ShowThreads(FILE * stream, REQUEST * req)
00371 {
00372     static prog_char head[] = "<HTML><HEAD><TITLE>Threads</TITLE></HEAD><BODY><H1>Threads</H1>\r\n"
00373         "<TABLE BORDER><TR><TH>Handle</TH><TH>Name</TH><TH>Priority</TH><TH>Status</TH><TH>Event<BR>Queue</TH><TH>Timer</TH><TH>Stack-<BR>pointer</TH><TH>Free<BR>Stack</TH></TR>\r\n";
00374 #if defined(__AVR__)
00375     static prog_char tfmt[] =
00376         "<TR><TD>%04X</TD><TD>%s</TD><TD>%u</TD><TD>%s</TD><TD>%04X</TD><TD>%04X</TD><TD>%04X</TD><TD>%u</TD><TD>%s</TD></TR>\r\n";
00377 #else
00378     static prog_char tfmt[] =
00379         "<TR><TD>%08lX</TD><TD>%s</TD><TD>%u</TD><TD>%s</TD><TD>%08lX</TD><TD>%08lX</TD><TD>%08lX</TD><TD>%lu</TD><TD>%s</TD></TR>\r\n";
00380 #endif
00381     static prog_char foot[] = "</TABLE></BODY></HTML>";
00382     static char *thread_states[] = { "TRM", "<FONT COLOR=#CC0000>RUN</FONT>", "<FONT COLOR=#339966>RDY</FONT>", "SLP" };
00383     NUTTHREADINFO *tdp = nutThreadList;
00384 
00385     /* Send HTTP response. */
00386     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00387     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00388 
00389     /* Send HTML header. */
00390     fputs_P(head, stream);
00391     for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
00392         fprintf_P(stream, tfmt, (uptr_t) tdp, tdp->td_name, tdp->td_priority,
00393                   thread_states[tdp->td_state], (uptr_t) tdp->td_queue, (uptr_t) tdp->td_timer,
00394                   (uptr_t) tdp->td_sp, (uptr_t) tdp->td_sp - (uptr_t) tdp->td_memory,
00395                   *((u_long *) tdp->td_memory) != DEADBEEF ? "Corr" : "OK");
00396     }
00397     fputs_P(foot, stream);
00398     fflush(stream);
00399 
00400     return 0;
00401 }
00402 
00403 /*
00404  * CGI Sample: Show list of timers.
00405  *
00406  * This routine must have been registered by NutRegisterCgi() and is
00407  * automatically called by NutHttpProcessRequest() when the client
00408  * request the URL 'cgi-bin/timers.cgi'.
00409  */
00410 static int ShowTimers(FILE * stream, REQUEST * req)
00411 {
00412     static prog_char head[] = "<HTML><HEAD><TITLE>Timers</TITLE></HEAD><BODY><H1>Timers</H1>\r\n";
00413     static prog_char thead[] =
00414         "<TABLE BORDER><TR><TH>Handle</TH><TH>Countdown</TH><TH>Tick Reload</TH><TH>Callback<BR>Address</TH><TH>Callback<BR>Argument</TH></TR>\r\n";
00415 #if defined(__AVR__)
00416     static prog_char tfmt[] = "<TR><TD>%04X</TD><TD>%lu</TD><TD>%lu</TD><TD>%04X</TD><TD>%04X</TD></TR>\r\n";
00417 #else
00418     static prog_char tfmt[] = "<TR><TD>%08lX</TD><TD>%lu</TD><TD>%lu</TD><TD>%08lX</TD><TD>%08lX</TD></TR>\r\n";
00419 #endif
00420     static prog_char foot[] = "</TABLE></BODY></HTML>";
00421     NUTTIMERINFO *tnp;
00422     u_long ticks_left;
00423 
00424     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00425     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00426 
00427     /* Send HTML header. */
00428     fputs_P(head, stream);
00429     if ((tnp = nutTimerList) != 0) {
00430         fputs_P(thead, stream);
00431         ticks_left = 0;
00432         while (tnp) {
00433             ticks_left += tnp->tn_ticks_left;
00434             fprintf_P(stream, tfmt, (uptr_t) tnp, ticks_left, tnp->tn_ticks, (uptr_t) tnp->tn_callback, (uptr_t) tnp->tn_arg);
00435             tnp = tnp->tn_next;
00436         }
00437     }
00438 
00439     fputs_P(foot, stream);
00440     fflush(stream);
00441 
00442     return 0;
00443 }
00444 
00445 /*
00446  * CGI Sample: Show list of sockets.
00447  *
00448  * This routine must have been registered by NutRegisterCgi() and is
00449  * automatically called by NutHttpProcessRequest() when the client
00450  * request the URL 'cgi-bin/sockets.cgi'.
00451  */
00452 static int ShowSockets(FILE * stream, REQUEST * req)
00453 {
00454     /* String literals are kept in flash ROM. */
00455     static prog_char head[] = "<HTML><HEAD><TITLE>Sockets</TITLE></HEAD>"
00456         "<BODY><H1>Sockets</H1>\r\n"
00457         "<TABLE BORDER><TR><TH>Handle</TH><TH>Type</TH><TH>Local</TH><TH>Remote</TH><TH>Status</TH></TR>\r\n";
00458 #if defined(__AVR__)
00459     static prog_char tfmt1[] = "<TR><TD>%04X</TD><TD>TCP</TD><TD>%s:%u</TD>";
00460 #else
00461     static prog_char tfmt1[] = "<TR><TD>%08lX</TD><TD>TCP</TD><TD>%s:%u</TD>";
00462 #endif
00463     static prog_char tfmt2[] = "<TD>%s:%u</TD><TD>";
00464     static prog_char foot[] = "</TABLE></BODY></HTML>";
00465     static prog_char st_listen[] = "LISTEN";
00466     static prog_char st_synsent[] = "SYNSENT";
00467     static prog_char st_synrcvd[] = "SYNRCVD";
00468     static prog_char st_estab[] = "<FONT COLOR=#CC0000>ESTABL</FONT>";
00469     static prog_char st_finwait1[] = "FINWAIT1";
00470     static prog_char st_finwait2[] = "FINWAIT2";
00471     static prog_char st_closewait[] = "CLOSEWAIT";
00472     static prog_char st_closing[] = "CLOSING";
00473     static prog_char st_lastack[] = "LASTACK";
00474     static prog_char st_timewait[] = "TIMEWAIT";
00475     static prog_char st_closed[] = "CLOSED";
00476     static prog_char st_unknown[] = "UNKNOWN";
00477     prog_char *st_P;
00478     extern TCPSOCKET *tcpSocketList;
00479     TCPSOCKET *ts;
00480 
00481     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00482     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00483 
00484     /* Send HTML header. */
00485     fputs_P(head, stream);
00486     for (ts = tcpSocketList; ts; ts = ts->so_next) {
00487         switch (ts->so_state) {
00488         case TCPS_LISTEN:
00489             st_P = (prog_char *) st_listen;
00490             break;
00491         case TCPS_SYN_SENT:
00492             st_P = (prog_char *) st_synsent;
00493             break;
00494         case TCPS_SYN_RECEIVED:
00495             st_P = (prog_char *) st_synrcvd;
00496             break;
00497         case TCPS_ESTABLISHED:
00498             st_P = (prog_char *) st_estab;
00499             break;
00500         case TCPS_FIN_WAIT_1:
00501             st_P = (prog_char *) st_finwait1;
00502             break;
00503         case TCPS_FIN_WAIT_2:
00504             st_P = (prog_char *) st_finwait2;
00505             break;
00506         case TCPS_CLOSE_WAIT:
00507             st_P = (prog_char *) st_closewait;
00508             break;
00509         case TCPS_CLOSING:
00510             st_P = (prog_char *) st_closing;
00511             break;
00512         case TCPS_LAST_ACK:
00513             st_P = (prog_char *) st_lastack;
00514             break;
00515         case TCPS_TIME_WAIT:
00516             st_P = (prog_char *) st_timewait;
00517             break;
00518         case TCPS_CLOSED:
00519             st_P = (prog_char *) st_closed;
00520             break;
00521         default:
00522             st_P = (prog_char *) st_unknown;
00523             break;
00524         }
00525         /*
00526          * Fixed a bug reported by Zhao Weigang.
00527          */
00528         fprintf_P(stream, tfmt1, (uptr_t) ts, inet_ntoa(ts->so_local_addr), ntohs(ts->so_local_port));
00529         fprintf_P(stream, tfmt2, inet_ntoa(ts->so_remote_addr), ntohs(ts->so_remote_port));
00530         fputs_P(st_P, stream);
00531         fputs("</TD></TR>\r\n", stream);
00532         fflush(stream);
00533     }
00534 
00535     fputs_P(foot, stream);
00536     fflush(stream);
00537 
00538     return 0;
00539 }
00540 
00541 /*
00542  * CGI Sample: Proccessing a form.
00543  *
00544  * This routine must have been registered by NutRegisterCgi() and is
00545  * automatically called by NutHttpProcessRequest() when the client
00546  * request the URL 'cgi-bin/form.cgi'.
00547  *
00548  * Thanks to Tom Boettger, who provided this sample for ICCAVR.
00549  */
00550 int ShowForm(FILE * stream, REQUEST * req)
00551 {
00552     static prog_char html_head[] = "<HTML><BODY><BR><H1>Form Result</H1><BR><BR>";
00553     static prog_char html_body[] = "<BR><BR><p><a href=\"../index.html\">return to main</a></BODY></HTML></p>";
00554 
00555     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00556     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00557 
00558     /* Send HTML header. */
00559     fputs_P(html_head, stream);
00560 
00561     if (req->req_query) {
00562         char *name;
00563         char *value;
00564         int i;
00565         int count;
00566 
00567         count = NutHttpGetParameterCount(req);
00568         /* Extract count parameters. */
00569         for (i = 0; i < count; i++) {
00570             name = NutHttpGetParameterName(req, i);
00571             value = NutHttpGetParameterValue(req, i);
00572 
00573             /* Send the parameters back to the client. */
00574 
00575 #ifdef __IMAGECRAFT__
00576             fprintf(stream, "%s: %s<BR>\r\n", name, value);
00577 #else
00578             fprintf_P(stream, PSTR("%s: %s<BR>\r\n"), name, value);
00579 #endif
00580         }
00581     }
00582 
00583     fputs_P(html_body, stream);
00584     fflush(stream);
00585 
00586     return 0;
00587 }
00588 
00589 #if defined(USE_SSI)
00590 /*
00591  * CGI Sample: Dynamic output cgi included by ssi.shtml file
00592  *
00593  * This routine must have been registered by NutRegisterCgi() and is
00594  * automatically called by NutHttpProcessRequest() when the client
00595  * request the URL 'cgi-bin/form.cgi'.
00596  *
00597  * Thanks to Tom Boettger, who provided this sample for ICCAVR.
00598  */
00599 int SSIDemoCGI(FILE * stream, REQUEST * req)
00600 {
00601     if (req->req_query) {
00602         char *name;
00603         char *value;
00604         int i;
00605         int count;
00606 
00607         count = NutHttpGetParameterCount(req);
00608         
00609         /* Extract count parameters. */
00610 #ifdef __IMAGECRAFT__        
00611         fprintf(stream, "CGI ssi-demo.cgi called with parameters: These are the parameters\r\n<p>");
00612 #else
00613         fprintf_P(stream, PSTR("CGI ssi-demo.cgi called with parameters: These are the parameters\r\n<p>"));
00614 #endif
00615         for (i = 0; i < count; i++) {
00616             name = NutHttpGetParameterName(req, i);
00617             value = NutHttpGetParameterValue(req, i);
00618 
00619             /* Send the parameters back to the client. */
00620 
00621 #ifdef __IMAGECRAFT__
00622             fprintf(stream, "%s: %s<BR>\r\n", name, value);
00623 #else
00624             fprintf_P(stream, PSTR("%s: %s<BR>\r\n"), name, value);
00625 #endif
00626         }
00627     } else {
00628         time_t now;
00629         tm     loc_time;
00630         
00631         /* Called without any parameter, show the current time */
00632         now = time(NULL);
00633         localtime_r(&now, &loc_time);
00634 #ifdef __IMAGECRAFT__        
00635         fprintf(stream, "CGI ssi-demo.cgi called without any parameter.<br><br>Current time is: %02d.%02d.%04d -- %02d:%02d:%02d<br>\r\n",
00636                   loc_time.tm_mday, loc_time.tm_mon+1, loc_time.tm_year+1900, loc_time.tm_hour, loc_time.tm_min, loc_time.tm_sec);
00637 #else 
00638         fprintf_P(stream, PSTR("CGI ssi-demo.cgi called without any parameter.<br><br>Current time is: %02d.%02d.%04d -- %02d:%02d:%02d<br>\r\n"),
00639                   loc_time.tm_mday, loc_time.tm_mon+1, loc_time.tm_year+1900, loc_time.tm_hour, loc_time.tm_min, loc_time.tm_sec);
00640 #endif
00641     }
00642 
00643     fflush(stream);
00644 
00645     return 0;
00646 }
00647 #endif
00648 
00661 THREAD(Service, arg)
00662 {
00663     TCPSOCKET *sock;
00664     FILE *stream;
00665     u_char id = (u_char) ((uptr_t) arg);
00666 
00667     /*
00668      * Now loop endless for connections.
00669      */
00670     for (;;) {
00671 
00672         /*
00673          * Create a socket.
00674          */
00675         if ((sock = NutTcpCreateSocket()) == 0) {
00676             printf("[%u] Creating socket failed\n", id);
00677             NutSleep(5000);
00678             continue;
00679         }
00680 
00681         /*
00682          * Listen on port 80. This call will block until we get a connection
00683          * from a client.
00684          */
00685         NutTcpAccept(sock, 80);
00686 #if defined(__AVR__)
00687         printf("[%u] Connected, %u bytes free\n", id, NutHeapAvailable());
00688 #else
00689         printf("[%u] Connected, %lu bytes free\n", id, NutHeapAvailable());
00690 #endif
00691 
00692         /*
00693          * Wait until at least 8 kByte of free RAM is available. This will
00694          * keep the client connected in low memory situations.
00695          */
00696 #if defined(__AVR__)
00697         while (NutHeapAvailable() < 8192) {
00698 #else
00699         while (NutHeapAvailable() < 4096) {
00700 #endif
00701             printf("[%u] Low mem\n", id);
00702             NutSleep(1000);
00703         }
00704 
00705         /*
00706          * Associate a stream with the socket so we can use standard I/O calls.
00707          */
00708         if ((stream = _fdopen((int) ((uptr_t) sock), "r+b")) == 0) {
00709             printf("[%u] Creating stream device failed\n", id);
00710         } else {
00711             /*
00712              * This API call saves us a lot of work. It will parse the
00713              * client's HTTP request, send any requested file from the
00714              * registered file system or handle CGI requests by calling
00715              * our registered CGI routine.
00716              */
00717             NutHttpProcessRequest(stream);
00718 
00719             /*
00720              * Destroy the virtual stream device.
00721              */
00722             fclose(stream);
00723         }
00724 
00725         /*
00726          * Close our socket.
00727          */
00728         NutTcpCloseSocket(sock);
00729         printf("[%u] Disconnected\n", id);
00730     }
00731 }
00732 #endif /* DEV_ETHER */
00733 
00739 int main(void)
00740 {
00741     u_long baud = 115200;
00742     u_char i;
00743 
00744     /*
00745      * Initialize the uart device.
00746      */
00747     NutRegisterDevice(&DEV_DEBUG, 0, 0);
00748     freopen(DEV_DEBUG_NAME, "w", stdout);
00749     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00750     NutSleep(200);
00751     printf("\n\nNut/OS %s HTTP Daemon...", NutVersionString());
00752 
00753 #ifdef DEV_ETHER
00754 
00755 #ifdef NUTDEBUG
00756     NutTraceTcp(stdout, 0);
00757     NutTraceOs(stdout, 0);
00758     NutTraceHeap(stdout, 0);
00759     NutTracePPP(stdout, 0);
00760 #endif
00761 
00762     /*
00763      * Register Ethernet controller.
00764      */
00765     if (NutRegisterDevice(&DEV_ETHER, 0, 0)) {
00766         puts("Registering device failed");
00767     }
00768 
00769     printf("Configure %s...", DEV_ETHER_NAME);
00770     if (NutNetLoadConfig(DEV_ETHER_NAME)) {
00771         u_char mac[] = MY_MAC;
00772 
00773         printf("initial boot...");
00774 #ifdef USE_DHCP
00775         if (NutDhcpIfConfig(DEV_ETHER_NAME, mac, 60000)) 
00776 #endif
00777         {
00778             u_long ip_addr = inet_addr(MY_IPADDR);
00779             u_long ip_mask = inet_addr(MY_IPMASK);
00780             u_long ip_gate = inet_addr(MY_IPGATE);
00781 
00782             printf("No DHCP...");
00783             if (NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask) == 0) {
00784                 /* Without DHCP we had to set the default gateway manually.*/
00785                 if(ip_gate) {
00786                     printf("hard coded gate...");
00787                     NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
00788                 }
00789                 puts("OK");
00790             }
00791             else {
00792                 puts("failed");
00793             }
00794         }
00795     }
00796     else {
00797 #ifdef USE_DHCP
00798         if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000)) {
00799             puts("failed");
00800         }
00801         else {
00802             puts("OK");
00803         }
00804 #else
00805         if (NutNetIfConfig(DEV_ETHER_NAME, 0, 0, confnet.cdn_ip_mask)) {
00806             puts("failed");
00807         }
00808         else {
00809             puts("OK");
00810         }
00811 #endif
00812     }
00813     printf("%s ready\n", inet_ntoa(confnet.cdn_ip_addr));
00814 
00815 #ifdef USE_DISCOVERY
00816     NutRegisterDiscovery((u_long)-1, 0, DISF_INITAL_ANN);
00817 #endif
00818 
00819     /*
00820      * Register our device for the file system.
00821      */
00822     NutRegisterDevice(&MY_FSDEV, 0, 0);
00823 
00824 #ifdef MY_BLKDEV
00825     /* Register block device. */
00826     printf("Registering block device '" MY_BLKDEV_NAME "'...");
00827     if (NutRegisterDevice(&MY_BLKDEV, 0, 0)) {
00828         puts("failed");
00829         for (;;);
00830     }
00831     puts("OK");
00832 
00833     /* Mount partition. */
00834     printf("Mounting block device '" MY_BLKDEV_NAME ":1/" MY_FSDEV_NAME "'...");
00835     if (_open(MY_BLKDEV_NAME ":1/" MY_FSDEV_NAME, _O_RDWR | _O_BINARY) == -1) {
00836         puts("failed");
00837         for (;;);
00838     }
00839     puts("OK");
00840 #endif
00841 
00842 #ifdef MY_HTTPROOT
00843     /* Register root path. */
00844     printf("Registering HTTP root '" MY_HTTPROOT "'...");
00845     if (NutRegisterHttpRoot(MY_HTTPROOT)) {
00846         puts("failed");
00847         for (;;);
00848     }
00849     puts("OK");
00850 #endif
00851 
00852     NutRegisterCgiBinPath("cgi-bin/;user/cgi-bin/;admin/cgi-bin/");
00853 
00854 
00855     /*
00856      * Register our CGI sample. This will be called
00857      * by http://host/cgi-bin/test.cgi?anyparams
00858      */
00859     NutRegisterCgi("test.cgi", ShowQuery);
00860 
00861 #if defined(USE_SSI)
00862     /* 
00863      * Register a cgi included by the ssi demo. This will show how dynamic 
00864      * content is included in a ssi page and how the request parameters for 
00865      * a site are passed down to the included cgi.
00866      */    
00867     NutRegisterCgi("ssi-demo.cgi", SSIDemoCGI);
00868 #endif
00869 
00870     /*
00871      * Register some CGI samples, which display interesting
00872      * system informations.
00873      */
00874     NutRegisterCgi("threads.cgi", ShowThreads);
00875     NutRegisterCgi("timers.cgi", ShowTimers);
00876     NutRegisterCgi("sockets.cgi", ShowSockets);
00877 
00878     /*
00879      * Finally a CGI example to process a form.
00880      */
00881     NutRegisterCgi("form.cgi", ShowForm);
00882 
00883     /*
00884      * Protect the cgi-bin directory with
00885      * user and password.
00886      */
00887     NutRegisterAuth("admin", "root:root");
00888     NutRegisterAuth("user", "user:user");
00889 
00890     /*
00891      * Register SSI and ASP handler
00892      */
00893 #if defined(USE_SSI)
00894     NutRegisterSsi();
00895 #endif
00896 #if defined(USE_ASP)
00897     NutRegisterAsp();
00898     NutRegisterAspCallback(ASPCallback);
00899 #endif
00900 
00901     /*
00902      * Start four server threads.
00903      */
00904     for (i = 1; i <= 4; i++) {
00905         char thname[] = "httpd0";
00906 
00907         thname[5] = '0' + i;
00908         NutThreadCreate(thname, Service, (void *) (uptr_t) i, 
00909             (HTTPD_SERVICE_STACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD);
00910     }
00911 #endif /* DEV_ETHER */
00912 
00913     /*
00914      * We could do something useful here, like serving a watchdog.
00915      */
00916     NutThreadSetPriority(254);
00917     for (;;) {
00918         NutSleep(60000);
00919     }
00920     return 0;
00921 }

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/