/* * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * */ #include <string.h> #include <io.h> #include <dev/nicrtl.h> #include <dev/uartavr.h> #include <dev/urom.h> #include <sys/version.h> #include <sys/thread.h> #include <sys/timer.h> #include <sys/heap.h> #include <sys/confnet.h> #include <sys/socket.h> #include <arpa/inet.h> #include <pro/httpd.h> #include <pro/dhcp.h> #ifdef NUTDEBUG #include <sys/osdebug.h> #include <net/netdebug.h> #endif static char *states[] = { "TRM", "<FONT COLOR=#CC0000>RUN</FONT>", "<FONT COLOR=#339966>RDY</FONT>", "SLP" }; /* * CGI Sample. See httpd.h for REQUEST structure. */ static int ShowQuery(FILE *stream, REQUEST *req) { NutHttpSendHeaderTop(stream, req, 200, "Ok"); NutHttpSendHeaderBot(stream, "text/html", -1); fprintf(stream, "<HTML>" "<HEAD>" "<TITLE>Show Query</TITLE>" "</HEAD>" "<BODY>"); if(req->req_query) fputs(req->req_query, stream); else fputs("None", stream); fputs("</BODY></HTML>", stream); fflush(stream); return 0; } /* * CGI Sample. */ static int ShowThreads(FILE *stream, REQUEST *req) { NUTTHREADINFO *tdp = nutThreadList; NutHttpSendHeaderTop(stream, req, 200, "Ok"); NutHttpSendHeaderBot(stream, "text/html", -1); fputs("<HTML>" "<HEAD>" "<TITLE>Show Threads</TITLE>" "</HEAD>" "<BODY>\r\n", stream); fputs("<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", stream); while(tdp) { fprintf(stream, "<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", (u_int)tdp, tdp->td_name, tdp->td_priority, states[tdp->td_state], (u_int)tdp->td_queue, (u_int)tdp->td_timer, tdp->td_sp, (u_short)tdp->td_sp - (u_short)tdp->td_memory, *((u_long *)tdp->td_memory) != DEADBEEF ? "Corr" : "OK"); tdp = tdp->td_next; } fputs("</TABLE></BODY></HTML>", stream); fflush(stream); return 0; } /* * CGI Sample. */ static int ShowTimer(FILE *stream, REQUEST *req) { NUTTIMERINFO *tnp; u_long ticks_left; NutHttpSendHeaderTop(stream, req, 200, "Ok"); NutHttpSendHeaderBot(stream, "text/html", -1); fputs("<HTML>" "<HEAD>" "<TITLE>Show Threads</TITLE>" "</HEAD>" "<BODY>", stream); if((tnp = nutTimerList) != 0) { fputs("<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", stream); ticks_left = 0; while(tnp) { ticks_left += tnp->tn_ticks_left; fprintf(stream, "<TR><TD>%04X</TD><TD>%lu</TD><TD>%lu</TD><TD>%04X</TD><TD>%04X</TD></TR>\r\n", (u_int)tnp, ticks_left, tnp->tn_ticks, (u_int)tnp->tn_callback, (u_int)tnp->tn_arg); tnp = tnp->tn_next; } } fputs("</TABLE></BODY></HTML>", stream); fflush(stream); return 0; } /* * CGI Sample. */ static int ShowSockets(FILE *stream, REQUEST *req) { extern TCPSOCKET *tcpSocketList; TCPSOCKET *ts; NutHttpSendHeaderTop(stream, req, 200, "Ok"); NutHttpSendHeaderBot(stream, "text/html", -1); fputs("<HTML>" "<HEAD>" "<TITLE>Show Threads</TITLE>" "</HEAD>" "<BODY>", stream); fputs("<TABLE BORDER><TR><TH>Handle</TH><TH>Type</TH><TH>Local</TH><TH>Remote</TH><TH>Status</TH></TR>\r\n", stream); for(ts = tcpSocketList; ts; ts = ts->so_next) { fprintf(stream, "<TR><TD>%04X</TD><TD>TCP</TD><TD>%s:%u</TD>", (u_int)ts, inet_ntoa(ts->so_local_addr), ntohs(ts->so_local_port)); fprintf(stream, "<TD>%s:%u</TD><TD>", inet_ntoa(ts->so_remote_addr), ntohs(ts->so_remote_port)); switch(ts->so_state) { case TCPS_LISTEN: fputs("LISTEN", stream); break; case TCPS_SYN_SENT: fputs("SYNSENT", stream); break; case TCPS_SYN_RECEIVED: fputs("SYNRCVD", stream); break; case TCPS_ESTABLISHED: fputs("<FONT COLOR=#CC0000>ESTABL</FONT>", stream); break; case TCPS_FIN_WAIT_1: fputs("FINWAIT1", stream); break; case TCPS_FIN_WAIT_2: fputs("FINWAIT2", stream); break; case TCPS_CLOSE_WAIT: fputs("CLOSEWAIT", stream); break; case TCPS_CLOSING: fputs("CLOSING", stream); break; case TCPS_LAST_ACK: fputs("LASTACK", stream); break; case TCPS_TIME_WAIT: fputs("TIMEWAIT", stream); break; case TCPS_CLOSED: fputs("CLOSED", stream); break; default: fputs("?UNK?", stream); break; } fputs("</TD></TR>\r\n", stream); fflush(stream); } fputs("</TABLE></BODY></HTML>", stream); fflush(stream); return 0; } THREAD(Service, arg) { TCPSOCKET *sock; FILE *stream; u_char id = (u_char)((u_short)arg); /* * Now loop endless for connections. */ for(;;) { /* * Create a socket. */ if((sock = NutTcpCreateSocket()) == 0) { printf("[%u] Creating socket failed\n", id); NutSleep(5000); continue; } /* * Listen on port 80. If we return, * we got a client. */ NutTcpAccept(sock, 80); printf("[%u] Connected, %u bytes free\n", id, NutHeapAvailable()); /* * Check for enough memory. If we are below * 8 kByte, take a nap and try again. */ for(;;) { if(NutHeapAvailable() > 8192) break; printf("[%u] Low mem\n", id); NutSleep(1000); } /* * Create a virtual stream device from the socket, * so we can use NutPrintFormat() and other stream * device goodies. */ if((stream = _fdopen((int)sock, "r+b")) == 0) { printf("[%u] Creating stream device failed\n", id); } else { /* * Process http request. */ NutHttpProcessRequest(stream); /* * Destroy the virtual stream device. */ fclose(stream); } /* * Close our socket. */ NutTcpCloseSocket(sock); printf("[%u] Disconnected\n", id); } } int main(void) { u_long baud = 115200; u_char i; /* * Initialize the uart device. */ NutRegisterDevice(&devUart0, 0, 0); freopen("uart0", "w", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud); NutSleep(200); printf("\n\nNut/OS %s HTTP Daemon...", NutVersionString()); #ifdef NUTDEBUG NutKTcpTrace(0); NutKOsTrace(1); NutKHeapTrace(0); #endif /* * Register Realtek controller at address 8300 hex * and interrupt 5. */ if(NutRegisterDevice(&devEth0, 0x8300, 5)) puts("Registering device failed"); /* * LAN configuration using EEPROM values or DHCP/ARP method. * If it fails, use fixed values. */ if(NutDhcpIfConfig("eth0", 0, 60000)) { u_char mac[] = { 0x00,0x06,0x98,0x00,0x00,0x00 }; u_long ip_addr = inet_addr("192.168.192.100"); u_long ip_mask = inet_addr("255.255.255.0"); puts("EEPROM/DHCP/ARP config failed"); NutNetIfConfig("eth0", mac, ip_addr, ip_mask); } printf("%s ready\n", inet_ntoa(confnet.cdn_ip_addr)); /* * Register our device for the file system. */ NutRegisterDevice(&devUrom, 0, 0); /* * Register our CGI sample. This will be called * by http://host/cgi-bin/test.cgi?anyparams */ NutRegisterCgi("test.cgi", ShowQuery); /* * Register more CGI samples. */ NutRegisterCgi("threads.cgi", ShowThreads); NutRegisterCgi("timer.cgi", ShowTimer); NutRegisterCgi("sockets.cgi", ShowSockets); /* * Protect the cgi-bin directory with * user and password. */ NutRegisterAuth("cgi-bin", "root:root"); /* * Start four server threads. */ for(i = 1; i <= 4; i++) { char *thname = "httpd0"; thname[5] = '0' + i; NutThreadCreate(thname, Service, (void *)(u_short)i, 640); } /* * We could do something useful here, like serving a watchdog. */ NutThreadSetPriority(254); for(;;) NutSleep(60000); }