Nut/OS  4.10.3
API Reference
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 THE COPYRIGHT HOLDERS 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 THE
00024  * COPYRIGHT OWNER 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 
00046 /* 
00047  * Unique MAC address of the Ethernut Board. 
00048  *
00049  * Ignored if EEPROM contains a valid configuration.
00050  */
00051 #define MY_MAC  "\x00\x06\x98\x30\x00\x35"
00052 
00053 /* 
00054  * Unique IP address of the Ethernut Board. 
00055  *
00056  * Ignored if DHCP is used. 
00057  */
00058 #define MY_IPADDR "192.168.192.35"
00059 
00060 /* 
00061  * IP network mask of the Ethernut Board.
00062  *
00063  * Ignored if DHCP is used. 
00064  */
00065 #define MY_IPMASK "255.255.255.0"
00066 
00067 /* 
00068  * Gateway IP address for the Ethernut Board.
00069  *
00070  * Ignored if DHCP is used. 
00071  */
00072 #define MY_IPGATE "192.168.192.1"
00073 
00074 /* ICCAVR Demo is limited. Try to use the bare minimum. */
00075 #if !defined(__IMAGECRAFT__)
00076 
00077 /* Wether we should use DHCP. */
00078 #define USE_DHCP
00079 /* Wether we should run a discovery responder. */
00080 #define USE_DISCOVERY
00081 /* Wether to use PHAT file system. */
00082 //#define USE_PHAT
00083 
00084 #if defined(__ARM__)
00085 /* Wether we should use ASP. */
00086 #define USE_ASP
00087 /* Wether we should use SSI. */
00088 #define USE_SSI
00089 #endif
00090 
00091 #endif /* __IMAGECRAFT__ */
00092 
00093 
00094 #ifdef USE_PHAT
00095 
00096 #if defined(ETHERNUT3)
00097 
00098 /* Ethernut 3 file system. */
00099 #define MY_FSDEV       devPhat0
00100 #define MY_FSDEV_NAME  "PHAT0" 
00101 
00102 /* Ethernut 3 block device interface. */
00103 #define MY_BLKDEV      devNplMmc0
00104 #define MY_BLKDEV_NAME "MMC0"
00105 
00106 #elif defined(AT91SAM7X_EK)
00107 
00108 /* SAM7X-EK file system. */
00109 #define MY_FSDEV       devPhat0
00110 #define MY_FSDEV_NAME  "PHAT0" 
00111 
00112 /* SAM7X-EK block device interface. */
00113 #define MY_BLKDEV      devAt91SpiMmc0
00114 #define MY_BLKDEV_NAME "MMC0"
00115 
00116 #elif defined(AT91SAM9260_EK)
00117 
00118 /* SAM9260-EK file system. */
00119 #define MY_FSDEV       devPhat0
00120 #define MY_FSDEV_NAME  "PHAT0" 
00121 
00122 /* SAM9260-EK block device interface. */
00123 #define MY_BLKDEV      devAt91Mci0
00124 #define MY_BLKDEV_NAME "MCI0"
00125 
00126 #endif
00127 #endif /* USE_PHAT */
00128 
00129 #ifndef MY_FSDEV
00130 #define MY_FSDEV        devUrom
00131 #endif
00132 
00133 #ifdef MY_FSDEV_NAME
00134 #define MY_HTTPROOT     MY_FSDEV_NAME ":/" 
00135 #endif
00136 
00137 
00138 #include <cfg/os.h>
00139 
00140 #include <string.h>
00141 #include <io.h>
00142 #include <fcntl.h>
00143 #include <time.h>
00144 
00145 #include <dev/board.h>
00146 #include <dev/urom.h>
00147 #include <dev/nplmmc.h>
00148 #include <dev/sbimmc.h>
00149 #include <fs/phatfs.h>
00150 
00151 #include <sys/version.h>
00152 #include <sys/thread.h>
00153 #include <sys/timer.h>
00154 #include <sys/heap.h>
00155 #include <sys/confnet.h>
00156 #include <sys/socket.h>
00157 
00158 #include <arpa/inet.h>
00159 #include <net/route.h>
00160 
00161 #include <pro/httpd.h>
00162 #include <pro/dhcp.h>
00163 #include <pro/ssi.h>
00164 #include <pro/asp.h>
00165 #include <pro/discover.h>
00166 
00167 #ifdef NUTDEBUG
00168 #include <sys/osdebug.h>
00169 #include <net/netdebug.h>
00170 #endif
00171 
00172 /* Server thread stack size. */
00173 #ifndef HTTPD_SERVICE_STACK
00174 #if defined(__AVR__)
00175 #define HTTPD_SERVICE_STACK ((580 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
00176 #elif defined(__arm__)
00177 #define HTTPD_SERVICE_STACK ((1024 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
00178 #else
00179 #define HTTPD_SERVICE_STACK  ((2048 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
00180 #endif
00181 #endif
00182 
00183 static char *html_mt = "text/html";
00184 
00185 #ifdef DEV_ETHER
00186 
00187 #if defined(USE_ASP)
00188 /**************************************************************/
00189 /*  ASPCallback                                               */
00190 /*                                                            */
00191 /* This routine must have been registered by                  */
00192 /* NutRegisterAspCallback() and is automatically called by    */
00193 /* NutHttpProcessFileRequest() when the server process a page */
00194 /* with an asp function.                                      */
00195 /*                                                            */
00196 /* Return 0 on success, -1 otherwise.                         */
00197 /**************************************************************/
00198 
00199 
00200 static int ASPCallback (char *pASPFunction, FILE *stream)
00201 {
00202     if (strcmp(pASPFunction, "usr_date") == 0) {
00203         fprintf(stream, "Dummy example: 01.01.2005");
00204         return(0);
00205     }
00206 
00207     if (strcmp(pASPFunction, "usr_time") == 0) {
00208         fprintf(stream, "Dummy example: 12:15:02");
00209         return(0);
00210     }
00211 
00212     return (-1);
00213 }
00214 #endif
00215 
00216 /*
00217  * CGI Sample: Show request parameters.
00218  *
00219  * See httpd.h for REQUEST structure.
00220  *
00221  * This routine must have been registered by NutRegisterCgi() and is
00222  * automatically called by NutHttpProcessRequest() when the client
00223  * request the URL 'cgi-bin/test.cgi'.
00224  */
00225 static int ShowQuery(FILE * stream, REQUEST * req)
00226 {
00227     char *cp;
00228     /*
00229      * This may look a little bit weird if you are not used to C programming
00230      * for flash microcontrollers. The special type 'prog_char' forces the
00231      * string literals to be placed in flash ROM. This saves us a lot of
00232      * precious RAM.
00233      */
00234     static prog_char head[] = "<HTML><HEAD><TITLE>Parameters</TITLE></HEAD><BODY><H1>Parameters</H1>";
00235     static prog_char foot[] = "</BODY></HTML>";
00236     static prog_char req_fmt[] = "Method: %s<BR>\r\nVersion: HTTP/%d.%d<BR>\r\nContent length: %ld<BR>\r\n";
00237     static prog_char url_fmt[] = "URL: %s<BR>\r\n";
00238     static prog_char query_fmt[] = "Argument: %s<BR>\r\n";
00239     static prog_char type_fmt[] = "Content type: %s<BR>\r\n";
00240     static prog_char cookie_fmt[] = "Cookie: %s<BR>\r\n";
00241     static prog_char auth_fmt[] = "Auth info: %s<BR>\r\n";
00242     static prog_char agent_fmt[] = "User agent: %s<BR>\r\n";
00243 
00244     /* These useful API calls create a HTTP response for us. */
00245     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00246     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00247 
00248     /* Send HTML header. */
00249     fputs_P(head, stream);
00250 
00251     /*
00252      * Send request parameters.
00253      */
00254     switch (req->req_method) {
00255     case METHOD_GET:
00256         cp = "GET";
00257         break;
00258     case METHOD_POST:
00259         cp = "POST";
00260         break;
00261     case METHOD_HEAD:
00262         cp = "HEAD";
00263         break;
00264     default:
00265         cp = "UNKNOWN";
00266         break;
00267     }
00268     fprintf_P(stream, req_fmt, cp, req->req_version / 10, req->req_version % 10, req->req_length);
00269     if (req->req_url)
00270         fprintf_P(stream, url_fmt, req->req_url);
00271     if (req->req_query)
00272         fprintf_P(stream, query_fmt, req->req_query);
00273     if (req->req_type)
00274         fprintf_P(stream, type_fmt, req->req_type);
00275     if (req->req_cookie)
00276         fprintf_P(stream, cookie_fmt, req->req_cookie);
00277     if (req->req_auth)
00278         fprintf_P(stream, auth_fmt, req->req_auth);
00279     if (req->req_agent)
00280         fprintf_P(stream, agent_fmt, req->req_agent);
00281 
00282     /* Send HTML footer and flush output buffer. */
00283     fputs_P(foot, stream);
00284     fflush(stream);
00285 
00286     return 0;
00287 }
00288 
00289 /*
00290  * CGI Sample: Show list of threads.
00291  *
00292  * This routine must have been registered by NutRegisterCgi() and is
00293  * automatically called by NutHttpProcessRequest() when the client
00294  * request the URL 'cgi-bin/threads.cgi'.
00295  */
00296 static int ShowThreads(FILE * stream, REQUEST * req)
00297 {
00298     static prog_char head[] = "<HTML><HEAD><TITLE>Threads</TITLE></HEAD><BODY><H1>Threads</H1>\r\n"
00299         "<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";
00300 #if defined(__AVR__)
00301     static prog_char tfmt[] =
00302         "<TR><TD>%04X</TD><TD>%s</TD><TD>%u</TD><TD>%s</TD><TD>%04X</TD><TD>%04X</TD><TD>%04X</TD><TD>%lu</TD><TD>%s</TD></TR>\r\n";
00303 #else
00304     static prog_char tfmt[] =
00305         "<TR><TD>%08X</TD><TD>%s</TD><TD>%u</TD><TD>%s</TD><TD>%08X</TD><TD>%08X</TD><TD>%08X</TD><TD>%lu</TD><TD>%s</TD></TR>\r\n";
00306 #endif
00307     static prog_char foot[] = "</TABLE></BODY></HTML>";
00308     static char *thread_states[] = { "TRM", "<FONT COLOR=#CC0000>RUN</FONT>", "<FONT COLOR=#339966>RDY</FONT>", "SLP" };
00309     NUTTHREADINFO *tdp = nutThreadList;
00310 
00311     /* Send HTTP response. */
00312     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00313     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00314 
00315     /* Send HTML header. */
00316     fputs_P(head, stream);
00317     for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
00318         fprintf_P(stream, tfmt, (uintptr_t) tdp, tdp->td_name, tdp->td_priority,
00319                   thread_states[tdp->td_state], (uintptr_t) tdp->td_queue, (uintptr_t) tdp->td_timer,
00320                   (uintptr_t) tdp->td_sp, (unsigned long)((uintptr_t) tdp->td_sp - (uintptr_t) tdp->td_memory),
00321                   *((uint32_t *) tdp->td_memory) != DEADBEEF ? "Corr" : "OK");
00322     }
00323     fputs_P(foot, stream);
00324     fflush(stream);
00325 
00326     return 0;
00327 }
00328 
00329 /*
00330  * CGI Sample: Show list of timers.
00331  *
00332  * This routine must have been registered by NutRegisterCgi() and is
00333  * automatically called by NutHttpProcessRequest() when the client
00334  * request the URL 'cgi-bin/timers.cgi'.
00335  */
00336 static int ShowTimers(FILE * stream, REQUEST * req)
00337 {
00338     static prog_char head[] = "<HTML><HEAD><TITLE>Timers</TITLE></HEAD><BODY><H1>Timers</H1>\r\n";
00339     static prog_char thead[] =
00340         "<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";
00341 #if defined(__AVR__)
00342     static prog_char tfmt[] = "<TR><TD>%04X</TD><TD>%lu</TD><TD>%lu</TD><TD>%04X</TD><TD>%04X</TD></TR>\r\n";
00343 #else
00344     static prog_char tfmt[] = "<TR><TD>%08X</TD><TD>%lu</TD><TD>%lu</TD><TD>%08X</TD><TD>%08X</TD></TR>\r\n";
00345 #endif
00346     static prog_char foot[] = "</TABLE></BODY></HTML>";
00347     NUTTIMERINFO *tnp;
00348     uint32_t ticks_left;
00349 
00350     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00351     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00352 
00353     /* Send HTML header. */
00354     fputs_P(head, stream);
00355     if ((tnp = nutTimerList) != 0) {
00356         fputs_P(thead, stream);
00357         ticks_left = 0;
00358         while (tnp) {
00359             ticks_left += tnp->tn_ticks_left;
00360             fprintf_P(stream, tfmt, (uintptr_t) tnp, ticks_left, tnp->tn_ticks, (uintptr_t) tnp->tn_callback, (uintptr_t) tnp->tn_arg);
00361             tnp = tnp->tn_next;
00362         }
00363     }
00364 
00365     fputs_P(foot, stream);
00366     fflush(stream);
00367 
00368     return 0;
00369 }
00370 
00371 /*
00372  * CGI Sample: Show list of sockets.
00373  *
00374  * This routine must have been registered by NutRegisterCgi() and is
00375  * automatically called by NutHttpProcessRequest() when the client
00376  * request the URL 'cgi-bin/sockets.cgi'.
00377  */
00378 static int ShowSockets(FILE * stream, REQUEST * req)
00379 {
00380     /* String literals are kept in flash ROM. */
00381     static prog_char head[] = "<HTML><HEAD><TITLE>Sockets</TITLE></HEAD>"
00382         "<BODY><H1>Sockets</H1>\r\n"
00383         "<TABLE BORDER><TR><TH>Handle</TH><TH>Type</TH><TH>Local</TH><TH>Remote</TH><TH>Status</TH></TR>\r\n";
00384 #if defined(__AVR__)
00385     static prog_char tfmt1[] = "<TR><TD>%04X</TD><TD>TCP</TD><TD>%s:%u</TD>";
00386 #else
00387     static prog_char tfmt1[] = "<TR><TD>%08X</TD><TD>TCP</TD><TD>%s:%u</TD>";
00388 #endif
00389     static prog_char tfmt2[] = "<TD>%s:%u</TD><TD>";
00390     static prog_char foot[] = "</TABLE></BODY></HTML>";
00391     static prog_char st_listen[] = "LISTEN";
00392     static prog_char st_synsent[] = "SYNSENT";
00393     static prog_char st_synrcvd[] = "SYNRCVD";
00394     static prog_char st_estab[] = "<FONT COLOR=#CC0000>ESTABL</FONT>";
00395     static prog_char st_finwait1[] = "FINWAIT1";
00396     static prog_char st_finwait2[] = "FINWAIT2";
00397     static prog_char st_closewait[] = "CLOSEWAIT";
00398     static prog_char st_closing[] = "CLOSING";
00399     static prog_char st_lastack[] = "LASTACK";
00400     static prog_char st_timewait[] = "TIMEWAIT";
00401     static prog_char st_closed[] = "CLOSED";
00402     static prog_char st_unknown[] = "UNKNOWN";
00403     prog_char *st_P;
00404     extern TCPSOCKET *tcpSocketList;
00405     TCPSOCKET *ts;
00406 
00407     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00408     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00409 
00410     /* Send HTML header. */
00411     fputs_P(head, stream);
00412     for (ts = tcpSocketList; ts; ts = ts->so_next) {
00413         switch (ts->so_state) {
00414         case TCPS_LISTEN:
00415             st_P = (prog_char *) st_listen;
00416             break;
00417         case TCPS_SYN_SENT:
00418             st_P = (prog_char *) st_synsent;
00419             break;
00420         case TCPS_SYN_RECEIVED:
00421             st_P = (prog_char *) st_synrcvd;
00422             break;
00423         case TCPS_ESTABLISHED:
00424             st_P = (prog_char *) st_estab;
00425             break;
00426         case TCPS_FIN_WAIT_1:
00427             st_P = (prog_char *) st_finwait1;
00428             break;
00429         case TCPS_FIN_WAIT_2:
00430             st_P = (prog_char *) st_finwait2;
00431             break;
00432         case TCPS_CLOSE_WAIT:
00433             st_P = (prog_char *) st_closewait;
00434             break;
00435         case TCPS_CLOSING:
00436             st_P = (prog_char *) st_closing;
00437             break;
00438         case TCPS_LAST_ACK:
00439             st_P = (prog_char *) st_lastack;
00440             break;
00441         case TCPS_TIME_WAIT:
00442             st_P = (prog_char *) st_timewait;
00443             break;
00444         case TCPS_CLOSED:
00445             st_P = (prog_char *) st_closed;
00446             break;
00447         default:
00448             st_P = (prog_char *) st_unknown;
00449             break;
00450         }
00451         /*
00452          * Fixed a bug reported by Zhao Weigang.
00453          */
00454         fprintf_P(stream, tfmt1, (uintptr_t) ts, inet_ntoa(ts->so_local_addr), ntohs(ts->so_local_port));
00455         fprintf_P(stream, tfmt2, inet_ntoa(ts->so_remote_addr), ntohs(ts->so_remote_port));
00456         fputs_P(st_P, stream);
00457         fputs("</TD></TR>\r\n", stream);
00458         fflush(stream);
00459     }
00460 
00461     fputs_P(foot, stream);
00462     fflush(stream);
00463 
00464     return 0;
00465 }
00466 
00467 /*
00468  * CGI Sample: Proccessing a form.
00469  *
00470  * This routine must have been registered by NutRegisterCgi() and is
00471  * automatically called by NutHttpProcessRequest() when the client
00472  * request the URL 'cgi-bin/form.cgi'.
00473  *
00474  * Thanks to Tom Boettger, who provided this sample for ICCAVR.
00475  */
00476 int ShowForm(FILE * stream, REQUEST * req)
00477 {
00478     static prog_char html_head[] = "<HTML><BODY><BR><H1>Form Result</H1><BR><BR>";
00479     static prog_char html_body[] = "<BR><BR><p><a href=\"../index.html\">return to main</a></BODY></HTML></p>";
00480 
00481     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00482     NutHttpSendHeaderBottom(stream, req, html_mt, -1);
00483 
00484     /* Send HTML header. */
00485     fputs_P(html_head, stream);
00486 
00487     if (req->req_query) {
00488         char *name;
00489         char *value;
00490         int i;
00491         int count;
00492 
00493         count = NutHttpGetParameterCount(req);
00494         /* Extract count parameters. */
00495         for (i = 0; i < count; i++) {
00496             name = NutHttpGetParameterName(req, i);
00497             value = NutHttpGetParameterValue(req, i);
00498 
00499             /* Send the parameters back to the client. */
00500 
00501 #ifdef __IMAGECRAFT__
00502             fprintf(stream, "%s: %s<BR>\r\n", name, value);
00503 #else
00504             fprintf_P(stream, PSTR("%s: %s<BR>\r\n"), name, value);
00505 #endif
00506         }
00507     }
00508 
00509     fputs_P(html_body, stream);
00510     fflush(stream);
00511 
00512     return 0;
00513 }
00514 
00515 #if defined(USE_SSI)
00516 /*
00517  * CGI Sample: Dynamic output cgi included by ssi.shtml file
00518  *
00519  * This routine must have been registered by NutRegisterCgi() and is
00520  * automatically called by NutHttpProcessRequest() when the client
00521  * request the URL 'cgi-bin/form.cgi'.
00522  *
00523  * Thanks to Tom Boettger, who provided this sample for ICCAVR.
00524  */
00525 int SSIDemoCGI(FILE * stream, REQUEST * req)
00526 {
00527     if (req->req_query) {
00528         char *name;
00529         char *value;
00530         int i;
00531         int count;
00532 
00533         count = NutHttpGetParameterCount(req);
00534         
00535         /* Extract count parameters. */
00536 #ifdef __IMAGECRAFT__        
00537         fprintf(stream, "CGI ssi-demo.cgi called with parameters: These are the parameters\r\n<p>");
00538 #else
00539         fprintf_P(stream, PSTR("CGI ssi-demo.cgi called with parameters: These are the parameters\r\n<p>"));
00540 #endif
00541         for (i = 0; i < count; i++) {
00542             name = NutHttpGetParameterName(req, i);
00543             value = NutHttpGetParameterValue(req, i);
00544 
00545             /* Send the parameters back to the client. */
00546 
00547 #ifdef __IMAGECRAFT__
00548             fprintf(stream, "%s: %s<BR>\r\n", name, value);
00549 #else
00550             fprintf_P(stream, PSTR("%s: %s<BR>\r\n"), name, value);
00551 #endif
00552         }
00553     } else {
00554         time_t now;
00555         tm     loc_time;
00556         
00557         /* Called without any parameter, show the current time */
00558         now = time(NULL);
00559         localtime_r(&now, &loc_time);
00560 #ifdef __IMAGECRAFT__        
00561         fprintf(stream, "CGI ssi-demo.cgi called without any parameter.<br><br>Current time is: %02d.%02d.%04d -- %02d:%02d:%02d<br>\r\n",
00562                   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);
00563 #else 
00564         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"),
00565                   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);
00566 #endif
00567     }
00568 
00569     fflush(stream);
00570 
00571     return 0;
00572 }
00573 #endif
00574 
00587 THREAD(Service, arg)
00588 {
00589     TCPSOCKET *sock;
00590     FILE *stream;
00591     uint8_t id = (uint8_t) ((uintptr_t) arg);
00592 
00593     /*
00594      * Now loop endless for connections.
00595      */
00596     for (;;) {
00597 
00598         /*
00599          * Create a socket.
00600          */
00601         if ((sock = NutTcpCreateSocket()) == 0) {
00602             printf("[%u] Creating socket failed\n", id);
00603             NutSleep(5000);
00604             continue;
00605         }
00606 
00607         /*
00608          * Listen on port 80. This call will block until we get a connection
00609          * from a client.
00610          */
00611         NutTcpAccept(sock, 80);
00612 #if defined(__AVR__)
00613         printf("[%u] Connected, %u bytes free\n", id, NutHeapAvailable());
00614 #else
00615         printf("[%u] Connected, %u bytes free\n", id, NutHeapAvailable());
00616 #endif
00617 
00618         /*
00619          * Wait until at least 8 kByte of free RAM is available. This will
00620          * keep the client connected in low memory situations.
00621          */
00622 #if defined(__AVR__)
00623         while (NutHeapAvailable() < 8192) {
00624 #else
00625         while (NutHeapAvailable() < 4096) {
00626 #endif
00627             printf("[%u] Low mem\n", id);
00628             NutSleep(1000);
00629         }
00630 
00631         /*
00632          * Associate a stream with the socket so we can use standard I/O calls.
00633          */
00634         if ((stream = _fdopen((int) ((uintptr_t) sock), "r+b")) == 0) {
00635             printf("[%u] Creating stream device failed\n", id);
00636         } else {
00637             /*
00638              * This API call saves us a lot of work. It will parse the
00639              * client's HTTP request, send any requested file from the
00640              * registered file system or handle CGI requests by calling
00641              * our registered CGI routine.
00642              */
00643             NutHttpProcessRequest(stream);
00644 
00645             /*
00646              * Destroy the virtual stream device.
00647              */
00648             fclose(stream);
00649         }
00650 
00651         /*
00652          * Close our socket.
00653          */
00654         NutTcpCloseSocket(sock);
00655         printf("[%u] Disconnected\n", id);
00656     }
00657 }
00658 #endif /* DEV_ETHER */
00659 
00665 int main(void)
00666 {
00667     uint32_t baud = 115200;
00668     uint8_t i;
00669 
00670     /*
00671      * Initialize the uart device.
00672      */
00673     NutRegisterDevice(&DEV_CONSOLE, 0, 0);
00674     freopen(DEV_CONSOLE_NAME, "w", stdout);
00675     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00676     NutSleep(200);
00677     printf("\n\nNut/OS %s HTTP Daemon...", NutVersionString());
00678 
00679 #ifdef DEV_ETHER
00680 
00681 #ifdef NUTDEBUG
00682     NutTraceTcp(stdout, 0);
00683     NutTraceOs(stdout, 0);
00684     NutTraceHeap(stdout, 0);
00685     NutTracePPP(stdout, 0);
00686 #endif
00687 
00688     /*
00689      * Register Ethernet controller.
00690      */
00691     if (NutRegisterDevice(&DEV_ETHER, 0, 0)) {
00692         puts("Registering device failed");
00693     }
00694 
00695     printf("Configure %s...", DEV_ETHER_NAME);
00696     if (NutNetLoadConfig(DEV_ETHER_NAME)) {
00697         uint8_t mac[] = MY_MAC;
00698 
00699         printf("initial boot...");
00700 #ifdef USE_DHCP
00701         if (NutDhcpIfConfig(DEV_ETHER_NAME, mac, 60000)) 
00702 #endif
00703         {
00704             uint32_t ip_addr = inet_addr(MY_IPADDR);
00705             uint32_t ip_mask = inet_addr(MY_IPMASK);
00706             uint32_t ip_gate = inet_addr(MY_IPGATE);
00707 
00708             printf("No DHCP...");
00709             if (NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask) == 0) {
00710                 /* Without DHCP we had to set the default gateway manually.*/
00711                 if(ip_gate) {
00712                     printf("hard coded gate...");
00713                     NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
00714                 }
00715                 puts("OK");
00716             }
00717             else {
00718                 puts("failed");
00719             }
00720         }
00721     }
00722     else {
00723 #ifdef USE_DHCP
00724         if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000)) {
00725             puts("failed");
00726         }
00727         else {
00728             puts("OK");
00729         }
00730 #else
00731         if (NutNetIfConfig(DEV_ETHER_NAME, 0, 0, confnet.cdn_ip_mask)) {
00732             puts("failed");
00733         }
00734         else {
00735             puts("OK");
00736         }
00737 #endif
00738     }
00739     printf("%s ready\n", inet_ntoa(confnet.cdn_ip_addr));
00740 
00741 #ifdef USE_DISCOVERY
00742     NutRegisterDiscovery((uint32_t)-1, 0, DISF_INITAL_ANN);
00743 #endif
00744 
00745     /*
00746      * Register our device for the file system.
00747      */
00748     NutRegisterDevice(&MY_FSDEV, 0, 0);
00749 
00750 #ifdef MY_BLKDEV
00751     /* Register block device. */
00752     printf("Registering block device '" MY_BLKDEV_NAME "'...");
00753     if (NutRegisterDevice(&MY_BLKDEV, 0, 0)) {
00754         puts("failed");
00755         for (;;);
00756     }
00757     puts("OK");
00758 
00759     /* Mount partition. */
00760     printf("Mounting block device '" MY_BLKDEV_NAME ":1/" MY_FSDEV_NAME "'...");
00761     if (_open(MY_BLKDEV_NAME ":1/" MY_FSDEV_NAME, _O_RDWR | _O_BINARY) == -1) {
00762         puts("failed");
00763         for (;;);
00764     }
00765     puts("OK");
00766 #endif
00767 
00768 #ifdef MY_HTTPROOT
00769     /* Register root path. */
00770     printf("Registering HTTP root '" MY_HTTPROOT "'...");
00771     if (NutRegisterHttpRoot(MY_HTTPROOT)) {
00772         puts("failed");
00773         for (;;);
00774     }
00775     puts("OK");
00776 #endif
00777 
00778     NutRegisterCgiBinPath("cgi-bin/;user/cgi-bin/;admin/cgi-bin/");
00779 
00780 
00781     /*
00782      * Register our CGI sample. This will be called
00783      * by http://host/cgi-bin/test.cgi?anyparams
00784      */
00785     NutRegisterCgi("test.cgi", ShowQuery);
00786 
00787 #if defined(USE_SSI)
00788     /* 
00789      * Register a cgi included by the ssi demo. This will show how dynamic 
00790      * content is included in a ssi page and how the request parameters for 
00791      * a site are passed down to the included cgi.
00792      */    
00793     NutRegisterCgi("ssi-demo.cgi", SSIDemoCGI);
00794 #endif
00795 
00796     /*
00797      * Register some CGI samples, which display interesting
00798      * system informations.
00799      */
00800     NutRegisterCgi("threads.cgi", ShowThreads);
00801     NutRegisterCgi("timers.cgi", ShowTimers);
00802     NutRegisterCgi("sockets.cgi", ShowSockets);
00803 
00804     /*
00805      * Finally a CGI example to process a form.
00806      */
00807     NutRegisterCgi("form.cgi", ShowForm);
00808 
00809     /*
00810      * Protect the cgi-bin directory with
00811      * user and password.
00812      */
00813     NutRegisterAuth("admin", "root:root");
00814     NutRegisterAuth("user", "user:user");
00815 
00816     /*
00817      * Register SSI and ASP handler
00818      */
00819 #if defined(USE_SSI)
00820     NutRegisterSsi();
00821 #endif
00822 #if defined(USE_ASP)
00823     NutRegisterAsp();
00824     NutRegisterAspCallback(ASPCallback);
00825 #endif
00826 
00827     /*
00828      * Start four server threads.
00829      */
00830     for (i = 1; i <= 4; i++) {
00831         char thname[] = "httpd0";
00832 
00833         thname[5] = '0' + i;
00834         NutThreadCreate(thname, Service, (void *) (uintptr_t) i, HTTPD_SERVICE_STACK); 
00835     }
00836 #endif /* DEV_ETHER */
00837 
00838     /*
00839      * We could do something useful here, like serving a watchdog.
00840      */
00841     NutThreadSetPriority(254);
00842     for (;;) {
00843         NutSleep(60000);
00844     }
00845     return 0;
00846 }