diff options
Diffstat (limited to 'extras/apps/src/socket_echo_server.c')
-rw-r--r-- | extras/apps/src/socket_echo_server.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/extras/apps/src/socket_echo_server.c b/extras/apps/src/socket_echo_server.c new file mode 100644 index 00000000000..4f4c5f30803 --- /dev/null +++ b/extras/apps/src/socket_echo_server.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <vppinfra/format.h> +#include <signal.h> +#include <sys/ucontext.h> +#include <sys/time.h> + +volatile int signal_received; + +static void +unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc) +{ + signal_received = 1; +} + +static void +setup_signal_handler (void) +{ + uword i; + struct sigaction sa; + + for (i = 1; i < 32; i++) + { + memset (&sa, 0, sizeof (sa)); + sa.sa_sigaction = (void *) unix_signal_handler; + sa.sa_flags = SA_SIGINFO; + + switch (i) + { + /* these signals take the default action */ + case SIGABRT: + case SIGKILL: + case SIGSTOP: + case SIGUSR1: + case SIGUSR2: + continue; + + /* ignore SIGPIPE, SIGCHLD */ + case SIGPIPE: + case SIGCHLD: + sa.sa_sigaction = (void *) SIG_IGN; + break; + + /* catch and handle all other signals */ + default: + break; + } + + if (sigaction (i, &sa, 0) < 0) + clib_unix_warning ("sigaction %U", format_signal, i); + } +} + + +int +main (int argc, char *argv[]) +{ + int sockfd, portno, n, sent, accfd, reuse; + socklen_t client_addr_len; + struct sockaddr_in serv_addr; + struct sockaddr_in client; + struct hostent *server; + u8 *rx_buffer = 0, no_echo = 0; + struct timeval start, end; + long rcvd = 0; + double deltat; + + if (argc > 1 && argc < 3) + { + fformat (stderr, "usage %s host port\n", argv[0]); + exit (0); + } + + if (argc >= 4) + { + no_echo = atoi (argv[3]); + portno = atoi (argv[2]); + server = gethostbyname (argv[1]); + if (server == NULL) + { + clib_unix_warning ("gethostbyname"); + exit (1); + } + } + else + { + /* Defaults */ + portno = 1234; + server = gethostbyname ("6.0.1.1"); + if (server == NULL) + { + clib_unix_warning ("gethostbyname"); + exit (1); + } + } + + + setup_signal_handler (); + + sockfd = socket (AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + { + clib_unix_error ("socket"); + exit (1); + } + + reuse = 1; + if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse, + sizeof (reuse)) < 0) + { + clib_unix_error ("setsockopt(SO_REUSEADDR) failed"); + exit (1); + } + + bzero ((char *) &serv_addr, sizeof (serv_addr)); + serv_addr.sin_family = AF_INET; + bcopy ((char *) server->h_addr, + (char *) &serv_addr.sin_addr.s_addr, server->h_length); + serv_addr.sin_port = htons (portno); + if (bind (sockfd, (const void *) &serv_addr, sizeof (serv_addr)) < 0) + { + clib_unix_warning ("bind"); + exit (1); + } + + vec_validate (rx_buffer, 128 << 10); + + if (listen (sockfd, 5 /* backlog */ ) < 0) + { + clib_unix_warning ("listen"); + close (sockfd); + return 1; + } + + while (1) + { + if (signal_received) + break; + + client_addr_len = sizeof (struct sockaddr); + accfd = accept (sockfd, (struct sockaddr *) &client, &client_addr_len); + if (accfd < 0) + { + clib_unix_warning ("accept"); + continue; + } + fformat (stderr, "Accepted connection from: %s : %d\n", + inet_ntoa (client.sin_addr), client.sin_port); + gettimeofday (&start, NULL); + + while (1) + { + n = recv (accfd, rx_buffer, vec_len (rx_buffer), 0 /* flags */ ); + if (n == 0) + { + /* Graceful exit */ + close (accfd); + gettimeofday (&end, NULL); + deltat = (end.tv_sec - start.tv_sec); + deltat += (end.tv_usec - start.tv_usec) / 1000000.0; + clib_warning ("Finished in %.6f", deltat); + clib_warning ("%.4f Gbit/second %s", + (((f64) rcvd * 8.0) / deltat / 1e9), + no_echo ? "half" : "full"); + rcvd = 0; + break; + } + if (n < 0) + { + clib_unix_warning ("recv"); + close (accfd); + break; + } + + if (signal_received) + break; + + rcvd += n; + if (no_echo) + continue; + + sent = send (accfd, rx_buffer, n, 0 /* flags */ ); + if (n < 0) + { + clib_unix_warning ("send"); + close (accfd); + break; + } + + if (sent != n) + { + clib_warning ("sent %d not %d", sent, n); + } + + if (signal_received) + break; + } + } + + close (sockfd); + + return 0; +} + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |