Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

httpserv.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2007 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 
00045 #ifndef MY_FSDEV
00046 #define MY_FSDEV        devUrom
00047 #endif
00048 
00049 #ifdef MY_FSDEV_NAME
00050 #define MY_HTTPROOT     MY_FSDEV_NAME ":/" 
00051 #endif
00052 
00053 #include <cfg/os.h>
00054 #include <cfg/memory.h>
00055 
00056 #include <stdlib.h>
00057 #include <string.h>
00058 #include <io.h>
00059 #include <fcntl.h>
00060 #include <time.h>
00061 
00062 #include <dev/board.h>
00063 #include <dev/urom.h>
00064 
00065 #include <sys/thread.h>
00066 #include <sys/timer.h>
00067 #include <sys/heap.h>
00068 #include <sys/socket.h>
00069 
00070 #include <pro/httpd.h>
00071 
00072 #include "tlv320dac.h"
00073 #include "httpserv.h"
00074 
00075 #ifndef HTTPD_THREAD_STACK
00076 #define HTTPD_THREAD_STACK  2048
00077 #endif
00078 
00079 #ifdef USE_HTTPSERVER
00080 
00086 #define EMPTY_GAIN  999
00087 
00088 extern void *__heap_start;
00089 extern void *__etext;
00090 
00091 int h_timevalid; 
00092 
00093 static char *html_mt = "text/html";
00094 
00102 static int CgiInfo(FILE * stream, REQUEST * req)
00103 {
00104     /* These useful API calls create a HTTP response for us. */
00105     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00106     NutHttpSendHeaderBot(stream, html_mt, -1);
00107 
00108     /* Send HTML header. */
00109     fputs("<HTML><HEAD><TITLE>Internet Radio Information</TITLE>" /* */
00110           "<meta http-equiv=\"refresh\" content=\"10; URL=info.cgi\">" /* */
00111           "</HEAD><BODY>\r\n" /* */
00112           "<h1>Internet Radio Status</h1>" /* */
00113           , stream);
00114 
00115     /* If we received date and time from a time server, display it. */
00116     if (h_timevalid) {
00117         time_t now = time(0);
00118         struct _tm *lot = localtime(&now);
00119         fprintf(stream, "Date = %02u.%02u.%u<br>\r\n", lot->tm_mday, lot->tm_mon + 1, 1900 + lot->tm_year);
00120         fprintf(stream, "Time = %02u:%02u:%02u<br>\r\n", lot->tm_hour, lot->tm_min, lot->tm_sec);
00121     }
00122     /* Display our clock settings. */
00123     fprintf(stream, "<br>CPU Clock = %lu kHz<br>\r\n", NutGetCpuClock() / 1000);
00124     fprintf(stream, "Master Clock = %lu kHz<br>\r\n", At91GetMasterClock() / 1000);
00125     /* Display our memory usage. */
00126     fprintf(stream, "<br>Code size incl. Web Content = %u kBytes<br>\r\n", ((u_int)(&__etext) - NUTMEM_START) / 1024);
00127     fprintf(stream, "Static data size = %u kBytes<br>\r\n", (u_int)(&__heap_start - &__etext) / 1024);
00128     fprintf(stream, "Total memory used = %u kBytes<br>\r\n", (u_int)(NUTMEM_SIZE - NutHeapAvailable()) / 1024);
00129     fflush(stream);
00130 
00131     if (radio.rc_sip == NULL) {
00132         fputs("<br><br><b>No station connected<br>\r\n", stream);
00133     }
00134     else {
00135         fprintf(stream, "<h2>Radio Station</h2>\r\n");
00136         fprintf(stream, "Name = %s<br>\r\n", radio.rc_sip->si_name);
00137         fprintf(stream, "Genre = %s<br>\r\n", radio.rc_sip->si_genre);
00138         fprintf(stream, "Bitrate = %u kBit<br>\r\n", radio.rc_sip->si_bitrate);
00139         fflush(stream);
00140         if (radio.rc_rip) {
00141             SHOUTCASTINFO *sci = (SHOUTCASTINFO *) radio.rc_rip->ri_bcast;
00142             fprintf(stream, "<h2>SHOUTcast Stream</h2>\r\n");
00143             fprintf(stream, "Buffer contents = %u Bytes<br>\r\n", radio.rc_rip->ri_avail);
00144             if (sci) {
00145                 fprintf(stream, "Title = %s<br>\r\n", sci->sci_metatitle);
00146                 fprintf(stream, "URL = %s<br>\r\n", sci->sci_metaurl);
00147             }
00148             fprintf(stream, "Metadata interval = %lu Bytes<br>\r\n", sci->sci_metaint);
00149             fflush(stream);
00150             if (radio.rc_pip) {
00151                 MP3PLAYERINFO *mpi = (MP3PLAYERINFO *) radio.rc_pip->pi_bcast;
00152                 if (mpi) {
00153                     fprintf(stream, "<h2>MP3 Decoder</h2>\r\n");
00154                     fprintf(stream, "Layer = %d<br>\r\n", mpi->mpi_frameinfo.layer);
00155                     fprintf(stream, "Version = %d<br>\r\n", mpi->mpi_frameinfo.version);
00156                     fprintf(stream, "Bitrate = %d<br>\r\n", mpi->mpi_frameinfo.bitrate);
00157                     fprintf(stream, "Channels = %d<br>\r\n", mpi->mpi_frameinfo.nChans);
00158                     fprintf(stream, "Sample rate = %d<br>\r\n", mpi->mpi_frameinfo.samprate);
00159                     fprintf(stream, "Bits per sample = %d<br>\r\n", mpi->mpi_frameinfo.bitsPerSample);
00160                     fflush(stream);
00161                 }
00162             }
00163         }
00164     }
00165 
00166     fputs("<BR><BR><a href=\"/index.html\">BACK</a>", stream);
00167 
00168     /* Send HTML footer and flush output buffer. */
00169     fputs("</BODY></HTML>", stream);
00170     fflush(stream);
00171 
00172     return 0;
00173 }
00174 
00175 /*
00176  * CGI Radio Control
00177  */
00178 int CgiControl(FILE * stream, REQUEST * req)
00179 {
00180     int lvol = EMPTY_GAIN;
00181     int rvol = EMPTY_GAIN;
00182     int stop = 0;
00183 
00184     NutHttpSendHeaderTop(stream, req, 200, "Ok");
00185     NutHttpSendHeaderBot(stream, html_mt, -1);
00186 
00187     /* Send HTML header. */
00188     fputs("<HTML><BODY><BR><H1>Control Result</H1><BR><BR>", stream);
00189     fflush(stream);
00190 
00191     if (req->req_query) {
00192         char *name;
00193         char *value;
00194         int i;
00195         int count;
00196 
00197         count = NutHttpGetParameterCount(req);
00198         /* Extract count parameters. */
00199         for (i = 0; i < count; i++) {
00200             name = NutHttpGetParameterName(req, i);
00201             value = NutHttpGetParameterValue(req, i);
00202 
00203             /* Send the parameters back to the client. */
00204             //fprintf(stream, "%s = '%s'<BR>\r\n", name, value);
00205             if (strcmp(name, "lvol") == 0 && value[0]) {
00206                 lvol = atoi(value);
00207             }
00208             else if (strcmp(name, "rvol") == 0 && value[0]) {
00209                 rvol = atoi(value);
00210             }
00211             else if (strcmp(name, "stream") == 0 && value[0]) {
00212                 stop = 1;
00213             }
00214         }
00215 
00216         /* Handle volume changes. User needs to fill one channel only 
00217            in order to set both. */
00218         if (rvol == EMPTY_GAIN) {
00219             rvol = lvol;
00220         }
00221         else if (lvol == EMPTY_GAIN) {
00222             lvol = rvol;
00223         }
00224         if (lvol != EMPTY_GAIN) {
00225             Tlv320DacSetVolume(lvol, rvol);
00226             fprintf(stream, "Volume set to %d/%d dB<BR>.\r\n", lvol, rvol);
00227         }
00228 
00229         /* Handle station re-connect. */
00230         if (stop) {
00231             if (radio.rc_rip) {
00232                 ReceiverStop(radio.rc_rip);
00233                 fprintf(stream, "Stream stopped.<BR>\r\n");
00234             }
00235             if (radio.rc_pip) {
00236                 PlayerStop(radio.rc_pip);
00237                 fprintf(stream, "Player stopped.<BR>\r\n");
00238             }
00239         }
00240     }
00241 
00242     fputs("<BR><BR><p><a href=\"/index.html\">BACK</a></BODY></HTML></p>", stream);
00243     fflush(stream);
00244 
00245     return 0;
00246 }
00247 
00260 THREAD(Service, arg)
00261 {
00262     TCPSOCKET *sock;
00263     FILE *stream;
00264     u_char id = (u_char) ((uptr_t) arg);
00265 
00266     /*
00267      * Now loop endless for connections.
00268      */
00269     for (;;) {
00270 
00271         /*
00272          * Create a socket.
00273          */
00274         if ((sock = NutTcpCreateSocket()) == 0) {
00275             printf("[%u] Creating socket failed\n", id);
00276             NutSleep(5000);
00277             continue;
00278         }
00279 
00280         /*
00281          * Listen on port 80. This call will block until we get a connection
00282          * from a client.
00283          */
00284         NutTcpAccept(sock, 80);
00285 
00286         /*
00287          * Wait until at least 8 kByte of free RAM is available. This will
00288          * keep the client connected in low memory situations.
00289          */
00290         while (NutHeapAvailable() < 8192) {
00291             printf("[%u] Low mem\n", id);
00292             NutSleep(1000);
00293         }
00294 
00295         /*
00296          * Associate a stream with the socket so we can use standard I/O calls.
00297          */
00298         if ((stream = _fdopen((int) ((uptr_t) sock), "r+b")) == 0) {
00299             printf("[%u] Creating stream device failed\n", id);
00300         } else {
00301             /*
00302              * This API call saves us a lot of work. It will parse the
00303              * client's HTTP request, send any requested file from the
00304              * registered file system or handle CGI requests by calling
00305              * our registered CGI routine.
00306              */
00307             NutHttpProcessRequest(stream);
00308 
00309             /*
00310              * Destroy the virtual stream device.
00311              */
00312             fclose(stream);
00313         }
00314 
00315         /*
00316          * Close our socket.
00317          */
00318         NutTcpCloseSocket(sock);
00319     }
00320 }
00321 
00325 int HttpServerStart(void)
00326 {
00327     int i;
00328 
00329     /*
00330      * Register our device for the file system.
00331      */
00332     NutRegisterDevice(&MY_FSDEV, 0, 0);
00333 
00334 #ifdef MY_HTTPROOT
00335     /* Register root path. */
00336     printf("Registering HTTP root '" MY_HTTPROOT "'...");
00337     if (NutRegisterHttpRoot(MY_HTTPROOT)) {
00338         puts("failed");
00339         for (;;);
00340     }
00341     puts("OK");
00342 #endif
00343 
00344     /*
00345      * Register our CGIs.
00346      */
00347     NutRegisterCgi("info.cgi", CgiInfo);
00348     NutRegisterCgi("control.cgi", CgiControl);
00349 
00350     /*
00351      * Protect the admin directory with user and password.
00352      */
00353     NutRegisterAuth("admin", "admin:lemta");
00354 
00355     /*
00356      * Start four server threads.
00357      */
00358     for (i = 1; i <= 4; i++) {
00359         char *thname = "httpd0";
00360 
00361         thname[5] = '0' + i;
00362         NutThreadCreate(thname, Service, (void *) (uptr_t) i, HTTPD_THREAD_STACK);
00363     }
00364     return 0;
00365 }
00366 
00367 #endif /* USE_HTTPSERVER */
00368 

Generated on Fri Feb 23 17:28:49 2007 for SAM Internet Radio by  doxygen 1.4.4