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