tcps/tcps.c

Simple TCP server.

Program Ethernut with tcps.hex and enter

00001  telnet x.x.x.x 

on a command prompt, replacing x.x.x.x with the IP address of your ethernut board. Enter help for a list of available commands.

00001 /*
00002  * Copyright (C) 2001-2005 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 
00083 #include <cfg/os.h>
00084 #include <string.h>
00085 #include <stdio.h>
00086 #include <io.h>
00087 
00088 #include <dev/board.h>
00089 
00090 #include <sys/version.h>
00091 #include <sys/heap.h>
00092 #include <sys/thread.h>
00093 #include <sys/timer.h>
00094 #include <sys/socket.h>
00095 
00096 #include <arpa/inet.h>
00097 #include <pro/dhcp.h>
00098 
00099 #ifdef NUTDEBUG
00100 #include <sys/osdebug.h>
00101 #include <net/netdebug.h>
00102 #endif
00103 
00104 #include <sys/confnet.h>
00105 
00106 static char buff[128];
00107 
00108 /*
00109  * To save RAM, we store large strings in program space. With AVRGCC we
00110  * would be able to use the PSTR() macro and put the text directly in
00111  * the statement that uses it. But ICCAVR doesn't support anything like 
00112  * this. Sigh.
00113  */
00114 #if defined(__IMAGECRAFT__)
00115 #define CC_STRING   "ICCAVR"
00116 #elif defined(__GNUC__)
00117 #define CC_STRING   "AVRGCC"
00118 #else
00119 #define CC_STRING   "Compiler unknown"
00120 #endif
00121 
00122 prog_char vbanner_P[] = "\n\nTCP Server Sample - Nut/OS %s - " CC_STRING "\n";
00123 prog_char banner_P[] = "200 Welcome to tcps. Type help to get help.\r\n";
00124 prog_char help_P[] = "400 List of commands follows\r\n"
00125     "m[emory]\tQueries number of RAM bytes free.\r\n"
00126     "t[hreads]\tLists all created threads.\r\n"
00127     "ti[mers]\tLists all running timers.\r\n" "q[uit]\t\tTerminates connection.\r\n" ".\r\n";
00128 prog_char thread_intro_P[] = "220 List of threads with name,state,prio,stack,mem,timeout follows\r\n";
00129 prog_char timer_intro_P[] = "221 List of timers with ticks left and interval follows\r\n";
00130 prog_char mem_fmt_P[] = "210 %u bytes RAM free\r\n";
00131 
00132 /*
00133  * Process client requests.
00134  */
00135 void ProcessRequests(FILE * stream)
00136 {
00137     int got;
00138     char *cp;
00139 
00140     /*
00141      * Send a welcome banner.
00142      */
00143     fputs_P(banner_P, stream);
00144     for (;;) {
00145 
00146         /*
00147          * Flush output and read a line.
00148          */
00149         fflush(stream);
00150         if (fgets(buff, sizeof(buff), stream) == 0)
00151             break;
00152 
00153         /*
00154          * Chop off EOL.
00155          */
00156         if ((cp = strchr(buff, '\r')) != 0)
00157             *cp = 0;
00158         if ((cp = strchr(buff, '\n')) != 0)
00159             *cp = 0;
00160 
00161         /*
00162          * Ignore blank lines.
00163          */
00164         got = strlen(buff);
00165         if (got == 0)
00166             continue;
00167 
00168         /*
00169          * Memory info.
00170          */
00171         if (strncmp(buff, "memory", got) == 0) {
00172             fprintf_P(stream, mem_fmt_P, (u_int)NutHeapAvailable());
00173             continue;
00174         }
00175 
00176         /*
00177          * List threads.
00178          */
00179         if (strncmp(buff, "threads", got) == 0) {
00180             NUTTHREADINFO *tdp;
00181             NUTTIMERINFO *tnp;
00182 
00183             fputs_P(thread_intro_P, stream);
00184             for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
00185                 fputs(tdp->td_name, stream);
00186                 switch (tdp->td_state) {
00187                 case TDS_TERM:
00188                     fputs("\tTerm\t", stream);
00189                     break;
00190                 case TDS_RUNNING:
00191                     fputs("\tRun\t", stream);
00192                     break;
00193                 case TDS_READY:
00194                     fputs("\tReady\t", stream);
00195                     break;
00196                 case TDS_SLEEP:
00197                     fputs("\tSleep\t", stream);
00198                     break;
00199                 }
00200                 fprintf(stream, "%u\t%u", tdp->td_priority, (u_int) tdp->td_sp - (u_int) tdp->td_memory);
00201                 if (*((u_long *) tdp->td_memory) != DEADBEEF)
00202                     fputs("\tCorrupted\t", stream);
00203                 else
00204                     fputs("\tOK\t", stream);
00205 
00206                 if ((tnp = (NUTTIMERINFO *) tdp->td_timer) != 0)
00207                     fprintf(stream, "%lu\r\n", tnp->tn_ticks_left);
00208                 else
00209                     fputs("None\r\n", stream);
00210             }
00211             fputs(".\r\n", stream);
00212             continue;
00213         }
00214 
00215         /*
00216          * List timers.
00217          */
00218         if (strncmp("timers", buff, got) == 0) {
00219             NUTTIMERINFO *tnp;
00220 
00221             fputs_P(timer_intro_P, stream);
00222             for (tnp = nutTimerList; tnp; tnp = tnp->tn_next) {
00223                 fprintf(stream, "%lu\t", tnp->tn_ticks_left);
00224                 if (tnp->tn_ticks)
00225                     fprintf(stream, "%lu\r\n", tnp->tn_ticks);
00226                 else
00227                     fputs("Oneshot\r\n", stream);
00228             }
00229             fputs(".\r\n", stream);
00230             continue;
00231         }
00232 
00233         /*
00234          * Quit connection.
00235          */
00236         if (strncmp("quit", buff, got) == 0) {
00237             break;
00238         }
00239 
00240         /*
00241          * Display help text on any unknown command.
00242          */
00243         fputs_P(help_P, stream);
00244     }
00245 }
00246 
00247 /*
00248  * Main application routine. 
00249  *
00250  * Nut/OS automatically calls this entry after initialization.
00251  */
00252 int main(void)
00253 {
00254     TCPSOCKET *sock;
00255     FILE *stream;
00256     u_long baud = 115200;
00257     u_char mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x55 };
00258 
00259     /*
00260      * Register all devices used in our application.
00261      */
00262     NutRegisterDevice(&DEV_DEBUG, 0, 0);
00263     NutRegisterDevice(&DEV_ETHER, 0x8300, 5);
00264 
00265     /*
00266      * Assign stdout to the UART device.
00267      */
00268     freopen(DEV_DEBUG_NAME, "w", stdout);
00269     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00270     printf_P(vbanner_P, NutVersionString());
00271 #ifdef NUTDEBUG
00272     NutTraceTcp(stdout, 1);
00273     NutTraceOs(stdout, 0);
00274     NutTraceHeap(stdout, 0);
00275     NutTracePPP(stdout, 0);
00276 #endif
00277 
00278     NutNetLoadConfig(DEV_ETHER_NAME);
00279     memcpy(confnet.cdn_mac, mac, 6);
00280     NutNetSaveConfig();
00281 
00282     /*
00283      * Setup the ethernet device. Try DHCP first. If this is
00284      * the first time boot with empty EEPROM and no DHCP server
00285      * was found, use hardcoded values.
00286      */
00287     printf("Configure eth0...");
00288     if (NutDhcpIfConfig("eth0", 0, 60000)) {
00289         printf("initial boot...");
00290         if (NutDhcpIfConfig("eth0", mac, 60000)) {
00291             u_long ip_addr = inet_addr("192.168.192.100");
00292             u_long ip_mask = inet_addr("255.255.255.0");
00293 
00294             printf("no DHCP...");
00295             NutNetIfConfig("eth0", mac, ip_addr, ip_mask);
00296             /* If not in a local network, we must also call 
00297                NutIpRouteAdd() to configure the routing. */
00298         }
00299     }
00300     puts("OK");
00301     printf("IP: %s\n", inet_ntoa(confnet.cdn_ip_addr));
00302 
00303     /*
00304      * Now loop endless for connections.
00305      */
00306     for (;;) {
00307         /*
00308          * Create a socket.
00309          */
00310         if ((sock = NutTcpCreateSocket()) != 0) {
00311             /*
00312              * Listen on port 23. If we return, we got a client.
00313              */
00314             printf("Waiting for a telnet client...");
00315             if (NutTcpAccept(sock, 23) == 0) {
00316                 puts("connected");
00317 
00318                 /*
00319                  * Open a stream and associate it with the socket, so 
00320                  * we can use standard I/O. Note, that socket streams
00321                  * currently do support text mode.
00322                  */
00323                 if ((stream = _fdopen((int) sock, "r+b")) != 0) {
00324                     /*
00325                      * Process client requests.
00326                      */
00327                     ProcessRequests(stream);
00328                     puts("Disconnected");
00329 
00330                     /*
00331                      * Close the stream.
00332                      */
00333                     fclose(stream);
00334                 } else
00335                     puts("Assigning a stream failed");
00336             } else
00337                 puts("failed");
00338 
00339             /*
00340              * Close our socket.
00341              */
00342             NutTcpCloseSocket(sock);
00343         }
00344     }
00345 }

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