/**************************************************************************** * examples/nettest/nettest.c * * Copyright (C) 2007 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * 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 Gregory Nutt nor the names of its 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include "nettest.h" /**************************************************************************** * Public Functions ****************************************************************************/ void recv_server(void) { struct sockaddr_in myaddr; #ifdef NETTEST_HAVE_SOLINGER struct linger ling; #endif char buffer[1024]; int listensd; int acceptsd; socklen_t addrlen; int nbytesread; #ifndef CONFIG_EXAMPLE_NETTEST_PERFORMANCE int totalbytesread; int nbytessent; int ch; int i; #endif int optval; /* Create a new TCP socket */ listensd = socket(PF_INET, SOCK_STREAM, 0); if (listensd < 0) { message("server: socket failure: %d\n", errno); exit(1); } /* Set socket to reuse address */ optval = 1; if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0) { message("server: setsockopt SO_REUSEADDR failure: %d\n", errno); exit(1); } /* Bind the socket to a local address */ myaddr.sin_family = AF_INET; myaddr.sin_port = HTONS(PORTNO); myaddr.sin_addr.s_addr = INADDR_ANY; if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0) { message("server: bind failure: %d\n", errno); exit(1); } /* Listen for connections on the bound TCP socket */ if (listen(listensd, 5) < 0) { message("server: listen failure %d\n", errno); exit(1); } /* Accept only one connection */ message("server: Accepting connections on port %d\n", PORTNO); addrlen = sizeof(struct sockaddr_in); acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen); if (acceptsd < 0) { message("server: accept failure: %d\n", errno); exit(1); } message("server: Connection accepted -- receiving\n"); /* Configure to "linger" until all data is sent when the socket is closed */ #ifdef NETTEST_HAVE_SOLINGER ling.l_onoff = 1; ling.l_linger = 30; /* timeout is seconds */ if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0) { message("server: setsockopt SO_LINGER failure: %d\n", errno); exit(1); } #endif #ifdef CONFIG_EXAMPLE_NETTEST_PERFORMANCE /* Then receive data forever */ for (;;) { nbytesread = recv(acceptsd, buffer, 1024, 0); if (nbytesread <= 0) { message("server: recv failed: %d\n", errno); close(listensd); close(acceptsd); exit(-1); } } #else /* Receive canned message */ totalbytesread = 0; while (totalbytesread < SENDSIZE) { message("server: Reading...\n"); nbytesread = recv(acceptsd, &buffer[totalbytesread], 1024 - totalbytesread, 0); if (nbytesread <= 0) { message("server: recv failed: %d\n", errno); close(listensd); close(acceptsd); exit(-1); } totalbytesread += nbytesread; message("server: Received %d of %d bytes\n", totalbytesread, SENDSIZE); } /* Verify the message */ if (totalbytesread != SENDSIZE) { message("server: Received %d / Expected %d bytes\n", totalbytesread, SENDSIZE); close(listensd); close(acceptsd); exit(-1); } ch = 0x20; for (i = 0; i < SENDSIZE; i++ ) { if (buffer[i] != ch) { message("server: Byte %d is %02x / Expected %02x\n", i, buffer[i], ch); close(listensd); close(acceptsd); exit(-1); } if (++ch > 0x7e) { ch = 0x20; } } #ifdef CONFIG_EXAMPLE_NETTEST_HOST /* At present, data received by the target before it is completed the * the write opertion and started the read operation results in a failure * (the data is not received, but it is ACKed). This will have to be * fixed. */ # warning "FIXME: This should not be necessary" sleep(10); #endif /* Then send the same data back to the client */ message("server: Sending %d bytes\n", totalbytesread); nbytessent = send(acceptsd, buffer, totalbytesread, 0); if (nbytessent <= 0) { message("server: send failed: %d\n", errno); close(listensd); close(acceptsd); exit(-1); } message("server: Sent %d bytes\n", nbytessent); /* If this platform only does abortive disconnects, then wait a bit to get the * client side a change to receive the data. */ #if 1 /* Do it for all platforms */ message("server: Wait before closing\n"); sleep(60); #endif close(listensd); close(acceptsd); #endif }