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