api: fix crash when cf removed
[vpp.git] / src / vlibmemory / socket_api.c
1 /*
2  *------------------------------------------------------------------
3  * socket_api.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 #define SOCK_API_REG_HANDLE_BIT (1<<31)
51
52 static u32
53 sock_api_registration_handle (vl_api_registration_t * regp)
54 {
55   ASSERT (regp->vl_api_registration_pool_index < SOCK_API_REG_HANDLE_BIT);
56   return regp->vl_api_registration_pool_index | SOCK_API_REG_HANDLE_BIT;
57 }
58
59 static u32
60 socket_api_registration_handle_to_index (u32 reg_index)
61 {
62   return (reg_index & ~SOCK_API_REG_HANDLE_BIT);
63 }
64
65 u8
66 vl_socket_api_registration_handle_is_valid (u32 reg_handle)
67 {
68   return ((reg_handle & SOCK_API_REG_HANDLE_BIT) != 0);
69 }
70
71 void
72 vl_sock_api_dump_clients (vlib_main_t * vm, api_main_t * am)
73 {
74   vl_api_registration_t *reg;
75   socket_main_t *sm = &socket_main;
76   clib_file_t *f;
77
78   /*
79    * Must have at least one active client, not counting the
80    * REGISTRATION_TYPE_SOCKET_LISTEN bind/accept socket
81    */
82   if (pool_elts (sm->registration_pool) < 2)
83     return;
84
85   vlib_cli_output (vm, "Socket clients");
86   vlib_cli_output (vm, "%20s %8s", "Name", "Fildesc");
87     /* *INDENT-OFF* */
88     pool_foreach (reg, sm->registration_pool)
89      {
90         if (reg->registration_type == REGISTRATION_TYPE_SOCKET_SERVER) {
91             f = vl_api_registration_file (reg);
92             vlib_cli_output (vm, "%20s %8d", reg->name, f->file_descriptor);
93         }
94     }
95 /* *INDENT-ON* */
96 }
97
98 vl_api_registration_t *
99 vl_socket_api_client_handle_to_registration (u32 handle)
100 {
101   socket_main_t *sm = &socket_main;
102   u32 index = socket_api_registration_handle_to_index (handle);
103   if (pool_is_free_index (sm->registration_pool, index))
104     {
105 #if DEBUG > 2
106       clib_warning ("Invalid index %d\n", index);
107 #endif
108       return 0;
109     }
110   return pool_elt_at_index (sm->registration_pool, index);
111 }
112
113 void
114 vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
115 {
116 #if CLIB_DEBUG > 1
117   u32 output_length;
118 #endif
119   socket_main_t *sm = &socket_main;
120   u16 msg_id = ntohs (*(u16 *) elem);
121   api_main_t *am = vlibapi_get_main ();
122   msgbuf_t *mb = (msgbuf_t *) (elem - offsetof (msgbuf_t, data));
123   vl_api_registration_t *sock_rp;
124   clib_file_main_t *fm = &file_main;
125   clib_error_t *error;
126   clib_file_t *cf;
127
128   cf = vl_api_registration_file (rp);
129   ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
130
131   if (msg_id >= vec_len (am->api_trace_cfg))
132     {
133       clib_warning ("id out of range: %d", msg_id);
134       vl_msg_api_free ((void *) elem);
135       return;
136     }
137
138   sock_rp = pool_elt_at_index (sm->registration_pool,
139                                rp->vl_api_registration_pool_index);
140   ASSERT (sock_rp);
141
142   /* Add the msgbuf_t to the output vector */
143   vec_add (sock_rp->output_vector, (u8 *) mb, sizeof (*mb));
144
145   /* Try to send the message and save any error like
146    * we do in the input epoll loop */
147   vec_add (sock_rp->output_vector, elem, ntohl (mb->data_len));
148   error = clib_file_write (cf);
149   unix_save_error (&unix_main, error);
150
151   /* Make sure cf not removed in clib_file_write */
152   cf = vl_api_registration_file (rp);
153   if (!cf)
154     {
155       clib_warning ("cf removed");
156       vl_msg_api_free ((void *) elem);
157       return;
158     }
159
160   /* If we didn't finish sending everything, wait for tx space */
161   if (vec_len (sock_rp->output_vector) > 0
162       && !(cf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
163     {
164       cf->flags |= UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
165       fm->file_update (cf, UNIX_FILE_UPDATE_MODIFY);
166     }
167
168 #if CLIB_DEBUG > 1
169   output_length = sizeof (*mb) + ntohl (mb->data_len);
170   clib_warning ("wrote %u bytes to fd %d", output_length,
171                 cf->file_descriptor);
172 #endif
173
174   vl_msg_api_free ((void *) elem);
175 }
176
177 void
178 vl_socket_free_registration_index (u32 pool_index)
179 {
180   int i;
181   vl_api_registration_t *rp;
182   void vl_api_call_reaper_functions (u32 client_index);
183
184   if (pool_is_free_index (socket_main.registration_pool, pool_index))
185     {
186       clib_warning ("main pool index %d already free", pool_index);
187       return;
188     }
189   rp = pool_elt_at_index (socket_main.registration_pool, pool_index);
190
191   vl_api_call_reaper_functions (pool_index);
192
193   ASSERT (rp->registration_type != REGISTRATION_TYPE_FREE);
194   for (i = 0; i < vec_len (rp->additional_fds_to_close); i++)
195     if (close (rp->additional_fds_to_close[i]) < 0)
196       clib_unix_warning ("close");
197   vec_free (rp->additional_fds_to_close);
198   vec_free (rp->name);
199   vec_free (rp->unprocessed_input);
200   vec_free (rp->output_vector);
201   rp->registration_type = REGISTRATION_TYPE_FREE;
202   pool_put (socket_main.registration_pool, rp);
203 }
204
205 void
206 vl_socket_process_api_msg (vl_api_registration_t * rp, i8 * input_v)
207 {
208   msgbuf_t *mbp = (msgbuf_t *) input_v;
209
210   u8 *the_msg = (u8 *) (mbp->data);
211   socket_main.current_rp = rp;
212   vl_msg_api_socket_handler (the_msg);
213   socket_main.current_rp = 0;
214 }
215
216 /*
217  * Read function for API socket.
218  *
219  * Read data from socket, invoke SOCKET_READ_EVENT
220  * for each fully read API message, return 0.
221  * Store incomplete data for next invocation to continue.
222  *
223  * On severe read error, the file is closed.
224  *
225  * As reading is single threaded,
226  * socket_main.input_buffer is used temporarily.
227  * Even its length is modified, but always restored before return.
228  *
229  * Incomplete data is copied into a vector,
230  * pointer saved in registration's unprocessed_input.
231  */
232 clib_error_t *
233 vl_socket_read_ready (clib_file_t * uf)
234 {
235   clib_file_main_t *fm = &file_main;
236   vlib_main_t *vm = vlib_get_main ();
237   vl_api_registration_t *rp;
238   /* n is the size of data read to input_buffer */
239   int n;
240   /* msg_buffer vector can point to input_buffer or unprocessed_input */
241   i8 *msg_buffer = 0;
242   /* data_for_process is a vector containing one full message, incl msgbuf_t */
243   u8 *data_for_process;
244   /* msgbuf_len is the size of one message, including sizeof (msgbuf_t) */
245   u32 msgbuf_len;
246   u32 save_input_buffer_length = vec_len (socket_main.input_buffer);
247   vl_socket_args_for_process_t *a;
248   u32 reg_index = uf->private_data;
249
250   rp = vl_socket_get_registration (reg_index);
251
252   /* Ignore unprocessed_input for now, n describes input_buffer for now. */
253   n = read (uf->file_descriptor, socket_main.input_buffer,
254             vec_len (socket_main.input_buffer));
255
256   if (n <= 0)
257     {
258       if (errno != EAGAIN)
259         {
260           /* Severe error, close the file. */
261           clib_file_del (fm, uf);
262           vl_socket_free_registration_index (reg_index);
263         }
264       /* EAGAIN means we do not close the file, but no data to process anyway. */
265       return 0;
266     }
267
268   /* Fake smaller length teporarily, so input_buffer can be used as msg_buffer. */
269   _vec_len (socket_main.input_buffer) = n;
270
271   /*
272    * Look for bugs here. This code is tricky because
273    * data read from a stream socket does not honor message
274    * boundaries. In the case of a long message (>4K bytes)
275    * we have to do (at least) 2 reads, etc.
276    */
277   /* Determine msg_buffer. */
278   if (vec_len (rp->unprocessed_input))
279     {
280       vec_append (rp->unprocessed_input, socket_main.input_buffer);
281       msg_buffer = rp->unprocessed_input;
282     }
283   else
284     {
285       msg_buffer = socket_main.input_buffer;
286     }
287   /* Loop to process any full messages. */
288   ASSERT (vec_len (msg_buffer) > 0);
289   do
290     {
291       /* Here, we are not sure how big a chunk of message we have left. */
292       /* Do we at least know how big the full message will be? */
293       if (vec_len (msg_buffer) <= sizeof (msgbuf_t))
294         /* No, so fragment is not a full message. */
295         goto save_and_split;
296
297       /* Now we know how big the full message will be. */
298       msgbuf_len =
299         ntohl (((msgbuf_t *) msg_buffer)->data_len) + sizeof (msgbuf_t);
300
301       /* But do we have a full message? */
302       if (msgbuf_len > vec_len (msg_buffer))
303         {
304         save_and_split:
305           /* We don't have the entire message yet. */
306           /* If msg_buffer is unprocessed_input, nothing needs to be done. */
307           if (msg_buffer == socket_main.input_buffer)
308             /* But if we were using the input buffer, save the fragment. */
309             {
310               ASSERT (vec_len (rp->unprocessed_input) == 0);
311               vec_validate (rp->unprocessed_input, vec_len (msg_buffer) - 1);
312               clib_memcpy_fast (rp->unprocessed_input, msg_buffer,
313                                 vec_len (msg_buffer));
314               _vec_len (rp->unprocessed_input) = vec_len (msg_buffer);
315             }
316           /* No more full messages, restore original input_buffer length. */
317           _vec_len (socket_main.input_buffer) = save_input_buffer_length;
318           return 0;
319         }
320
321       /*
322        * We have at least one full message.
323        * But msg_buffer can contain more data, so copy one message data
324        * so we can overwrite its length to what single message has.
325        */
326       data_for_process = (u8 *) vec_dup (msg_buffer);
327       _vec_len (data_for_process) = msgbuf_len;
328       /* Everything is ready to signal the SOCKET_READ_EVENT. */
329       pool_get (socket_main.process_args, a);
330       a->reg_index = reg_index;
331       a->data = data_for_process;
332
333       vlib_process_signal_event (vm, vl_api_clnt_node.index,
334                                  SOCKET_READ_EVENT,
335                                  a - socket_main.process_args);
336       if (vec_len (msg_buffer) > msgbuf_len)
337         /* There are some fragments left. Shrink the msg_buffer to simplify logic. */
338         vec_delete (msg_buffer, msgbuf_len, 0);
339       else
340         /* We are done with msg_buffer. */
341         _vec_len (msg_buffer) = 0;
342     }
343   while (vec_len (msg_buffer) > 0);
344
345   /* Restore input_buffer, it could have been msg_buffer. */
346   _vec_len (socket_main.input_buffer) = save_input_buffer_length;
347   return 0;
348 }
349
350 clib_error_t *
351 vl_socket_write_ready (clib_file_t * uf)
352 {
353   clib_file_main_t *fm = &file_main;
354   vl_api_registration_t *rp;
355   int n;
356
357   rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
358
359   /* Flush output vector. */
360   size_t total_bytes = vec_len (rp->output_vector);
361   size_t bytes_to_send, remaining_bytes = total_bytes;
362   void *p = rp->output_vector;
363   while (remaining_bytes > 0)
364     {
365       bytes_to_send = remaining_bytes > 4096 ? 4096 : remaining_bytes;
366       n = write (uf->file_descriptor, p, bytes_to_send);
367       if (n < 0)
368         {
369           if (errno == EAGAIN)
370             {
371               break;
372             }
373 #if DEBUG > 2
374           clib_warning ("write error, close the file...\n");
375 #endif
376           clib_file_del (fm, uf);
377           vl_socket_free_registration_index (rp -
378                                              socket_main.registration_pool);
379           return 0;
380         }
381       remaining_bytes -= bytes_to_send;
382       p += bytes_to_send;
383     }
384
385   vec_delete (rp->output_vector, total_bytes - remaining_bytes, 0);
386   if (vec_len (rp->output_vector) <= 0
387       && (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
388     {
389       uf->flags &= ~UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
390       fm->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
391     }
392
393   return 0;
394 }
395
396 clib_error_t *
397 vl_socket_error_ready (clib_file_t * uf)
398 {
399   vl_api_registration_t *rp;
400   clib_file_main_t *fm = &file_main;
401
402   rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
403   clib_file_del (fm, uf);
404   vl_socket_free_registration_index (rp - socket_main.registration_pool);
405
406   return 0;
407 }
408
409 void
410 socksvr_file_add (clib_file_main_t * fm, int fd)
411 {
412   vl_api_registration_t *rp;
413   clib_file_t template = { 0 };
414
415   pool_get (socket_main.registration_pool, rp);
416   clib_memset (rp, 0, sizeof (*rp));
417
418   template.read_function = vl_socket_read_ready;
419   template.write_function = vl_socket_write_ready;
420   template.error_function = vl_socket_error_ready;
421   template.file_descriptor = fd;
422   template.description = format (0, "socksrv");
423   template.private_data = rp - socket_main.registration_pool;
424
425   rp->registration_type = REGISTRATION_TYPE_SOCKET_SERVER;
426   rp->vl_api_registration_pool_index = rp - socket_main.registration_pool;
427   rp->clib_file_index = clib_file_add (fm, &template);
428 }
429
430 static clib_error_t *
431 socksvr_accept_ready (clib_file_t * uf)
432 {
433   clib_file_main_t *fm = &file_main;
434   socket_main_t *sm = &socket_main;
435   clib_socket_t *sock = &sm->socksvr_listen_socket;
436   clib_socket_t client;
437   clib_error_t *error;
438
439   error = clib_socket_accept (sock, &client);
440   if (error)
441     return error;
442
443   socksvr_file_add (fm, client.fd);
444   return 0;
445 }
446
447 static clib_error_t *
448 socksvr_bogus_write (clib_file_t * uf)
449 {
450   clib_warning ("why am I here?");
451   return 0;
452 }
453
454 /*
455  * vl_api_sockclnt_create_t_handler
456  */
457 void
458 vl_api_sockclnt_create_t_handler (vl_api_sockclnt_create_t * mp)
459 {
460   vl_api_registration_t *regp;
461   vl_api_sockclnt_create_reply_t *rp;
462   api_main_t *am = vlibapi_get_main ();
463   hash_pair_t *hp;
464   int rv = 0;
465   u32 nmsg = hash_elts (am->msg_index_by_name_and_crc);
466   u32 i = 0;
467
468   regp = socket_main.current_rp;
469
470   ASSERT (regp->registration_type == REGISTRATION_TYPE_SOCKET_SERVER);
471
472   regp->name = format (0, "%s%c", mp->name, 0);
473
474   u32 size = sizeof (*rp) + (nmsg * sizeof (vl_api_message_table_entry_t));
475   rp = vl_msg_api_alloc_zero (size);
476   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE_REPLY);
477   rp->index = htonl (sock_api_registration_handle (regp));
478   rp->context = mp->context;
479   rp->response = htonl (rv);
480   rp->count = htons (nmsg);
481
482   /* *INDENT-OFF* */
483   hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
484   ({
485     rp->message_table[i].index = htons(hp->value[0]);
486     (void) strncpy_s((char *)rp->message_table[i].name,
487                      64 /* bytes of space at dst */,
488                      (char *)hp->key,
489                      64-1 /* chars to copy, without zero byte. */);
490     i++;
491   }));
492   /* *INDENT-ON* */
493   vl_api_send_msg (regp, (u8 *) rp);
494 }
495
496 /*
497  * vl_api_sockclnt_delete_t_handler
498  */
499 void
500 vl_api_sockclnt_delete_t_handler (vl_api_sockclnt_delete_t * mp)
501 {
502   vl_api_registration_t *regp;
503   vl_api_sockclnt_delete_reply_t *rp;
504
505   regp = vl_api_client_index_to_registration (mp->client_index);
506   if (!regp)
507     return;
508
509   u32 reg_index = socket_api_registration_handle_to_index (ntohl (mp->index));
510   rp = vl_msg_api_alloc (sizeof (*rp));
511   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_DELETE_REPLY);
512   rp->context = mp->context;
513
514   if (!pool_is_free_index (socket_main.registration_pool, reg_index))
515     {
516       rp->response = htonl (1);
517       vl_api_send_msg (regp, (u8 *) rp);
518
519       vl_api_registration_del_file (regp);
520       vl_socket_free_registration_index (reg_index);
521     }
522   else
523     {
524       clib_warning ("unknown client ID %d", reg_index);
525       rp->response = htonl (-1);
526       vl_api_send_msg (regp, (u8 *) rp);
527     }
528 }
529
530 clib_error_t *
531 vl_sock_api_send_fd_msg (int socket_fd, int fds[], int n_fds)
532 {
533   struct msghdr mh = { 0 };
534   struct iovec iov[1];
535   char ctl[CMSG_SPACE (sizeof (int) * n_fds)];
536   struct cmsghdr *cmsg;
537   char *msg = "fdmsg";
538   int rv;
539
540   iov[0].iov_base = msg;
541   iov[0].iov_len = strlen (msg);
542   mh.msg_iov = iov;
543   mh.msg_iovlen = 1;
544
545   clib_memset (&ctl, 0, sizeof (ctl));
546   mh.msg_control = ctl;
547   mh.msg_controllen = sizeof (ctl);
548   cmsg = CMSG_FIRSTHDR (&mh);
549   cmsg->cmsg_len = CMSG_LEN (sizeof (int) * n_fds);
550   cmsg->cmsg_level = SOL_SOCKET;
551   cmsg->cmsg_type = SCM_RIGHTS;
552   clib_memcpy_fast (CMSG_DATA (cmsg), fds, sizeof (int) * n_fds);
553
554   while ((rv = sendmsg (socket_fd, &mh, 0)) < 0 && errno == EAGAIN)
555     ;
556   if (rv < 0)
557     return clib_error_return_unix (0, "sendmsg");
558   return 0;
559 }
560
561 vl_api_shm_elem_config_t *
562 vl_api_make_shm_config (vl_api_sock_init_shm_t * mp)
563 {
564   vl_api_shm_elem_config_t *config = 0, *c;
565   u64 cfg;
566   int i;
567
568   if (!mp->nitems)
569     {
570       vec_validate (config, 6);
571       config[0].type = VL_API_VLIB_RING;
572       config[0].size = 256;
573       config[0].count = 32;
574
575       config[1].type = VL_API_VLIB_RING;
576       config[1].size = 1024;
577       config[1].count = 16;
578
579       config[2].type = VL_API_VLIB_RING;
580       config[2].size = 4096;
581       config[2].count = 2;
582
583       config[3].type = VL_API_CLIENT_RING;
584       config[3].size = 256;
585       config[3].count = 32;
586
587       config[4].type = VL_API_CLIENT_RING;
588       config[4].size = 1024;
589       config[4].count = 16;
590
591       config[5].type = VL_API_CLIENT_RING;
592       config[5].size = 4096;
593       config[5].count = 2;
594
595       config[6].type = VL_API_QUEUE;
596       config[6].count = 128;
597       config[6].size = sizeof (uword);
598     }
599   else
600     {
601       vec_validate (config, mp->nitems - 1);
602       for (i = 0; i < mp->nitems; i++)
603         {
604           cfg = mp->configs[i];
605           /* Pretty much a hack but it avoids defining our own api type
606            * in memclnt.api */
607           c = (vl_api_shm_elem_config_t *) & cfg;
608           config[i].type = c->type;
609           config[i].count = c->count;
610           config[i].size = c->size;
611         }
612     }
613   return config;
614 }
615
616 /*
617  * Bootstrap shm api using the socket api
618  */
619 void
620 vl_api_sock_init_shm_t_handler (vl_api_sock_init_shm_t * mp)
621 {
622   vl_api_sock_init_shm_reply_t *rmp;
623   ssvm_private_t _memfd_private, *memfd = &_memfd_private;
624   svm_map_region_args_t _args, *a = &_args;
625   vl_api_registration_t *regp;
626   api_main_t *am = vlibapi_get_main ();
627   svm_region_t *vlib_rp;
628   clib_file_t *cf;
629   vl_api_shm_elem_config_t *config = 0;
630   vl_shmem_hdr_t *shmem_hdr;
631   int rv, tries = 1000;
632
633   regp = vl_api_client_index_to_registration (mp->client_index);
634   if (regp == 0)
635     {
636       clib_warning ("API client disconnected");
637       return;
638     }
639   if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
640     {
641       clib_warning ("Invalid registration");
642       return;
643     }
644
645   /*
646    * Set up a memfd segment of the requested size wherein the
647    * shmem data structures will be initialized
648    */
649   clib_memset (memfd, 0, sizeof (*memfd));
650   memfd->ssvm_size = mp->requested_size;
651   memfd->requested_va = 0ULL;
652   memfd->is_server = 1;
653   memfd->name = format (0, "%s%c", regp->name, 0);
654
655   if ((rv = ssvm_server_init_memfd (memfd)))
656     goto reply;
657
658   /* delete the unused heap created in ssvm_server_init_memfd and mark it
659    * accessible again for ASAN */
660   clib_mem_destroy_heap (memfd->sh->heap);
661   CLIB_MEM_UNPOISON ((void *) memfd->sh->ssvm_va, memfd->ssvm_size);
662
663   /* Remember to close this fd when the socket connection goes away */
664   vec_add1 (regp->additional_fds_to_close, memfd->fd);
665
666   /*
667    * Create a plausible svm_region in the memfd backed segment
668    */
669   clib_memset (a, 0, sizeof (*a));
670   a->baseva = memfd->sh->ssvm_va + MMAP_PAGESIZE;
671   a->size = memfd->ssvm_size - MMAP_PAGESIZE;
672   /* $$$$ might want a different config parameter */
673   a->pvt_heap_size = am->api_pvt_heap_size;
674   a->flags = SVM_FLAGS_MHEAP;
675   svm_region_init_mapped_region (a, (svm_region_t *) a->baseva);
676
677   /*
678    * Part deux, initialize the svm_region_t shared-memory header
679    * api allocation rings, and so on.
680    */
681   config = vl_api_make_shm_config (mp);
682   vlib_rp = (svm_region_t *) a->baseva;
683   vl_init_shmem (vlib_rp, config, 1 /* is_vlib (dont-care) */ ,
684                  1 /* is_private */ );
685
686   /* Remember who created this. Needs to be post vl_init_shmem */
687   shmem_hdr = (vl_shmem_hdr_t *) vlib_rp->user_ctx;
688   shmem_hdr->clib_file_index = vl_api_registration_file_index (regp);
689
690   vec_add1 (am->vlib_private_rps, vlib_rp);
691   memfd->sh->ready = 1;
692   vec_free (config);
693
694   /* Recompute the set of input queues to poll in memclnt_process */
695   vec_reset_length (vl_api_queue_cursizes);
696
697 reply:
698
699   rmp = vl_msg_api_alloc (sizeof (*rmp));
700   rmp->_vl_msg_id = htons (VL_API_SOCK_INIT_SHM_REPLY);
701   rmp->context = mp->context;
702   rmp->retval = htonl (rv);
703
704   /*
705    * Note: The reply message needs to make it out the back door
706    * before we send the magic fd message. That's taken care of by
707    * the send function.
708    */
709   vl_socket_api_send (regp, (u8 *) rmp);
710
711   if (rv != 0)
712     return;
713
714   /* Send the magic "here's your sign (aka fd)" socket message */
715   cf = vl_api_registration_file (regp);
716   if (!cf)
717     {
718       clib_warning ("cf removed");
719       return;
720     }
721
722   /* Wait for reply to be consumed before sending the fd */
723   while (tries-- > 0)
724     {
725       int bytes;
726       rv = ioctl (cf->file_descriptor, TIOCOUTQ, &bytes);
727       if (rv < 0)
728         {
729           clib_unix_warning ("ioctl returned");
730           break;
731         }
732       if (bytes == 0)
733         break;
734       usleep (1e3);
735     }
736
737   vl_sock_api_send_fd_msg (cf->file_descriptor, &memfd->fd, 1);
738 }
739
740 #define foreach_vlib_api_msg                            \
741   _(SOCKCLNT_CREATE, sockclnt_create, 1)                \
742   _(SOCKCLNT_DELETE, sockclnt_delete, 1)                \
743   _(SOCK_INIT_SHM, sock_init_shm, 1)
744
745 clib_error_t *
746 vl_sock_api_init (vlib_main_t * vm)
747 {
748   clib_file_main_t *fm = &file_main;
749   clib_file_t template = { 0 };
750   vl_api_registration_t *rp;
751   socket_main_t *sm = &socket_main;
752   clib_socket_t *sock = &sm->socksvr_listen_socket;
753   clib_error_t *error;
754
755   /* If not explicitly configured, do not bind/enable, etc. */
756   if (sm->socket_name == 0)
757     return 0;
758
759 #define _(N,n,t)                                                \
760     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
761                            vl_api_##n##_t_handler,              \
762                            vl_noop_handler,                     \
763                            vl_api_##n##_t_endian,               \
764                            vl_api_##n##_t_print,                \
765                            sizeof(vl_api_##n##_t), t);
766   foreach_vlib_api_msg;
767 #undef _
768
769   vec_resize (sm->input_buffer, 4096);
770
771   sock->config = (char *) sm->socket_name;
772   sock->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_ALLOW_GROUP_WRITE;
773   error = clib_socket_init (sock);
774   if (error)
775     return error;
776
777   pool_get (sm->registration_pool, rp);
778   clib_memset (rp, 0, sizeof (*rp));
779
780   rp->registration_type = REGISTRATION_TYPE_SOCKET_LISTEN;
781
782   template.read_function = socksvr_accept_ready;
783   template.write_function = socksvr_bogus_write;
784   template.file_descriptor = sock->fd;
785   template.description = format (0, "socksvr %s", sock->config);
786   template.private_data = rp - sm->registration_pool;
787
788   rp->clib_file_index = clib_file_add (fm, &template);
789   return 0;
790 }
791
792 static clib_error_t *
793 socket_exit (vlib_main_t * vm)
794 {
795   socket_main_t *sm = &socket_main;
796   vl_api_registration_t *rp;
797
798   /* Defensive driving in case something wipes out early */
799   if (sm->registration_pool)
800     {
801       u32 index;
802         /* *INDENT-OFF* */
803         pool_foreach (rp, sm->registration_pool)  {
804           vl_api_registration_del_file (rp);
805           index = rp->vl_api_registration_pool_index;
806           vl_socket_free_registration_index (index);
807         }
808 /* *INDENT-ON* */
809     }
810
811   return 0;
812 }
813
814 VLIB_MAIN_LOOP_EXIT_FUNCTION (socket_exit);
815
816 static clib_error_t *
817 socksvr_config (vlib_main_t * vm, unformat_input_t * input)
818 {
819   socket_main_t *sm = &socket_main;
820
821   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
822     {
823       if (unformat (input, "socket-name %s", &sm->socket_name))
824         ;
825       /* DEPRECATE: default keyword is ignored */
826       else if (unformat (input, "default"))
827         ;
828       else
829         {
830           return clib_error_return (0, "unknown input '%U'",
831                                     format_unformat_error, input);
832         }
833     }
834
835   if (!vec_len (sm->socket_name))
836     sm->socket_name = format (0, "%s/%s", vlib_unix_get_runtime_dir (),
837                               API_SOCKET_FILENAME);
838   vec_terminate_c_string (sm->socket_name);
839
840   return 0;
841 }
842
843 VLIB_CONFIG_FUNCTION (socksvr_config, "socksvr");
844
845 void
846 vlibsocket_reference ()
847 {
848 }
849
850 /*
851  * fd.io coding-style-patch-verification: ON
852  *
853  * Local Variables:
854  * eval: (c-set-style "gnu")
855  * End:
856  */