2366f4201266245ee9fa3a2f3057537fbf56726e
[vpp.git] / src / uri / uri_socket_server.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <stdio.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <netdb.h>
22 #include <vppinfra/format.h>
23 #include <signal.h>
24 #include <sys/ucontext.h>
25
26 volatile int signal_received;
27
28 static void
29 unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
30 {
31   signal_received = 1;
32 }
33
34 static void
35 setup_signal_handler (void)
36 {
37   uword i;
38   struct sigaction sa;
39
40   for (i = 1; i < 32; i++)
41     {
42       memset (&sa, 0, sizeof (sa));
43       sa.sa_sigaction = (void *) unix_signal_handler;
44       sa.sa_flags = SA_SIGINFO;
45
46       switch (i)
47         {
48           /* these signals take the default action */
49         case SIGABRT:
50         case SIGKILL:
51         case SIGSTOP:
52         case SIGUSR1:
53         case SIGUSR2:
54           continue;
55
56           /* ignore SIGPIPE, SIGCHLD */
57         case SIGPIPE:
58         case SIGCHLD:
59           sa.sa_sigaction = (void *) SIG_IGN;
60           break;
61
62           /* catch and handle all other signals */
63         default:
64           break;
65         }
66
67       if (sigaction (i, &sa, 0) < 0)
68         clib_unix_warning ("sigaction %U", format_signal, i);
69     }
70 }
71
72
73 int
74 main (int argc, char *argv[])
75 {
76   int sockfd, portno, n, sent, accfd, reuse;
77   socklen_t client_addr_len;
78   struct sockaddr_in serv_addr;
79   struct sockaddr_in client;
80   struct hostent *server;
81   u8 *rx_buffer = 0;
82
83   if (argc > 1 && argc < 3)
84     {
85       fformat (stderr, "usage %s host port\n", argv[0]);
86       exit (0);
87     }
88
89   if (argc >= 3)
90     {
91       portno = atoi (argv[2]);
92       server = gethostbyname (argv[1]);
93       if (server == NULL)
94         {
95           clib_unix_warning ("gethostbyname");
96           exit (1);
97         }
98     }
99   else
100     {
101       /* Defaults */
102       portno = 1234;
103       server = gethostbyname ("6.0.1.1");
104       if (server == NULL)
105         {
106           clib_unix_warning ("gethostbyname");
107           exit (1);
108         }
109     }
110
111
112   setup_signal_handler ();
113
114   sockfd = socket (AF_INET, SOCK_STREAM, 0);
115   if (sockfd < 0)
116     {
117       clib_unix_error ("socket");
118       exit (1);
119     }
120
121   reuse = 1;
122   if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse,
123                   sizeof (reuse)) < 0)
124     {
125       clib_unix_error ("setsockopt(SO_REUSEADDR) failed");
126       exit (1);
127     }
128
129   bzero ((char *) &serv_addr, sizeof (serv_addr));
130   serv_addr.sin_family = AF_INET;
131   bcopy ((char *) server->h_addr,
132          (char *) &serv_addr.sin_addr.s_addr, server->h_length);
133   serv_addr.sin_port = htons (portno);
134   if (bind (sockfd, (const void *) &serv_addr, sizeof (serv_addr)) < 0)
135     {
136       clib_unix_warning ("bind");
137       exit (1);
138     }
139
140   vec_validate (rx_buffer, 8999 /* jumbo mtu */ );
141
142   if (listen (sockfd, 5 /* backlog */ ) < 0)
143     {
144       clib_unix_warning ("listen");
145       close (sockfd);
146       return 1;
147     }
148
149   while (1)
150     {
151       if (signal_received)
152         break;
153
154       client_addr_len = sizeof (struct sockaddr);
155       accfd = accept (sockfd, (struct sockaddr *) &client, &client_addr_len);
156       if (accfd < 0)
157         {
158           clib_unix_warning ("accept");
159           continue;
160         }
161       fformat (stderr, "Accepted connection from: %s : %d\n",
162                inet_ntoa (client.sin_addr), client.sin_port);
163       while (1)
164         {
165           n = recv (accfd, rx_buffer, vec_len (rx_buffer), 0 /* flags */ );
166           if (n == 0)
167             {
168               /* Graceful exit */
169               close (accfd);
170               break;
171             }
172           if (n < 0)
173             {
174               clib_unix_warning ("recv");
175               close (accfd);
176               break;
177             }
178
179           if (signal_received)
180             break;
181
182           sent = send (accfd, rx_buffer, n, 0 /* flags */ );
183           if (n < 0)
184             {
185               clib_unix_warning ("send");
186               close (accfd);
187               break;
188             }
189
190           if (sent != n)
191             {
192               clib_warning ("sent %d not %d", sent, n);
193             }
194
195           if (signal_received)
196             break;
197         }
198     }
199
200   close (sockfd);
201
202   return 0;
203 }
204
205
206 /*
207  * fd.io coding-style-patch-verification: ON
208  *
209  * Local Variables:
210  * eval: (c-set-style "gnu")
211  * End:
212  */