tls: enforce certificate verification
[vpp.git] / src / tests / vnet / session / tcp_echo.c
1 /*
2  * Copyright (c) 2016 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 <signal.h>
18
19 #include <vnet/session/application_interface.h>
20 #include <svm/svm_fifo_segment.h>
21 #include <vlibmemory/api.h>
22
23 #include <vpp/api/vpe_msg_enum.h>
24
25 #define vl_typedefs             /* define message structures */
26 #include <vpp/api/vpe_all_api_h.h>
27 #undef vl_typedefs
28
29 /* declare message handlers for each api */
30
31 #define vl_endianfun            /* define message structures */
32 #include <vpp/api/vpe_all_api_h.h>
33 #undef vl_endianfun
34
35 /* instantiate all the print functions we know about */
36 #define vl_print(handle, ...)
37 #define vl_printfun
38 #include <vpp/api/vpe_all_api_h.h>
39 #undef vl_printfun
40
41 typedef struct
42 {
43   svm_fifo_t *server_rx_fifo;
44   svm_fifo_t *server_tx_fifo;
45
46   u64 vpp_session_handle;
47   u64 bytes_received;
48   f64 start;
49 } session_t;
50
51 typedef enum
52 {
53   STATE_START,
54   STATE_ATTACHED,
55   STATE_READY,
56   STATE_DISCONNECTING,
57   STATE_FAILED
58 } connection_state_t;
59
60 typedef struct
61 {
62   /* vpe input queue */
63   svm_queue_t *vl_input_queue;
64
65   /* API client handle */
66   u32 my_client_index;
67
68   /* The URI we're playing with */
69   u8 *uri;
70
71   /* Session pool */
72   session_t *sessions;
73
74   /* Hash table for disconnect processing */
75   uword *session_index_by_vpp_handles;
76
77   /* intermediate rx buffer */
78   u8 *rx_buf;
79
80   /* URI for slave's connect */
81   u8 *connect_uri;
82
83   u32 connected_session_index;
84
85   int i_am_master;
86
87   /* drop all packets */
88   int drop_packets;
89
90   /* Our event queue */
91   svm_queue_t *our_event_queue;
92
93   /* $$$ single thread only for the moment */
94   svm_queue_t *vpp_event_queue;
95
96   u8 *socket_name;
97
98   pid_t my_pid;
99
100   /* For deadman timers */
101   clib_time_t clib_time;
102
103   /* State of the connection, shared between msg RX thread and main thread */
104   volatile connection_state_t state;
105
106   /* Signal variables */
107   volatile int time_to_stop;
108   volatile int time_to_print_stats;
109
110   u32 configured_segment_size;
111
112   /* VNET_API_ERROR_FOO -> "Foo" hash table */
113   uword *error_string_by_error_number;
114
115   u8 *connect_test_data;
116   pthread_t client_rx_thread_handle;
117   u32 client_bytes_received;
118   u8 test_return_packets;
119   u64 bytes_to_send;
120
121   /** Flag that decides if socket, instead of svm, api is used to connect to
122    * vpp. If sock api is used, shm binary api is subsequently bootstrapped
123    * and all other messages are exchanged using shm IPC. */
124   u8 use_sock_api;
125
126   /* convenience */
127   svm_fifo_segment_main_t *segment_main;
128 } echo_main_t;
129
130 echo_main_t echo_main;
131
132 #if CLIB_DEBUG > 0
133 #define NITER 10000
134 #else
135 #define NITER 4000000
136 #endif
137
138 const char test_srv_crt_rsa[] =
139   "-----BEGIN CERTIFICATE-----\r\n"
140   "MIID5zCCAs+gAwIBAgIJALeMYCEHrTtJMA0GCSqGSIb3DQEBCwUAMIGJMQswCQYD\r\n"
141   "VQQGEwJVUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMQ4wDAYDVQQK\r\n"
142   "DAVDaXNjbzEOMAwGA1UECwwFZmQuaW8xFjAUBgNVBAMMDXRlc3R0bHMuZmQuaW8x\r\n"
143   "IjAgBgkqhkiG9w0BCQEWE3ZwcC1kZXZAbGlzdHMuZmQuaW8wHhcNMTgwMzA1MjEx\r\n"
144   "NTEyWhcNMjgwMzAyMjExNTEyWjCBiTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNB\r\n"
145   "MREwDwYDVQQHDAhTYW4gSm9zZTEOMAwGA1UECgwFQ2lzY28xDjAMBgNVBAsMBWZk\r\n"
146   "LmlvMRYwFAYDVQQDDA10ZXN0dGxzLmZkLmlvMSIwIAYJKoZIhvcNAQkBFhN2cHAt\r\n"
147   "ZGV2QGxpc3RzLmZkLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\r\n"
148   "4C1k8a1DuStgggqT4o09fP9sJ2dC54bxhS/Xk2VEfaIZ222WSo4X/syRVfVy9Yah\r\n"
149   "cpI1zJ/RDxaZSFhgA+nPZBrFMsrULkrdAOpOVj8eDEp9JuWdO2ODSoFnCvLxcYWB\r\n"
150   "Yc5kHryJpEaGJl1sFQSesnzMFty/59ta0stk0Fp8r5NhIjWvSovGzPo6Bhz+VS2c\r\n"
151   "ebIZh4x1t2hHaFcgm0qJoJ6DceReWCW8w+yOVovTolGGq+bpb2Hn7MnRSZ2K2NdL\r\n"
152   "+aLXpkZbS/AODP1FF2vTO1mYL290LO7/51vJmPXNKSDYMy5EvILr5/VqtjsFCwRL\r\n"
153   "Q4jcM/+GeHSAFWx4qIv0BwIDAQABo1AwTjAdBgNVHQ4EFgQUWa1SOB37xmT53tZQ\r\n"
154   "aXuLLhRI7U8wHwYDVR0jBBgwFoAUWa1SOB37xmT53tZQaXuLLhRI7U8wDAYDVR0T\r\n"
155   "BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoUht13W4ya27NVzQuCMvqPWL3VM4\r\n"
156   "3xbPFk02FaGz/WupPu276zGlzJAZrbuDcQowwwU1Ni1Yygxl96s1c2M5rHDTrOKG\r\n"
157   "rK0hbkSFBo+i6I8u4HiiQ4rYmG0Hv6+sXn3of0HsbtDPGgWZoipPWDljPYEURu3e\r\n"
158   "3HRe/Dtsj9CakBoSDzs8ndWaBR+f4sM9Tk1cjD46Gq2T/qpSPXqKxEUXlzhdCAn4\r\n"
159   "twub17Bq2kykHpppCwPg5M+v30tHG/R2Go15MeFWbEJthFk3TZMjKL7UFs7fH+x2\r\n"
160   "wSonXb++jY+KmCb93C+soABBizE57g/KmiR2IxQ/LMjDik01RSUIaM0lLA==\r\n"
161   "-----END CERTIFICATE-----\r\n";
162 const u32 test_srv_crt_rsa_len = sizeof (test_srv_crt_rsa);
163
164 const char test_srv_key_rsa[] =
165   "-----BEGIN PRIVATE KEY-----\r\n"
166   "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgLWTxrUO5K2CC\r\n"
167   "CpPijT18/2wnZ0LnhvGFL9eTZUR9ohnbbZZKjhf+zJFV9XL1hqFykjXMn9EPFplI\r\n"
168   "WGAD6c9kGsUyytQuSt0A6k5WPx4MSn0m5Z07Y4NKgWcK8vFxhYFhzmQevImkRoYm\r\n"
169   "XWwVBJ6yfMwW3L/n21rSy2TQWnyvk2EiNa9Ki8bM+joGHP5VLZx5shmHjHW3aEdo\r\n"
170   "VyCbSomgnoNx5F5YJbzD7I5Wi9OiUYar5ulvYefsydFJnYrY10v5otemRltL8A4M\r\n"
171   "/UUXa9M7WZgvb3Qs7v/nW8mY9c0pINgzLkS8guvn9Wq2OwULBEtDiNwz/4Z4dIAV\r\n"
172   "bHioi/QHAgMBAAECggEBAMzGipP8+oT166U+NlJXRFifFVN1DvdhG9PWnOxGL+c3\r\n"
173   "ILmBBC08WQzmHshPemBvR6DZkA1H23cV5JTiLWrFtC00CvhXsLRMrE5+uWotI6yE\r\n"
174   "iofybMroHvD6/X5R510UX9hQ6MHu5ShLR5VZ9zXHz5MpTmB/60jG5dLx+jgcwBK8\r\n"
175   "LuGv2YB/WCUwT9QJ3YU2eaingnXtz/MrFbkbltrqlnBdlD+kTtw6Yac9y1XuuQXc\r\n"
176   "BPeulLNDuPolJVWbUvDBZrpt2dXTgz8ws1sv+wCNE0xwQJsqW4Nx3QkpibUL9RUr\r\n"
177   "CVbKlNfa9lopT6nGKlgX69R/uH35yh9AOsfasro6w0ECgYEA82UJ8u/+ORah+0sF\r\n"
178   "Q0FfW5MTdi7OAUHOz16pUsGlaEv0ERrjZxmAkHA/VRwpvDBpx4alCv0Hc39PFLIk\r\n"
179   "nhSsM2BEuBkTAs6/GaoNAiBtQVE/hN7awNRWVmlieS0go3Y3dzaE9IUMyj8sPOFT\r\n"
180   "5JdJ6BM69PHKCkY3dKdnnfpFEuECgYEA68mRpteunF1mdZgXs+WrN+uLlRrQR20F\r\n"
181   "ZyMYiUCH2Dtn26EzA2moy7FipIIrQcX/j+KhYNGM3e7MU4LymIO29E18mn8JODnH\r\n"
182   "sQOXzBTsf8A4yIVMkcuQD3bfb0JiUGYUPOidTp2N7IJA7+6Yc3vQOyb74lnKnJoO\r\n"
183   "gougPT2wS+cCgYAn7muzb6xFsXDhyW0Tm6YJYBfRS9yAWEuVufINobeBZPSl2cN1\r\n"
184   "Jrnw+HlrfTNbrJWuJmjtZJXUXQ6cVp2rUbjutNyRV4vG6iRwEXYQ40EJdkr1gZpi\r\n"
185   "CHQhuShuuPih2MNAy7EEbM+sXrDjTBR3bFqzuHPzu7dp+BshCFX3lRfAAQKBgGQt\r\n"
186   "K5i7IhCFDjb/+3IPLgOAK7mZvsvZ4eXD33TQ2eZgtut1PXtBtNl17/b85uv293Fm\r\n"
187   "VDISVcsk3eLNS8zIiT6afUoWlxAwXEs0v5WRfjl4radkGvgGiJpJYvyeM67877RB\r\n"
188   "EDSKc/X8ESLfOB44iGvZUEMG6zJFscx9DgN25iQZAoGAbyd+JEWwdVH9/K3IH1t2\r\n"
189   "PBkZX17kNWv+iVM1WyFjbe++vfKZCrOJiyiqhDeEqgrP3AuNMlaaduC3VRC3G5oV\r\n"
190   "Mj1tlhDWQ/qhvKdCKNdIVQYDE75nw+FRWV8yYkHAnXYW3tNoweDIwixE0hkPR1bc\r\n"
191   "oEjPLVNtx8SOj/M4rhaPT3I=\r\n" "-----END PRIVATE KEY-----\r\n";
192 const u32 test_srv_key_rsa_len = sizeof (test_srv_key_rsa);
193
194 static u8 *
195 format_api_error (u8 * s, va_list * args)
196 {
197   echo_main_t *em = &echo_main;
198   i32 error = va_arg (*args, u32);
199   uword *p;
200
201   p = hash_get (em->error_string_by_error_number, -error);
202
203   if (p)
204     s = format (s, "%s", p[0]);
205   else
206     s = format (s, "%d", error);
207   return s;
208 }
209
210 static void
211 init_error_string_table (echo_main_t * em)
212 {
213   em->error_string_by_error_number = hash_create (0, sizeof (uword));
214
215 #define _(n,v,s) hash_set (em->error_string_by_error_number, -v, s);
216   foreach_vnet_api_error;
217 #undef _
218
219   hash_set (em->error_string_by_error_number, 99, "Misc");
220 }
221
222 int
223 wait_for_state_change (echo_main_t * em, connection_state_t state)
224 {
225 #if CLIB_DEBUG > 0
226 #define TIMEOUT 600.0
227 #else
228 #define TIMEOUT 600.0
229 #endif
230
231   f64 timeout = clib_time_now (&em->clib_time) + TIMEOUT;
232
233   while (clib_time_now (&em->clib_time) < timeout)
234     {
235       if (em->state == state)
236         return 0;
237       if (em->state == STATE_FAILED)
238         return -1;
239       if (em->time_to_stop == 1)
240         return 0;
241     }
242   clib_warning ("timeout waiting for STATE_READY");
243   return -1;
244 }
245
246 void
247 application_send_attach (echo_main_t * em)
248 {
249   vl_api_application_attach_t *bmp;
250   vl_api_application_tls_cert_add_t *cert_mp;
251   vl_api_application_tls_key_add_t *key_mp;
252
253   u32 fifo_size = 4 << 20;
254   bmp = vl_msg_api_alloc (sizeof (*bmp));
255   memset (bmp, 0, sizeof (*bmp));
256
257   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH);
258   bmp->client_index = em->my_client_index;
259   bmp->context = ntohl (0xfeedface);
260   bmp->options[APP_OPTIONS_FLAGS] =
261     APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT;
262   bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = 16;
263   bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = fifo_size;
264   bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = fifo_size;
265   bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = 128 << 20;
266   bmp->options[APP_OPTIONS_SEGMENT_SIZE] = 256 << 20;
267   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & bmp);
268
269   cert_mp = vl_msg_api_alloc (sizeof (*cert_mp) + test_srv_crt_rsa_len);
270   memset (cert_mp, 0, sizeof (*cert_mp));
271   cert_mp->_vl_msg_id = ntohs (VL_API_APPLICATION_TLS_CERT_ADD);
272   cert_mp->client_index = em->my_client_index;
273   cert_mp->context = ntohl (0xfeedface);
274   cert_mp->cert_len = clib_host_to_net_u16 (test_srv_crt_rsa_len);
275   clib_memcpy (cert_mp->cert, test_srv_crt_rsa, test_srv_crt_rsa_len);
276   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & cert_mp);
277
278   key_mp = vl_msg_api_alloc (sizeof (*key_mp) + test_srv_key_rsa_len);
279   memset (key_mp, 0, sizeof (*key_mp) + test_srv_key_rsa_len);
280   key_mp->_vl_msg_id = ntohs (VL_API_APPLICATION_TLS_KEY_ADD);
281   key_mp->client_index = em->my_client_index;
282   key_mp->context = ntohl (0xfeedface);
283   key_mp->key_len = clib_host_to_net_u16 (test_srv_key_rsa_len);
284   clib_memcpy (key_mp->key, test_srv_key_rsa, test_srv_key_rsa_len);
285   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & key_mp);
286 }
287
288 int
289 application_attach (echo_main_t * em)
290 {
291   application_send_attach (em);
292   if (wait_for_state_change (em, STATE_ATTACHED))
293     {
294       clib_warning ("timeout waiting for STATE_ATTACHED");
295       return -1;
296     }
297   return 0;
298 }
299
300 void
301 application_detach (echo_main_t * em)
302 {
303   vl_api_application_detach_t *bmp;
304   bmp = vl_msg_api_alloc (sizeof (*bmp));
305   memset (bmp, 0, sizeof (*bmp));
306
307   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
308   bmp->client_index = em->my_client_index;
309   bmp->context = ntohl (0xfeedface);
310   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & bmp);
311
312   clib_warning ("Sent detach");
313 }
314
315 static int
316 memfd_segment_attach (void)
317 {
318   ssvm_private_t _ssvm = { 0 }, *ssvm = &_ssvm;
319   clib_error_t *error;
320   int rv;
321
322   if ((error = vl_socket_client_recv_fd_msg (&ssvm->fd, 5)))
323     {
324       clib_error_report (error);
325       return -1;
326     }
327
328   if ((rv = ssvm_slave_init_memfd (ssvm)))
329     return rv;
330
331   return 0;
332 }
333
334 static int
335 fifo_segment_attach (char *name, u32 size, ssvm_segment_type_t type)
336 {
337   svm_fifo_segment_create_args_t _a, *a = &_a;
338   clib_error_t *error;
339   int rv;
340
341   memset (a, 0, sizeof (*a));
342   a->segment_name = (char *) name;
343   a->segment_size = size;
344   a->segment_type = type;
345
346   if (type == SSVM_SEGMENT_MEMFD)
347     {
348       if ((error = vl_socket_client_recv_fd_msg (&a->memfd_fd, 5)))
349         {
350           clib_error_report (error);
351           return -1;
352         }
353     }
354
355   if ((rv = svm_fifo_segment_attach (a)))
356     {
357       clib_warning ("svm_fifo_segment_attach ('%s') failed", name);
358       return rv;
359     }
360
361   return 0;
362 }
363
364 static void
365 vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t *
366                                            mp)
367 {
368   echo_main_t *em = &echo_main;
369   ssvm_segment_type_t seg_type;
370
371   if (mp->retval)
372     {
373       clib_warning ("attach failed: %U", format_api_error,
374                     clib_net_to_host_u32 (mp->retval));
375       em->state = STATE_FAILED;
376       return;
377     }
378
379   if (mp->segment_name_length == 0)
380     {
381       clib_warning ("segment_name_length zero");
382       return;
383     }
384
385   seg_type = em->use_sock_api ? SSVM_SEGMENT_MEMFD : SSVM_SEGMENT_SHM;
386
387   /* Attach to fifo segment */
388   if (fifo_segment_attach ((char *) mp->segment_name, mp->segment_size,
389                            seg_type))
390     {
391       em->state = STATE_FAILED;
392       return;
393     }
394
395   /* If we're using memfd segments, read and attach to event qs segment */
396   if (seg_type == SSVM_SEGMENT_MEMFD)
397     {
398       if (memfd_segment_attach ())
399         {
400           clib_warning ("failed to attach to evt q segment");
401           em->state = STATE_FAILED;
402           return;
403         }
404     }
405
406   ASSERT (mp->app_event_queue_address);
407   em->our_event_queue = uword_to_pointer (mp->app_event_queue_address,
408                                           svm_queue_t *);
409   em->state = STATE_ATTACHED;
410 }
411
412 static void
413 vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t *
414                                            mp)
415 {
416   if (mp->retval)
417     clib_warning ("detach returned with err: %d", mp->retval);
418 }
419
420 static void
421 stop_signal (int signum)
422 {
423   echo_main_t *um = &echo_main;
424
425   um->time_to_stop = 1;
426 }
427
428 static void
429 stats_signal (int signum)
430 {
431   echo_main_t *um = &echo_main;
432
433   um->time_to_print_stats = 1;
434 }
435
436 static clib_error_t *
437 setup_signal_handlers (void)
438 {
439   signal (SIGINT, stats_signal);
440   signal (SIGQUIT, stop_signal);
441   signal (SIGTERM, stop_signal);
442
443   return 0;
444 }
445
446 void
447 vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
448 {
449   clib_warning ("BUG");
450 }
451
452 int
453 connect_to_vpp (char *name)
454 {
455   echo_main_t *em = &echo_main;
456   api_main_t *am = &api_main;
457
458   if (em->use_sock_api)
459     {
460       if (vl_socket_client_connect ((char *) em->socket_name, name,
461                                     0 /* default rx, tx buffer */ ))
462         {
463           clib_warning ("socket connect failed");
464           return -1;
465         }
466
467       if (vl_socket_client_init_shm (0))
468         {
469           clib_warning ("init shm api failed");
470           return -1;
471         }
472     }
473   else
474     {
475       if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
476         {
477           clib_warning ("shmem connect failed");
478           return -1;
479         }
480     }
481   em->vl_input_queue = am->shmem_hdr->vl_input_queue;
482   em->my_client_index = am->my_client_index;
483   return 0;
484 }
485
486 void
487 disconnect_from_vpp (echo_main_t * em)
488 {
489   if (em->use_sock_api)
490     vl_socket_client_disconnect ();
491   else
492     vl_client_disconnect_from_vlib ();
493 }
494
495 static void
496 vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
497 {
498   svm_fifo_segment_create_args_t _a, *a = &_a;
499   int rv;
500
501   memset (a, 0, sizeof (*a));
502   a->segment_name = (char *) mp->segment_name;
503   a->segment_size = mp->segment_size;
504   /* Attach to the segment vpp created */
505   rv = svm_fifo_segment_attach (a);
506   if (rv)
507     {
508       clib_warning ("svm_fifo_segment_attach ('%s') failed",
509                     mp->segment_name);
510       return;
511     }
512   clib_warning ("Mapped new segment '%s' size %d", mp->segment_name,
513                 mp->segment_size);
514 }
515
516 static void
517 session_print_stats (echo_main_t * em, session_t * session)
518 {
519   f64 deltat;
520   u64 bytes;
521
522   deltat = clib_time_now (&em->clib_time) - session->start;
523   bytes = em->i_am_master ? session->bytes_received : em->bytes_to_send;
524   fformat (stdout, "Finished in %.6f\n", deltat);
525   fformat (stdout, "%.4f Gbit/second\n", (bytes * 8.0) / deltat / 1e9);
526 }
527
528 static void
529 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
530 {
531   echo_main_t *em = &echo_main;
532   session_t *session = 0;
533   vl_api_disconnect_session_reply_t *rmp;
534   uword *p;
535   int rv = 0;
536
537   p = hash_get (em->session_index_by_vpp_handles, mp->handle);
538
539   if (p)
540     {
541       session = pool_elt_at_index (em->sessions, p[0]);
542       hash_unset (em->session_index_by_vpp_handles, mp->handle);
543       pool_put (em->sessions, session);
544     }
545   else
546     {
547       clib_warning ("couldn't find session key %llx", mp->handle);
548       rv = -11;
549     }
550
551 //  em->time_to_stop = 1;
552
553   rmp = vl_msg_api_alloc (sizeof (*rmp));
554   memset (rmp, 0, sizeof (*rmp));
555
556   rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY);
557   rmp->retval = rv;
558   rmp->handle = mp->handle;
559   rmp->context = mp->context;
560   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & rmp);
561
562   if (session)
563     session_print_stats (em, session);
564 }
565
566 static void
567 vl_api_reset_session_t_handler (vl_api_reset_session_t * mp)
568 {
569   echo_main_t *em = &echo_main;
570   vl_api_reset_session_reply_t *rmp;
571   uword *p;
572   int rv = 0;
573
574   p = hash_get (em->session_index_by_vpp_handles, mp->handle);
575
576   if (p)
577     {
578       clib_warning ("got reset");
579       /* Cleanup later */
580       em->time_to_stop = 1;
581     }
582   else
583     {
584       clib_warning ("couldn't find session key %llx", mp->handle);
585       rv = -11;
586     }
587
588   rmp = vl_msg_api_alloc (sizeof (*rmp));
589   memset (rmp, 0, sizeof (*rmp));
590   rmp->_vl_msg_id = ntohs (VL_API_RESET_SESSION_REPLY);
591   rmp->retval = rv;
592   rmp->handle = mp->handle;
593   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & rmp);
594 }
595
596 void
597 client_handle_fifo_event_rx (echo_main_t * em, session_fifo_event_t * e)
598 {
599   svm_fifo_t *rx_fifo;
600   int n_read, bytes, i;
601
602   rx_fifo = e->fifo;
603
604   bytes = svm_fifo_max_dequeue (rx_fifo);
605   /* Allow enqueuing of new event */
606   svm_fifo_unset_event (rx_fifo);
607
608   /* Read the bytes */
609   do
610     {
611       n_read = svm_fifo_dequeue_nowait (rx_fifo,
612                                         clib_min (vec_len (em->rx_buf),
613                                                   bytes), em->rx_buf);
614       if (n_read > 0)
615         {
616           bytes -= n_read;
617           if (em->test_return_packets)
618             {
619               for (i = 0; i < n_read; i++)
620                 {
621                   if (em->rx_buf[i]
622                       != ((em->client_bytes_received + i) & 0xff))
623                     {
624                       clib_warning ("error at byte %lld, 0x%x not 0x%x",
625                                     em->client_bytes_received + i,
626                                     em->rx_buf[i],
627                                     ((em->client_bytes_received + i) & 0xff));
628                     }
629                 }
630             }
631           em->client_bytes_received += n_read;
632         }
633       else
634         {
635           if (n_read == -2)
636             {
637 //            clib_warning ("weird!");
638               break;
639             }
640         }
641
642     }
643   while (bytes > 0);
644 }
645
646 void
647 client_handle_event_queue (echo_main_t * em)
648 {
649   session_fifo_event_t _e, *e = &_e;;
650
651   svm_queue_sub (em->our_event_queue, (u8 *) e, SVM_Q_WAIT, 0);
652   switch (e->event_type)
653     {
654     case FIFO_EVENT_APP_RX:
655       client_handle_fifo_event_rx (em, e);
656       break;
657
658     case FIFO_EVENT_DISCONNECT:
659       return;
660
661     default:
662       clib_warning ("unknown event type %d", e->event_type);
663       break;
664     }
665 }
666
667 static void *
668 client_rx_thread_fn (void *arg)
669 {
670   session_fifo_event_t _e, *e = &_e;
671   echo_main_t *em = &echo_main;
672
673   em->client_bytes_received = 0;
674   while (1)
675     {
676       svm_queue_sub (em->our_event_queue, (u8 *) e, SVM_Q_WAIT, 0);
677       switch (e->event_type)
678         {
679         case FIFO_EVENT_APP_RX:
680           client_handle_fifo_event_rx (em, e);
681           break;
682
683         case FIFO_EVENT_DISCONNECT:
684           return 0;
685         default:
686           clib_warning ("unknown event type %d", e->event_type);
687           break;
688         }
689
690       if (PREDICT_FALSE (em->time_to_stop == 1))
691         break;
692     }
693   pthread_exit (0);
694 }
695
696
697 static void
698 vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp)
699 {
700   echo_main_t *em = &echo_main;
701   session_t *session;
702   u32 session_index;
703   svm_fifo_t *rx_fifo, *tx_fifo;
704   int rv;
705
706   if (mp->retval)
707     {
708       clib_warning ("connection failed with code: %U", format_api_error,
709                     clib_net_to_host_u32 (mp->retval));
710       em->state = STATE_FAILED;
711       return;
712     }
713   else
714     {
715       clib_warning ("connected with local ip %U port %d", format_ip46_address,
716                     mp->lcl_ip, mp->is_ip4,
717                     clib_net_to_host_u16 (mp->lcl_port));
718     }
719
720   em->vpp_event_queue =
721     uword_to_pointer (mp->vpp_event_queue_address, svm_queue_t *);
722
723   /*
724    * Setup session
725    */
726
727   pool_get (em->sessions, session);
728   session_index = session - em->sessions;
729
730   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
731   rx_fifo->client_session_index = session_index;
732   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
733   tx_fifo->client_session_index = session_index;
734
735   session->server_rx_fifo = rx_fifo;
736   session->server_tx_fifo = tx_fifo;
737   session->vpp_session_handle = mp->handle;
738   session->start = clib_time_now (&em->clib_time);
739
740   /* Save handle */
741   em->connected_session_index = session_index;
742   em->state = STATE_READY;
743
744   /* Add it to lookup table */
745   hash_set (em->session_index_by_vpp_handles, mp->handle, session_index);
746
747   /* Start RX thread */
748   rv = pthread_create (&em->client_rx_thread_handle,
749                        NULL /*attr */ , client_rx_thread_fn, 0);
750   if (rv)
751     {
752       clib_warning ("pthread_create returned %d", rv);
753       rv = VNET_API_ERROR_SYSCALL_ERROR_1;
754     }
755 }
756
757 static void
758 send_test_chunk (echo_main_t * em, svm_fifo_t * tx_fifo, int mypid, u32 bytes)
759 {
760   u8 *test_data = em->connect_test_data;
761   u64 bytes_sent = 0;
762   int test_buf_offset = 0;
763   u32 bytes_to_snd;
764   u32 queue_max_chunk = 128 << 10, actual_write;
765   session_fifo_event_t evt;
766   int rv;
767
768   bytes_to_snd = (bytes == 0) ? vec_len (test_data) : bytes;
769   if (bytes_to_snd > vec_len (test_data))
770     bytes_to_snd = vec_len (test_data);
771
772   while (bytes_to_snd > 0 && !em->time_to_stop)
773     {
774       actual_write = (bytes_to_snd > queue_max_chunk) ?
775         queue_max_chunk : bytes_to_snd;
776       rv = svm_fifo_enqueue_nowait (tx_fifo, actual_write,
777                                     test_data + test_buf_offset);
778
779       if (rv > 0)
780         {
781           bytes_to_snd -= rv;
782           test_buf_offset += rv;
783           bytes_sent += rv;
784
785           if (svm_fifo_set_event (tx_fifo))
786             {
787               /* Fabricate TX event, send to vpp */
788               evt.fifo = tx_fifo;
789               evt.event_type = FIFO_EVENT_APP_TX;
790
791               svm_queue_add (em->vpp_event_queue,
792                              (u8 *) & evt, 0 /* do wait for mutex */ );
793             }
794         }
795     }
796 }
797
798 void
799 client_send_data (echo_main_t * em)
800 {
801   u8 *test_data = em->connect_test_data;
802   int mypid = getpid ();
803   session_t *session;
804   svm_fifo_t *tx_fifo;
805   u32 n_iterations, leftover;
806   int i;
807
808   session = pool_elt_at_index (em->sessions, em->connected_session_index);
809   tx_fifo = session->server_tx_fifo;
810
811   ASSERT (vec_len (test_data) > 0);
812
813   vec_validate (em->rx_buf, vec_len (test_data) - 1);
814   n_iterations = em->bytes_to_send / vec_len (test_data);
815
816   for (i = 0; i < n_iterations; i++)
817     {
818       send_test_chunk (em, tx_fifo, mypid, 0);
819       if (em->time_to_stop)
820         break;
821     }
822
823   leftover = em->bytes_to_send % vec_len (test_data);
824   if (leftover)
825     send_test_chunk (em, tx_fifo, mypid, leftover);
826
827   if (!em->drop_packets)
828     {
829       f64 timeout = clib_time_now (&em->clib_time) + 10;
830
831       /* Wait for the outstanding packets */
832       while (em->client_bytes_received <
833              vec_len (test_data) * n_iterations + leftover)
834         {
835           if (clib_time_now (&em->clib_time) > timeout)
836             {
837               clib_warning ("timed out waiting for the missing packets");
838               break;
839             }
840         }
841     }
842   em->time_to_stop = 1;
843 }
844
845 void
846 client_send_connect (echo_main_t * em)
847 {
848   vl_api_connect_uri_t *cmp;
849   cmp = vl_msg_api_alloc (sizeof (*cmp));
850   memset (cmp, 0, sizeof (*cmp));
851
852   cmp->_vl_msg_id = ntohs (VL_API_CONNECT_URI);
853   cmp->client_index = em->my_client_index;
854   cmp->context = ntohl (0xfeedface);
855   memcpy (cmp->uri, em->connect_uri, vec_len (em->connect_uri));
856   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & cmp);
857 }
858
859 int
860 client_connect (echo_main_t * em)
861 {
862   client_send_connect (em);
863   if (wait_for_state_change (em, STATE_READY))
864     {
865       clib_warning ("Connect failed");
866       return -1;
867     }
868   return 0;
869 }
870
871 void
872 client_send_disconnect (echo_main_t * em)
873 {
874   session_t *connected_session;
875   vl_api_disconnect_session_t *dmp;
876   connected_session = pool_elt_at_index (em->sessions,
877                                          em->connected_session_index);
878   dmp = vl_msg_api_alloc (sizeof (*dmp));
879   memset (dmp, 0, sizeof (*dmp));
880   dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION);
881   dmp->client_index = em->my_client_index;
882   dmp->handle = connected_session->vpp_session_handle;
883   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & dmp);
884 }
885
886 int
887 client_disconnect (echo_main_t * em)
888 {
889   client_send_disconnect (em);
890   clib_warning ("Sent disconnect");
891   if (wait_for_state_change (em, STATE_START))
892     {
893       clib_warning ("Disconnect failed");
894       return -1;
895     }
896   return 0;
897 }
898
899 static void
900 client_run (echo_main_t * em)
901 {
902   int i;
903
904   if (application_attach (em))
905     return;
906
907   if (client_connect (em))
908     {
909       application_detach (em);
910       return;
911     }
912
913   /* Init test data */
914   vec_validate (em->connect_test_data, 128 * 1024 - 1);
915   for (i = 0; i < vec_len (em->connect_test_data); i++)
916     em->connect_test_data[i] = i & 0xff;
917
918   /* Start send */
919   client_send_data (em);
920
921   /* Disconnect and detach */
922   client_disconnect (em);
923   application_detach (em);
924 }
925
926 static void
927 vl_api_bind_uri_reply_t_handler (vl_api_bind_uri_reply_t * mp)
928 {
929   echo_main_t *em = &echo_main;
930
931   if (mp->retval)
932     {
933       clib_warning ("bind failed: %U", format_api_error,
934                     clib_net_to_host_u32 (mp->retval));
935       em->state = STATE_FAILED;
936       return;
937     }
938
939   em->state = STATE_READY;
940 }
941
942 static void
943 vl_api_unbind_uri_reply_t_handler (vl_api_unbind_uri_reply_t * mp)
944 {
945   echo_main_t *em = &echo_main;
946
947   if (mp->retval != 0)
948     clib_warning ("returned %d", ntohl (mp->retval));
949
950   em->state = STATE_START;
951 }
952
953 u8 *
954 format_ip4_address (u8 * s, va_list * args)
955 {
956   u8 *a = va_arg (*args, u8 *);
957   return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
958 }
959
960 u8 *
961 format_ip6_address (u8 * s, va_list * args)
962 {
963   ip6_address_t *a = va_arg (*args, ip6_address_t *);
964   u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
965
966   i_max_n_zero = ARRAY_LEN (a->as_u16);
967   max_n_zeros = 0;
968   i_first_zero = i_max_n_zero;
969   n_zeros = 0;
970   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
971     {
972       u32 is_zero = a->as_u16[i] == 0;
973       if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
974         {
975           i_first_zero = i;
976           n_zeros = 0;
977         }
978       n_zeros += is_zero;
979       if ((!is_zero && n_zeros > max_n_zeros)
980           || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
981         {
982           i_max_n_zero = i_first_zero;
983           max_n_zeros = n_zeros;
984           i_first_zero = ARRAY_LEN (a->as_u16);
985           n_zeros = 0;
986         }
987     }
988
989   last_double_colon = 0;
990   for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
991     {
992       if (i == i_max_n_zero && max_n_zeros > 1)
993         {
994           s = format (s, "::");
995           i += max_n_zeros - 1;
996           last_double_colon = 1;
997         }
998       else
999         {
1000           s = format (s, "%s%x",
1001                       (last_double_colon || i == 0) ? "" : ":",
1002                       clib_net_to_host_u16 (a->as_u16[i]));
1003           last_double_colon = 0;
1004         }
1005     }
1006
1007   return s;
1008 }
1009
1010 /* Format an IP46 address. */
1011 u8 *
1012 format_ip46_address (u8 * s, va_list * args)
1013 {
1014   ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
1015   ip46_type_t type = va_arg (*args, ip46_type_t);
1016   int is_ip4 = 1;
1017
1018   switch (type)
1019     {
1020     case IP46_TYPE_ANY:
1021       is_ip4 = ip46_address_is_ip4 (ip46);
1022       break;
1023     case IP46_TYPE_IP4:
1024       is_ip4 = 1;
1025       break;
1026     case IP46_TYPE_IP6:
1027       is_ip4 = 0;
1028       break;
1029     }
1030
1031   return is_ip4 ?
1032     format (s, "%U", format_ip4_address, &ip46->ip4) :
1033     format (s, "%U", format_ip6_address, &ip46->ip6);
1034 }
1035
1036 static void
1037 vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
1038 {
1039   echo_main_t *em = &echo_main;
1040   vl_api_accept_session_reply_t *rmp;
1041   svm_fifo_t *rx_fifo, *tx_fifo;
1042   session_t *session;
1043   static f64 start_time;
1044   u32 session_index;
1045   u8 *ip_str;
1046
1047   if (start_time == 0.0)
1048     start_time = clib_time_now (&em->clib_time);
1049
1050   ip_str = format (0, "%U", format_ip46_address, &mp->ip, mp->is_ip4);
1051   clib_warning ("Accepted session from: %s:%d", ip_str,
1052                 clib_net_to_host_u16 (mp->port));
1053   em->vpp_event_queue =
1054     uword_to_pointer (mp->vpp_event_queue_address, svm_queue_t *);
1055
1056   /* Allocate local session and set it up */
1057   pool_get (em->sessions, session);
1058   session_index = session - em->sessions;
1059
1060   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
1061   rx_fifo->client_session_index = session_index;
1062   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
1063   tx_fifo->client_session_index = session_index;
1064
1065   session->server_rx_fifo = rx_fifo;
1066   session->server_tx_fifo = tx_fifo;
1067
1068   /* Add it to lookup table */
1069   hash_set (em->session_index_by_vpp_handles, mp->handle, session_index);
1070
1071   em->state = STATE_READY;
1072
1073   /* Stats printing */
1074   if (pool_elts (em->sessions) && (pool_elts (em->sessions) % 20000) == 0)
1075     {
1076       f64 now = clib_time_now (&em->clib_time);
1077       fformat (stdout, "%d active sessions in %.2f seconds, %.2f/sec...\n",
1078                pool_elts (em->sessions), now - start_time,
1079                (f64) pool_elts (em->sessions) / (now - start_time));
1080     }
1081
1082   /*
1083    * Send accept reply to vpp
1084    */
1085   rmp = vl_msg_api_alloc (sizeof (*rmp));
1086   memset (rmp, 0, sizeof (*rmp));
1087   rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
1088   rmp->handle = mp->handle;
1089   rmp->context = mp->context;
1090   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & rmp);
1091
1092   session->bytes_received = 0;
1093   session->start = clib_time_now (&em->clib_time);
1094 }
1095
1096 void
1097 server_handle_fifo_event_rx (echo_main_t * em, session_fifo_event_t * e)
1098 {
1099   svm_fifo_t *rx_fifo, *tx_fifo;
1100   int n_read;
1101   session_fifo_event_t evt;
1102   svm_queue_t *q;
1103   session_t *session;
1104   int rv;
1105   u32 max_dequeue, offset, max_transfer, rx_buf_len;
1106
1107   rx_buf_len = vec_len (em->rx_buf);
1108   rx_fifo = e->fifo;
1109   session = &em->sessions[rx_fifo->client_session_index];
1110   tx_fifo = session->server_tx_fifo;
1111
1112   max_dequeue = svm_fifo_max_dequeue (rx_fifo);
1113   /* Allow enqueuing of a new event */
1114   svm_fifo_unset_event (rx_fifo);
1115
1116   if (PREDICT_FALSE (max_dequeue == 0))
1117     {
1118       return;
1119     }
1120
1121   /* Read the max_dequeue */
1122   do
1123     {
1124       max_transfer = clib_min (rx_buf_len, max_dequeue);
1125       n_read = svm_fifo_dequeue_nowait (rx_fifo, max_transfer, em->rx_buf);
1126       if (n_read > 0)
1127         {
1128           max_dequeue -= n_read;
1129           session->bytes_received += n_read;
1130         }
1131
1132       /* Reflect if a non-drop session */
1133       if (!em->drop_packets && n_read > 0)
1134         {
1135           offset = 0;
1136           do
1137             {
1138               rv = svm_fifo_enqueue_nowait (tx_fifo, n_read,
1139                                             &em->rx_buf[offset]);
1140               if (rv > 0)
1141                 {
1142                   n_read -= rv;
1143                   offset += rv;
1144                 }
1145             }
1146           while ((rv <= 0 || n_read > 0) && !em->time_to_stop);
1147
1148           /* If event wasn't set, add one */
1149           if (svm_fifo_set_event (tx_fifo))
1150             {
1151               /* Fabricate TX event, send to vpp */
1152               evt.fifo = tx_fifo;
1153               evt.event_type = FIFO_EVENT_APP_TX;
1154
1155               q = em->vpp_event_queue;
1156               svm_queue_add (q, (u8 *) & evt, 1 /* do wait for mutex */ );
1157             }
1158         }
1159     }
1160   while ((n_read < 0 || max_dequeue > 0) && !em->time_to_stop);
1161 }
1162
1163 void
1164 server_handle_event_queue (echo_main_t * em)
1165 {
1166   session_fifo_event_t _e, *e = &_e;
1167
1168   while (1)
1169     {
1170       svm_queue_sub (em->our_event_queue, (u8 *) e, SVM_Q_WAIT, 0);
1171       switch (e->event_type)
1172         {
1173         case FIFO_EVENT_APP_RX:
1174           server_handle_fifo_event_rx (em, e);
1175           break;
1176
1177         case FIFO_EVENT_DISCONNECT:
1178           return;
1179
1180         default:
1181           clib_warning ("unknown event type %d", e->event_type);
1182           break;
1183         }
1184       if (PREDICT_FALSE (em->time_to_stop == 1))
1185         break;
1186       if (PREDICT_FALSE (em->time_to_print_stats == 1))
1187         {
1188           em->time_to_print_stats = 0;
1189           fformat (stdout, "%d connections\n", pool_elts (em->sessions));
1190         }
1191     }
1192 }
1193
1194 void
1195 server_send_listen (echo_main_t * em)
1196 {
1197   vl_api_bind_uri_t *bmp;
1198   bmp = vl_msg_api_alloc (sizeof (*bmp));
1199   memset (bmp, 0, sizeof (*bmp));
1200
1201   bmp->_vl_msg_id = ntohs (VL_API_BIND_URI);
1202   bmp->client_index = em->my_client_index;
1203   bmp->context = ntohl (0xfeedface);
1204   memcpy (bmp->uri, em->uri, vec_len (em->uri));
1205   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & bmp);
1206 }
1207
1208 int
1209 server_listen (echo_main_t * em)
1210 {
1211   server_send_listen (em);
1212   if (wait_for_state_change (em, STATE_READY))
1213     {
1214       clib_warning ("timeout waiting for STATE_READY");
1215       return -1;
1216     }
1217   return 0;
1218 }
1219
1220 void
1221 server_send_unbind (echo_main_t * em)
1222 {
1223   vl_api_unbind_uri_t *ump;
1224
1225   ump = vl_msg_api_alloc (sizeof (*ump));
1226   memset (ump, 0, sizeof (*ump));
1227
1228   ump->_vl_msg_id = ntohs (VL_API_UNBIND_URI);
1229   ump->client_index = em->my_client_index;
1230   memcpy (ump->uri, em->uri, vec_len (em->uri));
1231   vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & ump);
1232 }
1233
1234 int
1235 server_unbind (echo_main_t * em)
1236 {
1237   server_send_unbind (em);
1238   if (wait_for_state_change (em, STATE_START))
1239     {
1240       clib_warning ("timeout waiting for STATE_START");
1241       return -1;
1242     }
1243   return 0;
1244 }
1245
1246 void
1247 server_run (echo_main_t * em)
1248 {
1249   session_t *session;
1250   int i;
1251
1252   /* $$$$ hack preallocation */
1253   for (i = 0; i < 200000; i++)
1254     {
1255       pool_get (em->sessions, session);
1256       memset (session, 0, sizeof (*session));
1257     }
1258   for (i = 0; i < 200000; i++)
1259     pool_put_index (em->sessions, i);
1260
1261   if (application_attach (em))
1262     return;
1263
1264   /* Bind to uri */
1265   if (server_listen (em))
1266     return;
1267
1268   /* Enter handle event loop */
1269   server_handle_event_queue (em);
1270
1271   /* Cleanup */
1272   server_send_unbind (em);
1273
1274   application_detach (em);
1275
1276   fformat (stdout, "Test complete...\n");
1277 }
1278
1279 static void
1280 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
1281                                            mp)
1282 {
1283   echo_main_t *em = &echo_main;
1284   session_t *session;
1285
1286   if (mp->retval)
1287     {
1288       clib_warning ("vpp complained about disconnect: %d",
1289                     ntohl (mp->retval));
1290     }
1291
1292   em->state = STATE_START;
1293   session = pool_elt_at_index (em->sessions, em->connected_session_index);
1294   if (session)
1295     session_print_stats (em, session);
1296 }
1297
1298 static void
1299   vl_api_application_tls_cert_add_reply_t_handler
1300   (vl_api_application_tls_cert_add_reply_t * mp)
1301 {
1302   if (mp->retval)
1303     clib_warning ("failed to add tls cert");
1304 }
1305
1306 static void
1307   vl_api_application_tls_key_add_reply_t_handler
1308   (vl_api_application_tls_key_add_reply_t * mp)
1309 {
1310   if (mp->retval)
1311     clib_warning ("failed to add tls key");
1312 }
1313
1314 #define foreach_tcp_echo_msg                                            \
1315 _(BIND_URI_REPLY, bind_uri_reply)                                       \
1316 _(UNBIND_URI_REPLY, unbind_uri_reply)                                   \
1317 _(ACCEPT_SESSION, accept_session)                                       \
1318 _(CONNECT_SESSION_REPLY, connect_session_reply)                         \
1319 _(DISCONNECT_SESSION, disconnect_session)                               \
1320 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply)                   \
1321 _(RESET_SESSION, reset_session)                                         \
1322 _(APPLICATION_ATTACH_REPLY, application_attach_reply)                   \
1323 _(APPLICATION_DETACH_REPLY, application_detach_reply)                   \
1324 _(MAP_ANOTHER_SEGMENT, map_another_segment)                             \
1325 _(APPLICATION_TLS_CERT_ADD_REPLY, application_tls_cert_add_reply)       \
1326 _(APPLICATION_TLS_KEY_ADD_REPLY, application_tls_key_add_reply)         \
1327
1328 void
1329 tcp_echo_api_hookup (echo_main_t * em)
1330 {
1331 #define _(N,n)                                                  \
1332     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1333                            vl_api_##n##_t_handler,              \
1334                            vl_noop_handler,                     \
1335                            vl_api_##n##_t_endian,               \
1336                            vl_api_##n##_t_print,                \
1337                            sizeof(vl_api_##n##_t), 1);
1338   foreach_tcp_echo_msg;
1339 #undef _
1340 }
1341
1342 int
1343 main (int argc, char **argv)
1344 {
1345   int i_am_master = 1, drop_packets = 0, test_return_packets = 0;
1346   echo_main_t *em = &echo_main;
1347   unformat_input_t _argv, *a = &_argv;
1348   u8 *chroot_prefix;
1349   u8 *heap, *uri = 0;
1350   u8 *bind_uri = (u8 *) "tcp://0.0.0.0/1234";
1351   u8 *connect_uri = (u8 *) "tcp://6.0.1.2/1234";
1352   u64 bytes_to_send = 64 << 10, mbytes;
1353   char *app_name;
1354   u32 tmp;
1355   mheap_t *h;
1356
1357   clib_mem_init (0, 256 << 20);
1358
1359   heap = clib_mem_get_per_cpu_heap ();
1360   h = mheap_header (heap);
1361
1362   /* make the main heap thread-safe */
1363   h->flags |= MHEAP_FLAG_THREAD_SAFE;
1364
1365   vec_validate (em->rx_buf, 128 << 10);
1366
1367   em->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
1368
1369   em->my_pid = getpid ();
1370   em->configured_segment_size = 1 << 20;
1371   em->socket_name = 0;
1372   em->use_sock_api = 1;
1373
1374   clib_time_init (&em->clib_time);
1375   init_error_string_table (em);
1376   svm_fifo_segment_main_init (0x200000000ULL, 20);
1377   unformat_init_command_line (a, argv);
1378
1379   while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
1380     {
1381       if (unformat (a, "chroot prefix %s", &chroot_prefix))
1382         {
1383           vl_set_memory_root_path ((char *) chroot_prefix);
1384         }
1385       else if (unformat (a, "uri %s", &uri))
1386         ;
1387       else if (unformat (a, "segment-size %dM", &tmp))
1388         em->configured_segment_size = tmp << 20;
1389       else if (unformat (a, "segment-size %dG", &tmp))
1390         em->configured_segment_size = tmp << 30;
1391       else if (unformat (a, "master"))
1392         i_am_master = 1;
1393       else if (unformat (a, "slave"))
1394         i_am_master = 0;
1395       else if (unformat (a, "drop"))
1396         drop_packets = 1;
1397       else if (unformat (a, "test"))
1398         test_return_packets = 1;
1399       else if (unformat (a, "mbytes %lld", &mbytes))
1400         {
1401           bytes_to_send = mbytes << 20;
1402         }
1403       else if (unformat (a, "gbytes %lld", &mbytes))
1404         {
1405           bytes_to_send = mbytes << 30;
1406         }
1407       else if (unformat (a, "socket-name %s", &em->socket_name))
1408         ;
1409       else if (unformat (a, "use-svm-api"))
1410         em->use_sock_api = 0;
1411       else
1412         {
1413           fformat (stderr, "%s: usage [master|slave]\n");
1414           exit (1);
1415         }
1416     }
1417
1418   if (!em->socket_name)
1419     em->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
1420
1421   if (uri)
1422     {
1423       em->uri = format (0, "%s%c", uri, 0);
1424       em->connect_uri = format (0, "%s%c", uri, 0);
1425     }
1426   else
1427     {
1428       em->uri = format (0, "%s%c", bind_uri, 0);
1429       em->connect_uri = format (0, "%s%c", connect_uri, 0);
1430     }
1431
1432   em->i_am_master = i_am_master;
1433   em->segment_main = &svm_fifo_segment_main;
1434   em->drop_packets = drop_packets;
1435   em->test_return_packets = test_return_packets;
1436   em->bytes_to_send = bytes_to_send;
1437   em->time_to_stop = 0;
1438
1439   setup_signal_handlers ();
1440   tcp_echo_api_hookup (em);
1441
1442   app_name = i_am_master ? "tcp_echo_server" : "tcp_echo_client";
1443   if (connect_to_vpp (app_name) < 0)
1444     {
1445       svm_region_exit ();
1446       fformat (stderr, "Couldn't connect to vpe, exiting...\n");
1447       exit (1);
1448     }
1449
1450   if (i_am_master == 0)
1451     client_run (em);
1452   else
1453     server_run (em);
1454
1455   disconnect_from_vpp (em);
1456   exit (0);
1457 }
1458
1459 /*
1460  * fd.io coding-style-patch-verification: ON
1461  *
1462  * Local Variables:
1463  * eval: (c-set-style "gnu")
1464  * End:
1465  */