vcl: support for eventfd mq signaling
[vpp.git] / src / vlibmemory / socket_api.c
1 /*
2  *------------------------------------------------------------------
3  * socksvr_vlib.c
4  *
5  * Copyright (c) 2009 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <sys/ioctl.h>
24 #include <fcntl.h>
25 #include <sys/stat.h>
26
27 #include <vppinfra/byte_order.h>
28 #include <svm/ssvm.h>
29 #include <vlibmemory/api.h>
30
31 #include <vlibmemory/vl_memory_msg_enum.h>
32
33 #define vl_typedefs             /* define message structures */
34 #include <vlibmemory/vl_memory_api_h.h>
35 #undef vl_typedefs
36
37 /* instantiate all the print functions we know about */
38 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
39 #define vl_printfun
40 #include <vlibmemory/vl_memory_api_h.h>
41 #undef vl_printfun
42
43 /* instantiate all the endian swap functions we know about */
44 #define vl_endianfun
45 #include <vlibmemory/vl_memory_api_h.h>
46 #undef vl_endianfun
47
48 socket_main_t socket_main;
49
50 void
51 vl_sock_api_dump_clients (vlib_main_t * vm, api_main_t * am)
52 {
53   vl_api_registration_t *reg;
54   socket_main_t *sm = &socket_main;
55   clib_file_t *f;
56
57   /*
58    * Must have at least one active client, not counting the
59    * REGISTRATION_TYPE_SOCKET_LISTEN bind/accept socket
60    */
61   if (pool_elts (sm->registration_pool) < 2)
62     return;
63
64   vlib_cli_output (vm, "Socket clients");
65   vlib_cli_output (vm, "%20s %8s", "Name", "Fildesc");
66     /* *INDENT-OFF* */
67     pool_foreach (reg, sm->registration_pool,
68     ({
69         if (reg->registration_type == REGISTRATION_TYPE_SOCKET_SERVER) {
70             f = vl_api_registration_file (reg);
71             vlib_cli_output (vm, "%20s %8d", reg->name, f->file_descriptor);
72         }
73     }));
74 /* *INDENT-ON* */
75 }
76
77 void
78 vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
79 {
80 #if CLIB_DEBUG > 1
81   u32 output_length;
82 #endif
83   socket_main_t *sm = &socket_main;
84   u16 msg_id = ntohs (*(u16 *) elem);
85   api_main_t *am = &api_main;
86   msgbuf_t *mb = (msgbuf_t *) (elem - offsetof (msgbuf_t, data));
87   vl_api_registration_t *sock_rp;
88   clib_file_t *cf;
89
90   cf = vl_api_registration_file (rp);
91   ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
92
93   if (msg_id >= vec_len (am->api_trace_cfg))
94     {
95       clib_warning ("id out of range: %d", msg_id);
96       vl_msg_api_free ((void *) elem);
97       return;
98     }
99
100   sock_rp = pool_elt_at_index (sm->registration_pool,
101                                rp->vl_api_registration_pool_index);
102   ASSERT (sock_rp);
103
104   /* Add the msgbuf_t to the output vector */
105   vl_socket_add_pending_output_no_flush (cf, sock_rp, (u8 *) mb,
106                                          sizeof (*mb));
107   /* Send the message */
108   vl_socket_add_pending_output (cf, sock_rp, elem, ntohl (mb->data_len));
109
110 #if CLIB_DEBUG > 1
111   output_length = sizeof (*mb) + ntohl (mb->data_len);
112   clib_warning ("wrote %u bytes to fd %d", output_length,
113                 cf->file_descriptor);
114 #endif
115
116   vl_msg_api_free ((void *) elem);
117 }
118
119 void
120 vl_socket_free_registration_index (u32 pool_index)
121 {
122   int i;
123   vl_api_registration_t *rp;
124   if (pool_is_free_index (socket_main.registration_pool, pool_index))
125     {
126       clib_warning ("main pool index %d already free", pool_index);
127       return;
128     }
129   rp = pool_elt_at_index (socket_main.registration_pool, pool_index);
130
131   ASSERT (rp->registration_type != REGISTRATION_TYPE_FREE);
132   for (i = 0; i < vec_len (rp->additional_fds_to_close); i++)
133     if (close (rp->additional_fds_to_close[i]) < 0)
134       clib_unix_warning ("close");
135   vec_free (rp->additional_fds_to_close);
136   vec_free (rp->name);
137   vec_free (rp->unprocessed_input);
138   vec_free (rp->output_vector);
139   rp->registration_type = REGISTRATION_TYPE_FREE;
140   pool_put (socket_main.registration_pool, rp);
141 }
142
143 void
144 vl_socket_process_api_msg (clib_file_t * uf, vl_api_registration_t * rp,
145                            i8 * input_v)
146 {
147   msgbuf_t *mbp = (msgbuf_t *) input_v;
148
149   u8 *the_msg = (u8 *) (mbp->data);
150   socket_main.current_uf = uf;
151   socket_main.current_rp = rp;
152   vl_msg_api_socket_handler (the_msg);
153   socket_main.current_uf = 0;
154   socket_main.current_rp = 0;
155 }
156
157 clib_error_t *
158 vl_socket_read_ready (clib_file_t * uf)
159 {
160   clib_file_main_t *fm = &file_main;
161   vlib_main_t *vm = vlib_get_main ();
162   vl_api_registration_t *rp;
163   int n;
164   i8 *msg_buffer = 0;
165   u8 *data_for_process;
166   u32 msg_len;
167   u32 save_input_buffer_length = vec_len (socket_main.input_buffer);
168   vl_socket_args_for_process_t *a;
169   msgbuf_t *mbp;
170   int mbp_set = 0;
171
172   rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
173
174   n = read (uf->file_descriptor, socket_main.input_buffer,
175             vec_len (socket_main.input_buffer));
176
177   if (n <= 0 && errno != EAGAIN)
178     {
179       clib_file_del (fm, uf);
180
181       if (!pool_is_free (socket_main.registration_pool, rp))
182         {
183           u32 index = rp - socket_main.registration_pool;
184           vl_socket_free_registration_index (index);
185         }
186       else
187         {
188           clib_warning ("client index %d already free?",
189                         rp->vl_api_registration_pool_index);
190         }
191       return 0;
192     }
193
194   _vec_len (socket_main.input_buffer) = n;
195
196   /*
197    * Look for bugs here. This code is tricky because
198    * data read from a stream socket does not honor message
199    * boundaries. In the case of a long message (>4K bytes)
200    * we have to do (at least) 2 reads, etc.
201    */
202   do
203     {
204       if (vec_len (rp->unprocessed_input))
205         {
206           vec_append (rp->unprocessed_input, socket_main.input_buffer);
207           msg_buffer = rp->unprocessed_input;
208         }
209       else
210         {
211           msg_buffer = socket_main.input_buffer;
212           mbp_set = 0;
213         }
214
215       if (mbp_set == 0)
216         {
217           /* Any chance that we have a complete message? */
218           if (vec_len (msg_buffer) <= sizeof (msgbuf_t))
219             goto save_and_split;
220
221           mbp = (msgbuf_t *) msg_buffer;
222           msg_len = ntohl (mbp->data_len);
223           mbp_set = 1;
224         }
225
226       /* We don't have the entire message yet. */
227       if (mbp_set == 0
228           || (msg_len + sizeof (msgbuf_t)) > vec_len (msg_buffer))
229         {
230         save_and_split:
231           /* if we were using the input buffer save the fragment */
232           if (msg_buffer == socket_main.input_buffer)
233             {
234               ASSERT (vec_len (rp->unprocessed_input) == 0);
235               vec_validate (rp->unprocessed_input, vec_len (msg_buffer) - 1);
236               clib_memcpy (rp->unprocessed_input, msg_buffer,
237                            vec_len (msg_buffer));
238               _vec_len (rp->unprocessed_input) = vec_len (msg_buffer);
239             }
240           _vec_len (socket_main.input_buffer) = save_input_buffer_length;
241           return 0;
242         }
243
244       data_for_process = (u8 *) vec_dup (msg_buffer);
245       _vec_len (data_for_process) = (msg_len + sizeof (msgbuf_t));
246       pool_get (socket_main.process_args, a);
247       a->clib_file = uf;
248       a->regp = rp;
249       a->data = data_for_process;
250
251       vlib_process_signal_event (vm, vl_api_clnt_node.index,
252                                  SOCKET_READ_EVENT,
253                                  a - socket_main.process_args);
254       if (n > (msg_len + sizeof (*mbp)))
255         vec_delete (msg_buffer, msg_len + sizeof (*mbp), 0);
256       else
257         _vec_len (msg_buffer) = 0;
258       n -= msg_len + sizeof (msgbuf_t);
259       msg_len = 0;
260       mbp_set = 0;
261     }
262   while (n > 0);
263
264   _vec_len (socket_main.input_buffer) = save_input_buffer_length;
265
266   return 0;
267 }
268
269 void
270 vl_socket_add_pending_output (clib_file_t * uf,
271                               vl_api_registration_t * rp,
272                               u8 * buffer, uword buffer_bytes)
273 {
274   clib_file_main_t *fm = &file_main;
275
276   vec_add (rp->output_vector, buffer, buffer_bytes);
277   if (vec_len (rp->output_vector) > 0)
278     {
279       int skip_update = 0 != (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE);
280       uf->flags |= UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
281       if (!skip_update)
282         fm->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
283     }
284 }
285
286 void
287 vl_socket_add_pending_output_no_flush (clib_file_t * uf,
288                                        vl_api_registration_t * rp,
289                                        u8 * buffer, uword buffer_bytes)
290 {
291   vec_add (rp->output_vector, buffer, buffer_bytes);
292 }
293
294 static void
295 socket_del_pending_output (clib_file_t * uf,
296                            vl_api_registration_t * rp, uword n_bytes)
297 {
298   clib_file_main_t *fm = &file_main;
299
300   vec_delete (rp->output_vector, n_bytes, 0);
301   if (vec_len (rp->output_vector) <= 0)
302     {
303       int skip_update = 0 == (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE);
304       uf->flags &= ~UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
305       if (!skip_update)
306         fm->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
307     }
308 }
309
310 clib_error_t *
311 vl_socket_write_ready (clib_file_t * uf)
312 {
313   clib_file_main_t *fm = &file_main;
314   vl_api_registration_t *rp;
315   int n;
316
317   rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
318
319   /* Flush output vector. */
320   n = write (uf->file_descriptor,
321              rp->output_vector, vec_len (rp->output_vector));
322   if (n < 0)
323     {
324 #if DEBUG > 2
325       clib_warning ("write error, close the file...\n");
326 #endif
327       clib_file_del (fm, uf);
328
329       vl_socket_free_registration_index (rp - socket_main.registration_pool);
330       return 0;
331     }
332
333   else if (n > 0)
334     socket_del_pending_output (uf, rp, n);
335
336   return 0;
337 }
338
339 clib_error_t *
340 vl_socket_error_ready (clib_file_t * uf)
341 {
342   vl_api_registration_t *rp;
343   clib_file_main_t *fm = &file_main;
344
345   rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
346   clib_file_del (fm, uf);
347   vl_socket_free_registration_index (rp - socket_main.registration_pool);
348
349   return 0;
350 }
351
352 void
353 socksvr_file_add (clib_file_main_t * fm, int fd)
354 {
355   vl_api_registration_t *rp;
356   clib_file_t template = { 0 };
357
358   pool_get (socket_main.registration_pool, rp);
359   memset (rp, 0, sizeof (*rp));
360
361   template.read_function = vl_socket_read_ready;
362   template.write_function = vl_socket_write_ready;
363   template.error_function = vl_socket_error_ready;
364   template.file_descriptor = fd;
365   template.private_data = rp - socket_main.registration_pool;
366
367   rp->registration_type = REGISTRATION_TYPE_SOCKET_SERVER;
368   rp->vl_api_registration_pool_index = rp - socket_main.registration_pool;
369   rp->clib_file_index = clib_file_add (fm, &template);
370 }
371
372 static clib_error_t *
373 socksvr_accept_ready (clib_file_t * uf)
374 {
375   clib_file_main_t *fm = &file_main;
376   socket_main_t *sm = &socket_main;
377   clib_socket_t *sock = &sm->socksvr_listen_socket;
378   clib_socket_t client;
379   clib_error_t *error;
380
381   error = clib_socket_accept (sock, &client);
382   if (error)
383     return error;
384
385   socksvr_file_add (fm, client.fd);
386   return 0;
387 }
388
389 static clib_error_t *
390 socksvr_bogus_write (clib_file_t * uf)
391 {
392   clib_warning ("why am I here?");
393   return 0;
394 }
395
396 /*
397  * vl_api_sockclnt_create_t_handler
398  */
399 void
400 vl_api_sockclnt_create_t_handler (vl_api_sockclnt_create_t * mp)
401 {
402   vl_api_registration_t *regp;
403   vl_api_sockclnt_create_reply_t *rp;
404   int rv = 0;
405
406   regp = socket_main.current_rp;
407
408   ASSERT (regp->registration_type == REGISTRATION_TYPE_SOCKET_SERVER);
409
410   regp->name = format (0, "%s%c", mp->name, 0);
411
412   rp = vl_msg_api_alloc (sizeof (*rp));
413   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE_REPLY);
414   rp->handle = (uword) regp;
415   rp->index = (uword) regp->vl_api_registration_pool_index;
416   rp->context = mp->context;
417   rp->response = htonl (rv);
418
419   vl_api_send_msg (regp, (u8 *) rp);
420 }
421
422 /*
423  * vl_api_sockclnt_delete_t_handler
424  */
425 void
426 vl_api_sockclnt_delete_t_handler (vl_api_sockclnt_delete_t * mp)
427 {
428   vl_api_registration_t *regp;
429   vl_api_sockclnt_delete_reply_t *rp;
430
431   if (!pool_is_free_index (socket_main.registration_pool, mp->index))
432     {
433       regp = pool_elt_at_index (socket_main.registration_pool, mp->index);
434
435       rp = vl_msg_api_alloc (sizeof (*rp));
436       rp->_vl_msg_id = htons (VL_API_SOCKCLNT_DELETE_REPLY);
437       rp->handle = mp->handle;
438       rp->response = htonl (1);
439
440       vl_api_send_msg (regp, (u8 *) rp);
441
442       vl_api_registration_del_file (regp);
443       vl_socket_free_registration_index (mp->index);
444     }
445   else
446     {
447       clib_warning ("unknown client ID %d", mp->index);
448     }
449 }
450
451 clib_error_t *
452 vl_sock_api_send_fd_msg (int socket_fd, int fds[], int n_fds)
453 {
454   struct msghdr mh = { 0 };
455   struct iovec iov[1];
456   char ctl[CMSG_SPACE (sizeof (int) * n_fds)];
457   struct cmsghdr *cmsg;
458   char *msg = "fdmsg";
459   int rv;
460
461   iov[0].iov_base = msg;
462   iov[0].iov_len = strlen (msg);
463   mh.msg_iov = iov;
464   mh.msg_iovlen = 1;
465
466   memset (&ctl, 0, sizeof (ctl));
467   mh.msg_control = ctl;
468   mh.msg_controllen = sizeof (ctl);
469   cmsg = CMSG_FIRSTHDR (&mh);
470   cmsg->cmsg_len = CMSG_LEN (sizeof (int) * n_fds);
471   cmsg->cmsg_level = SOL_SOCKET;
472   cmsg->cmsg_type = SCM_RIGHTS;
473   clib_memcpy (CMSG_DATA (cmsg), fds, sizeof (int) * n_fds);
474
475   rv = sendmsg (socket_fd, &mh, 0);
476   if (rv < 0)
477     return clib_error_return_unix (0, "sendmsg");
478   return 0;
479 }
480
481 vl_api_shm_elem_config_t *
482 vl_api_make_shm_config (vl_api_sock_init_shm_t * mp)
483 {
484   vl_api_shm_elem_config_t *config = 0, *c;
485   u64 cfg;
486   int i;
487
488   if (!mp->nitems)
489     {
490       vec_validate (config, 6);
491       config[0].type = VL_API_VLIB_RING;
492       config[0].size = 256;
493       config[0].count = 32;
494
495       config[1].type = VL_API_VLIB_RING;
496       config[1].size = 1024;
497       config[1].count = 16;
498
499       config[2].type = VL_API_VLIB_RING;
500       config[2].size = 4096;
501       config[2].count = 2;
502
503       config[3].type = VL_API_CLIENT_RING;
504       config[3].size = 256;
505       config[3].count = 32;
506
507       config[4].type = VL_API_CLIENT_RING;
508       config[4].size = 1024;
509       config[4].count = 16;
510
511       config[5].type = VL_API_CLIENT_RING;
512       config[5].size = 4096;
513       config[5].count = 2;
514
515       config[6].type = VL_API_QUEUE;
516       config[6].count = 128;
517       config[6].size = sizeof (uword);
518     }
519   else
520     {
521       vec_validate (config, mp->nitems - 1);
522       for (i = 0; i < mp->nitems; i++)
523         {
524           cfg = mp->configs[i];
525           /* Pretty much a hack but it avoids defining our own api type
526            * in memclnt.api */
527           c = (vl_api_shm_elem_config_t *) & cfg;
528           config[i].type = c->type;
529           config[i].count = c->count;
530           config[i].size = c->size;
531         }
532     }
533   return config;
534 }
535
536 /*
537  * Bootstrap shm api using the socket api
538  */
539 void
540 vl_api_sock_init_shm_t_handler (vl_api_sock_init_shm_t * mp)
541 {
542   vl_api_sock_init_shm_reply_t *rmp;
543   ssvm_private_t _memfd_private, *memfd = &_memfd_private;
544   svm_map_region_args_t _args, *a = &_args;
545   vl_api_registration_t *regp;
546   api_main_t *am = &api_main;
547   svm_region_t *vlib_rp;
548   clib_file_t *cf;
549   vl_api_shm_elem_config_t *config = 0;
550   vl_shmem_hdr_t *shmem_hdr;
551   int rv;
552
553   regp = vl_api_client_index_to_registration (mp->client_index);
554   if (regp == 0)
555     {
556       clib_warning ("API client disconnected");
557       return;
558     }
559   if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
560     {
561       rv = -31;                 /* VNET_API_ERROR_INVALID_REGISTRATION */
562       goto reply;
563     }
564
565   /*
566    * Set up a memfd segment of the requested size wherein the
567    * shmem data structures will be initialized
568    */
569   memset (memfd, 0, sizeof (*memfd));
570   memfd->ssvm_size = mp->requested_size;
571   memfd->requested_va = 0ULL;
572   memfd->i_am_master = 1;
573   memfd->name = format (0, "%s%c", regp->name, 0);
574
575   if ((rv = ssvm_master_init_memfd (memfd)))
576     goto reply;
577
578   /* Remember to close this fd when the socket connection goes away */
579   vec_add1 (regp->additional_fds_to_close, memfd->fd);
580
581   /*
582    * Create a plausible svm_region in the memfd backed segment
583    */
584   memset (a, 0, sizeof (*a));
585   a->baseva = memfd->sh->ssvm_va + MMAP_PAGESIZE;
586   a->size = memfd->ssvm_size - MMAP_PAGESIZE;
587   /* $$$$ might want a different config parameter */
588   a->pvt_heap_size = am->api_pvt_heap_size;
589   a->flags = SVM_FLAGS_MHEAP;
590   svm_region_init_mapped_region (a, (svm_region_t *) a->baseva);
591
592   /*
593    * Part deux, initialize the svm_region_t shared-memory header
594    * api allocation rings, and so on.
595    */
596   config = vl_api_make_shm_config (mp);
597   vlib_rp = (svm_region_t *) a->baseva;
598   vl_init_shmem (vlib_rp, config, 1 /* is_vlib (dont-care) */ ,
599                  1 /* is_private */ );
600
601   /* Remember who created this. Needs to be post vl_init_shmem */
602   shmem_hdr = (vl_shmem_hdr_t *) vlib_rp->user_ctx;
603   shmem_hdr->clib_file_index = vl_api_registration_file_index (regp);
604
605   vec_add1 (am->vlib_private_rps, vlib_rp);
606   memfd->sh->ready = 1;
607   vec_free (config);
608
609   /* Recompute the set of input queues to poll in memclnt_process */
610   vec_reset_length (vl_api_queue_cursizes);
611
612 reply:
613
614   rmp = vl_msg_api_alloc (sizeof (*rmp));
615   rmp->_vl_msg_id = htons (VL_API_SOCK_INIT_SHM_REPLY);
616   rmp->context = mp->context;
617   rmp->retval = htonl (rv);
618
619   vl_api_send_msg (regp, (u8 *) rmp);
620
621   if (rv != 0)
622     return;
623
624   /*
625    * We need the reply message to make it out the back door
626    * before we send the magic fd message so force a flush
627    */
628   cf = vl_api_registration_file (regp);
629   cf->write_function (cf);
630
631   /* Send the magic "here's your sign (aka fd)" socket message */
632   vl_sock_api_send_fd_msg (cf->file_descriptor, &memfd->fd, 1);
633 }
634
635 #define foreach_vlib_api_msg                            \
636 _(SOCKCLNT_CREATE, sockclnt_create)                     \
637 _(SOCKCLNT_DELETE, sockclnt_delete)                     \
638 _(SOCK_INIT_SHM, sock_init_shm)
639
640 clib_error_t *
641 vl_sock_api_init (vlib_main_t * vm)
642 {
643   clib_file_main_t *fm = &file_main;
644   clib_file_t template = { 0 };
645   vl_api_registration_t *rp;
646   socket_main_t *sm = &socket_main;
647   clib_socket_t *sock = &sm->socksvr_listen_socket;
648   clib_error_t *error;
649
650   /* If not explicitly configured, do not bind/enable, etc. */
651   if (sm->socket_name == 0)
652     return 0;
653
654 #define _(N,n)                                                  \
655     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
656                            vl_api_##n##_t_handler,              \
657                            vl_noop_handler,                     \
658                            vl_api_##n##_t_endian,               \
659                            vl_api_##n##_t_print,                \
660                            sizeof(vl_api_##n##_t), 1);
661   foreach_vlib_api_msg;
662 #undef _
663
664   vec_resize (sm->input_buffer, 4096);
665
666   sock->config = (char *) sm->socket_name;
667
668   /* mkdir of file socket, only under /run  */
669   if (strncmp (sock->config, "/run", 4) == 0)
670     {
671       u8 *tmp = format (0, "%s", sock->config);
672       int i = vec_len (tmp);
673       while (i && tmp[--i] != '/')
674         ;
675
676       tmp[i] = 0;
677
678       if (i)
679         vlib_unix_recursive_mkdir ((char *) tmp);
680       vec_free (tmp);
681     }
682
683   sock->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_SEQPACKET |
684     CLIB_SOCKET_F_ALLOW_GROUP_WRITE;
685   error = clib_socket_init (sock);
686   if (error)
687     return error;
688
689   pool_get (sm->registration_pool, rp);
690   memset (rp, 0, sizeof (*rp));
691
692   rp->registration_type = REGISTRATION_TYPE_SOCKET_LISTEN;
693
694   template.read_function = socksvr_accept_ready;
695   template.write_function = socksvr_bogus_write;
696   template.file_descriptor = sock->fd;
697   template.private_data = rp - sm->registration_pool;
698
699   rp->clib_file_index = clib_file_add (fm, &template);
700   return 0;
701 }
702
703 static clib_error_t *
704 socket_exit (vlib_main_t * vm)
705 {
706   socket_main_t *sm = &socket_main;
707   vl_api_registration_t *rp;
708
709   /* Defensive driving in case something wipes out early */
710   if (sm->registration_pool)
711     {
712       u32 index;
713         /* *INDENT-OFF* */
714         pool_foreach (rp, sm->registration_pool, ({
715           vl_api_registration_del_file (rp);
716           index = rp->vl_api_registration_pool_index;
717           vl_socket_free_registration_index (index);
718         }));
719 /* *INDENT-ON* */
720     }
721
722   return 0;
723 }
724
725 VLIB_MAIN_LOOP_EXIT_FUNCTION (socket_exit);
726
727 static clib_error_t *
728 socksvr_config (vlib_main_t * vm, unformat_input_t * input)
729 {
730   socket_main_t *sm = &socket_main;
731
732   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
733     {
734       if (unformat (input, "socket-name %s", &sm->socket_name))
735         ;
736       else if (unformat (input, "default"))
737         {
738           sm->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
739         }
740       else
741         {
742           return clib_error_return (0, "unknown input '%U'",
743                                     format_unformat_error, input);
744         }
745     }
746   return 0;
747 }
748
749 VLIB_CONFIG_FUNCTION (socksvr_config, "socksvr");
750
751 clib_error_t *
752 vlibsocket_init (vlib_main_t * vm)
753 {
754   return 0;
755 }
756
757 VLIB_INIT_FUNCTION (vlibsocket_init);
758
759 /*
760  * fd.io coding-style-patch-verification: ON
761  *
762  * Local Variables:
763  * eval: (c-set-style "gnu")
764  * End:
765  */