Nut/OS  4.10.3
API Reference
httpserv.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2004 by egnite Software GmbH
00003  * Copyright (C) 2009 by egnite 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 
00036 
00047 #include <cfg/os.h>
00048 
00049 #include <string.h>
00050 #include <io.h>
00051 #include <fcntl.h>
00052 #include <time.h>
00053 
00054 #include <dev/board.h>
00055 #include <dev/urom.h>
00056 #include <dev/nplmmc.h>
00057 #include <dev/sbimmc.h>
00058 #include <fs/phatfs.h>
00059 
00060 #include <sys/version.h>
00061 #include <sys/thread.h>
00062 #include <sys/timer.h>
00063 #include <sys/heap.h>
00064 #include <sys/confnet.h>
00065 #include <sys/socket.h>
00066 
00067 #include <arpa/inet.h>
00068 #include <net/route.h>
00069 #include <netinet/in.h>
00070 
00071 #include <pro/httpd.h>
00072 #include <pro/dhcp.h>
00073 #include <pro/ssi.h>
00074 #include <pro/asp.h>
00075 #include <pro/discover.h>
00076 
00077 #include "upnp.h"
00078 
00079 
00080 /* Server thread stack size. */
00081 #ifndef HTTPD_SERVICE_STACK
00082 #define HTTPD_SERVICE_STACK ((1024 * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)
00083 #endif
00084 
00097 THREAD(Service, arg)
00098 {
00099     TCPSOCKET *sock;
00100     FILE *stream;
00101     uint8_t id = (uint8_t) ((uintptr_t) arg);
00102 
00103     /*
00104      * Now loop endless for connections.
00105      */
00106     for (;;) {
00107 
00108         /*
00109          * Create a socket.
00110          */
00111         if ((sock = NutTcpCreateSocket()) == 0) {
00112             printf("[%u] Creating socket failed\n", id);
00113             NutSleep(5000);
00114             continue;
00115         }
00116 
00117         /*
00118          * Listen on port 80. This call will block until we get a connection
00119          * from a client.
00120          */
00121         NutTcpAccept(sock, 80);
00122         printf("[%u] Connected, %lu bytes free\n", id, NutHeapAvailable());
00123 
00124         /*
00125          * Wait until at least 4 kByte of free RAM is available. This will
00126          * keep the client connected in low memory situations.
00127          */
00128         while (NutHeapAvailable() < 4096) {
00129             printf("[%u] Low mem\n", id);
00130             NutSleep(1000);
00131         }
00132 
00133         /*
00134          * Associate a stream with the socket so we can use standard I/O calls.
00135          */
00136         if ((stream = _fdopen((int) ((uintptr_t) sock), "r+b")) == 0) {
00137             printf("[%u] Creating stream device failed\n", id);
00138         } else {
00139             /*
00140              * This API call saves us a lot of work. It will parse the
00141              * client's HTTP request, send any requested file from the
00142              * registered file system or handle CGI requests by calling
00143              * our registered CGI routine.
00144              */
00145             NutHttpProcessRequest(stream);
00146 
00147             /*
00148              * Destroy the virtual stream device.
00149              */
00150             fclose(stream);
00151         }
00152 
00153         /*
00154          * Close our socket.
00155          */
00156         NutTcpCloseSocket(sock);
00157         printf("[%u] Disconnected\n", id);
00158     }
00159 }
00160 
00166 int main(void)
00167 {
00168     uint32_t baud = 115200;
00169     uint8_t i;
00170 
00171     /*
00172      * Initialize the uart device.
00173      */
00174     NutRegisterDevice(&DEV_CONSOLE, 0, 0);
00175     freopen(DEV_CONSOLE_NAME, "w", stdout);
00176     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00177     NutSleep(200);
00178     printf("\n\nNut/OS %s HTTP Daemon...\n", NutVersionString());
00179 
00180     /*
00181      * Register Ethernet controller.
00182      */
00183     if (NutRegisterDevice(&DEV_ETHER, 0, 0)) {
00184         puts("Registering device failed");
00185     } else {
00186         /*
00187          * Add "All Host" multicast address.
00188          */
00189         printf("Add \"All Host\" multicast address...");
00190         if (NutNetIfAddMcastAddr(DEV_ETHER_NAME, INADDR_ALLHOSTS_GROUP) != 0) {
00191             /*
00192              * It could be possible that your ethernet 
00193              * driver does not support multicast.
00194              */
00195             puts("failed");
00196         } else {
00197             puts("OK");
00198         }
00199     }
00200 
00201     printf("Configure %s...", DEV_ETHER_NAME);
00202     if (NutNetLoadConfig(DEV_ETHER_NAME)) {
00203         puts("failed");
00204     } else {
00205         if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000)) {
00206             puts("failed");
00207         } else {
00208             puts("OK");
00209         }
00210     }
00211     printf("%s ready\n", inet_ntoa(confnet.cdn_ip_addr));
00212 
00213     /*
00214      * Register our device for the file system.
00215      */
00216     NutRegisterDevice(&devUrom, 0, 0);
00217 
00218 
00219     NutRegisterCgiBinPath("cgi-bin/");
00220 
00221 
00222     /*
00223      * Start four server threads.
00224      */
00225     for (i = 1; i <= 4; i++) {
00226         char thname[] = "httpd0";
00227 
00228         thname[5] = '0' + i;
00229         NutThreadCreate(thname, Service, (void *) (uintptr_t) i, HTTPD_SERVICE_STACK);
00230     }
00231 
00232     /*
00233      * Start the UPnP functionality
00234      */
00235     upnp_Init();
00236 
00237     /*
00238      * We could do something useful here, like serving a watchdog.
00239      */
00240     NutThreadSetPriority(254);
00241     for (;;) {
00242         NutSleep(60000);
00243     }
00244     return 0;
00245 }
00246 
00247 /*** EOF ***/