httpserv.c

Go to the documentation of this file.
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 }

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