| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- /*
- * Copyright (C) 2009 by egnite GmbH
- * Copyright (C) 2001-2005 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 THE COPYRIGHT HOLDERS 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 THE
- * COPYRIGHT OWNER 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/
- *
- */
- /*!
- * $Id: tcps.c 4640 2012-09-24 12:05:56Z u_bonnes $
- */
- /*!
- * \example tcps/tcps.c
- *
- * Simple TCP server.
- *
- * \code telnet x.x.x.x \endcode
- *
- * on a command prompt, replacing x.x.x.x with the
- * IP address of your target board. Enter help
- * for a list of available commands.
- */
- /* Device specific definitions. */
- #include <dev/board.h>
- #include <dev/reset.h>
- #include <dev/gpio.h>
- /* OS specific definitions. */
- #include <sys/version.h>
- #include <sys/confnet.h>
- #include <sys/heap.h>
- #include <sys/timer.h>
- #include <sys/socket.h>
- /* Network specific definitions. */
- #include <arpa/inet.h>
- #include <net/if_var.h>
- #include <pro/dhcp.h>
- /* Standard C header files. */
- #include <stdlib.h>
- #include <stdio.h>
- #include <io.h>
- #include <string.h>
- #include <time.h>
- #include <ctype.h>
- /* Version of this application sample. */
- #define APP_VERSION "2.0.0"
- /* Max. size of the input line. */
- #define MAX_INPUT_LINE 32
- /* TCP server port. Telnet default is 23. */
- #define TCP_SERVER_PORT 23
- static time_t start_time;
- /*
- * Halt the application on fatal errors.
- */
- static void FatalError(char *msg)
- {
- /* Print a message ... */
- puts(msg);
- /* ... and never return. */
- for (;;);
- }
- /*
- * Extract command and up to 2 parameters from an input line.
- *
- * This helper routine splits a line into words. A pointer to the
- * first word is returned as a function result. A pointer to an
- * optional second word is set via a funtion parameter and a
- * pointer to the rest of the line is set via a second function
- * parameter.
- *
- * Example:
- *
- * If line points to "help me to get this done", then we can use
- *
- * char *cmd;
- * char *param1;
- * char *param2;
- *
- * cmd = ParseLine(line, ¶m1, ¶m2);
- *
- * On return, cmd will point to "help", param1 will point to "me"
- * and param 2 will point to "to get this done".
- *
- * If the line contains less than 3 words, then the second
- * parameter pointer is set to NULL. With one word only, also
- * the first parameter pointer is set to NULL. The function
- * result is NULL on empty lines, including lines containing
- * all spaces.
- *
- * Leading spaces are skipped. Trailing end of line characters
- * are removed.
- *
- * Note, that the original contents of the line will be
- * modified.
- */
- static char *ParseLine(char *line, char **pp1, char **pp2)
- {
- char *p0;
- char *cp;
- /* Initialize parameter pointers to NULL. */
- *pp1 = NULL;
- *pp2 = NULL;
- /* Chop off EOL. */
- cp = strchr(line, '\r');
- if (cp) {
- *cp = 0;
- }
- cp = strchr(line, '\n');
- if (cp) {
- *cp = 0;
- }
- /*
- * Parse line for command and parameters.
- */
- p0 = line;
- while (isspace((int)*p0)) {
- /* Skip leading spaces. */
- p0++;
- }
- if (*p0 == '\0') {
- /* Return NULL on empty lines. */
- return NULL;
- }
- cp = strchr(p0, ' ');
- if (cp) {
- *cp++ = '\0';
- while (isspace((int)*cp)) {
- /* Skip leading spaces. */
- cp++;
- }
- if (*cp) {
- /* First parameter found. */
- *pp1 = cp;
- cp = strchr(cp, ' ');
- } else {
- cp = NULL;
- }
- if (cp) {
- *cp++ = '\0';
- while (isspace((int)*cp)) {
- /* Skip leading spaces. */
- cp++;
- }
- if (*cp) {
- /* Remaining parameter(s) found. */
- *pp2 = cp;
- }
- }
- }
- /* Return pointer to command. */
- return p0;
- }
- /*
- * Process client requests.
- *
- * This function is called when a connection has been established
- * and returns when the connection is closed.
- */
- static void ProcessRequests(FILE * stream)
- {
- char *buff;
- char *cmd;
- size_t clen;
- char *p1;
- char *p2;
- /*
- * Allocate an input buffer. Check the result.
- */
- buff = malloc(MAX_INPUT_LINE + 1);
- if (buff == NULL) {
- return;
- }
- /*
- * Send a welcome banner to the new client.
- */
- fputs("200 Welcome to tcps. Type help to get help.\r\n", stream);
- for (;;) {
- /*
- * Flush any pending output and read in a new line.
- *
- * If you want line editing capabilities, check
- * http://www.ethernut.de/nutwiki/Input_Line_Editor
- */
- fflush(stream);
- if (fgets(buff, MAX_INPUT_LINE, stream) == NULL) {
- /* Probably a disconnect, return. */
- break;
- }
- /* Parse the input line. */
- cmd = ParseLine(buff, &p1, &p2);
- if (cmd == NULL) {
- /* Skip empty lines. */
- continue;
- }
- /* Retrieve command length for abbreviations. */
- clen = strlen(cmd);
- /*
- * Process memory info request.
- *
- * http://www.ethernut.de/nutwiki/Heap_Memory
- */
- if (strncmp(cmd, "heap", clen) == 0) {
- fprintf(stream, "210 %u bytes RAM free\r\n", (unsigned int)NutHeapAvailable());
- continue;
- }
- /*
- * Process IP address configuration.
- */
- if (strncmp(cmd, "ip", clen) == 0) {
- uint32_t ip = p1 ? inet_addr(p1) : (uint32_t) -1;
- if (ip == (uint32_t) -1) {
- fputs("420 Invalid or missing address\r\n", stream);
- } else {
- confnet.cdn_cip_addr = ip;
- if (NutNetSaveConfig()) {
- fputs("421 Failed to save configuration\r\n", stream);
- } else {
- fputs("220 Configuration saved\r\n", stream);
- }
- }
- continue;
- }
- /*
- * Process IP mask configuration.
- */
- if (strncmp(cmd, "mask", clen) == 0) {
- uint32_t mask = p1 ? inet_addr(p1) : (uint32_t) -1;
- if (mask == (uint32_t) -1) {
- fputs("430 Invalid or missing mask\r\n", stream);
- } else {
- confnet.cdn_ip_mask = mask;
- if (NutNetSaveConfig()) {
- fputs("421 Failed to save configuration\r\n", stream);
- } else {
- fputs("230 Configuration saved\r\n", stream);
- }
- }
- continue;
- }
- #ifndef MCU_GBA
- /*
- * Process GPIO pin status, not available on GameBoy.
- *
- * http://www.ethernut.de/nutwiki/LowLevelPortIo
- */
- if (strncmp(cmd, "pin", clen) == 0) {
- int bank = p1 ? atoi(p1) : 0;
- int bit = p2 ? atoi(p2) : 0;
- int state = GpioPinGet(bank, bit);
- fprintf(stream, "240 %d at GPIO bank %d bit %d\r\n", state, bank, bit);
- continue;
- }
- #endif
- /*
- * Process serial line send request.
- */
- if (strncmp(cmd, "send", clen) == 0) {
- if (p1) {
- printf("%s", p1);
- if (p1) {
- printf(" %s", p2);
- }
- }
- putchar('\n');
- fputs("250 Message sent\r\n", stream);
- continue;
- }
- /*
- * Process time info request.
- */
- if (strncmp(cmd, "uptime", clen) == 0) {
- fprintf(stream, "220 %ld seconds running\r\n", (long)(time(NULL) - start_time));
- continue;
- }
- /*
- * Process system reset request.
- *
- * http://www.ethernut.de/nutwiki/System_Reset
- */
- if (strncmp(cmd, "reset", clen) == 0) {
- fputs("910 System reset\r\n", stream);
- fflush(stream);
- NutSleep(1000);
- NutReset();
- fputs("490 System reset not implemented\r\n", stream);
- continue;
- }
- /*
- * Quit connection.
- */
- if (strncmp(cmd, "quit", clen) == 0) {
- fputs("900 Bye\r\n", stream);
- fflush(stream);
- break;
- }
- /*
- * Display help text on any unknown command.
- */
- fputs("400 List of commands follows\r\n"
- "h[eap] Query heap memory bytes available.\r\n"
- "i[p] Set IP <address>.\r\n"
- "m[ask] Set IP <mask>.\r\n"
- #ifndef MCU_GBA
- "p[in] Query status of GPIO pin <bank> <bit>.\r\n"
- #endif
- "r[eset] Reset system.\r\n"
- "s[end] Send <message> to serial port.\r\n"
- "u[ptime] Query number of seconds the system is running.\r\n"
- "q[uit] Terminates connection.\r\n"
- ".\r\n", stream);
- }
- free(buff);
- }
- /*
- * Main application routine.
- *
- * Nut/OS automatically calls this entry after initialization.
- */
- int main(void)
- {
- TCPSOCKET *sock;
- FILE *stream;
- uint32_t baud = 115200;
- /*
- * Assign stdout to the DEBUG device.
- */
- NutRegisterDevice(&DEV_CONSOLE, 0, 0);
- freopen(DEV_CONSOLE.dev_name, "w", stdout);
- _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
- /*
- * Print out our version information.
- */
- printf("\n\nNut/OS %s\n", NutVersionString());
- printf("TCP Server Sample %s\n", APP_VERSION);
- /*
- * Configure the network interface. It is assumed, that
- * we got a valid configuration in non-volatile memory.
- *
- * For alternatives see
- * http://www.ethernut.de/nutwiki/Network_Configuration
- */
- printf("Configure %s...", DEV_ETHER_NAME);
- if (NutRegisterDevice(&DEV_ETHER, 0, 0)) {
- FatalError("failed");
- }
- if (NutDhcpIfConfig("eth0", 0, 60000)) {
- FatalError("no valid network configuration");
- }
- printf("OK\nRun 'telnet %s", inet_ntoa(confnet.cdn_ip_addr));
- #if TCP_SERVER_PORT != 23
- printf(" %d", TCP_SERVER_PORT);
- #endif
- puts("' to connect to this server");
- /* Set the start time. */
- start_time = time(NULL);
- /*
- * Now loop endless for client connections.
- *
- * Note, that we are only able to serve one client at a time.
- * If you want to allow concurrent connections, then this
- * loop must run in threads. Then each thread can handle one
- * client. See
- * http://www.ethernut.de/nutwiki/Multithreading
- */
- for (;;) {
- /* Create a socket. */
- if ((sock = NutTcpCreateSocket()) != 0) {
- printf("Waiting for a telnet client...");
- /* Listen on port 23. If we return, we got a client. */
- if (NutTcpAccept(sock, TCP_SERVER_PORT) == 0) {
- puts("connected");
- /*
- * Open a stream and associate it with the socket, so
- * we can use standard I/O. Note, that socket streams
- * currently do support cooked text mode.
- */
- stream = _fdopen((int) sock, "r+b");
- if (stream) {
- /* Process client requests as long as the connection is
- * established.
- *
- * Note, that unplugging the network cable will not terminate
- * a TCP connection by default. If you need this, you may set
- * a receive timeout on the socket:
- *
- * uint32_t to = 5000;
- * NutTcpSetSockOpt(sock, SO_RCVTIMEO, &to, sizeof(to));
- *
- * See also
- * http://www.ethernut.de/nutwiki/Socket_Timeouts
- */
- ProcessRequests(stream);
- /* Close the stream. */
- fclose(stream);
- } else {
- puts("Assigning a stream failed");
- }
- } else {
- puts("failed");
- }
- /* Close our socket. */
- NutTcpCloseSocket(sock);
- puts("Disconnected");
- }
- }
- /* Never reached, but required to suppress compiler warning. */
- return 0;
- }
|