vlib: fix build with musl
[vpp.git] / src / vlibmemory / socket_client.c
1 /*
2  *------------------------------------------------------------------
3  * socket_client.c - API message handling over sockets, client code.
4  *
5  * Copyright (c) 2017 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 <stdio.h>
21 #define __USE_GNU
22 #define _GNU_SOURCE
23 #include <sys/socket.h>
24
25 #include <svm/ssvm.h>
26 #include <vlibmemory/socket_client.h>
27 #include <vlibmemory/memory_client.h>
28
29 #include <vlibmemory/vl_memory_msg_enum.h>
30
31 #define vl_typedefs             /* define message structures */
32 #include <vlibmemory/vl_memory_api_h.h>
33 #undef vl_typedefs
34
35 #define vl_endianfun            /* define message structures */
36 #include <vlibmemory/vl_memory_api_h.h>
37 #undef vl_endianfun
38
39 /* instantiate all the print functions we know about */
40 #define vl_print(handle, ...) clib_warning (__VA_ARGS__)
41 #define vl_printfun
42 #include <vlibmemory/vl_memory_api_h.h>
43 #undef vl_printfun
44
45 socket_client_main_t socket_client_main;
46 __thread socket_client_main_t *socket_client_ctx = &socket_client_main;
47
48 /* Debug aid */
49 u32 vl (void *p) __attribute__ ((weak));
50
51 u32
52 vl (void *p)
53 {
54   return vec_len (p);
55 }
56
57 static socket_client_main_t *
58 vl_socket_client_ctx_push (socket_client_main_t * ctx)
59 {
60   socket_client_main_t *old = socket_client_ctx;
61   socket_client_ctx = ctx;
62   return old;
63 }
64
65 static void
66 vl_socket_client_ctx_pop (socket_client_main_t * old_ctx)
67 {
68   socket_client_ctx = old_ctx;
69 }
70
71 static int
72 vl_socket_client_read_internal (socket_client_main_t * scm, int wait)
73 {
74   u32 data_len = 0, msg_size;
75   int n, current_rx_index;
76   msgbuf_t *mbp = 0;
77   f64 timeout;
78
79   if (scm->socket_fd == 0)
80     return -1;
81
82   if (wait)
83     timeout = clib_time_now (&scm->clib_time) + wait;
84
85   while (1)
86     {
87       while (vec_len (scm->socket_rx_buffer) < sizeof (*mbp))
88         {
89           current_rx_index = vec_len (scm->socket_rx_buffer);
90           vec_validate (scm->socket_rx_buffer, current_rx_index
91                         + scm->socket_buffer_size - 1);
92           _vec_len (scm->socket_rx_buffer) = current_rx_index;
93           n = read (scm->socket_fd, scm->socket_rx_buffer + current_rx_index,
94                     scm->socket_buffer_size);
95           if (n < 0)
96             {
97               if (errno == EAGAIN)
98                 continue;
99
100               clib_unix_warning ("socket_read");
101               return -1;
102             }
103           _vec_len (scm->socket_rx_buffer) += n;
104         }
105
106 #if CLIB_DEBUG > 1
107       if (n > 0)
108         clib_warning ("read %d bytes", n);
109 #endif
110
111       mbp = (msgbuf_t *) (scm->socket_rx_buffer);
112       data_len = ntohl (mbp->data_len);
113       current_rx_index = vec_len (scm->socket_rx_buffer);
114       vec_validate (scm->socket_rx_buffer, current_rx_index + data_len);
115       _vec_len (scm->socket_rx_buffer) = current_rx_index;
116       mbp = (msgbuf_t *) (scm->socket_rx_buffer);
117       msg_size = data_len + sizeof (*mbp);
118
119       while (vec_len (scm->socket_rx_buffer) < msg_size)
120         {
121           n = read (scm->socket_fd,
122                     scm->socket_rx_buffer + vec_len (scm->socket_rx_buffer),
123                     msg_size - vec_len (scm->socket_rx_buffer));
124           if (n < 0)
125             {
126               if (errno == EAGAIN)
127                 continue;
128
129               clib_unix_warning ("socket_read");
130               return -1;
131             }
132           _vec_len (scm->socket_rx_buffer) += n;
133         }
134
135       if (vec_len (scm->socket_rx_buffer) >= data_len + sizeof (*mbp))
136         {
137           vl_msg_api_socket_handler ((void *) (mbp->data));
138
139           if (vec_len (scm->socket_rx_buffer) == data_len + sizeof (*mbp))
140             _vec_len (scm->socket_rx_buffer) = 0;
141           else
142             vec_delete (scm->socket_rx_buffer, data_len + sizeof (*mbp), 0);
143           mbp = 0;
144
145           /* Quit if we're out of data, and not expecting a ping reply */
146           if (vec_len (scm->socket_rx_buffer) == 0
147               && scm->control_pings_outstanding == 0)
148             break;
149         }
150       if (wait && clib_time_now (&scm->clib_time) >= timeout)
151         return -1;
152     }
153   return 0;
154 }
155
156 int
157 vl_socket_client_read (int wait)
158 {
159   return vl_socket_client_read_internal (socket_client_ctx, wait);
160 }
161
162 int
163 vl_socket_client_read2 (socket_client_main_t * scm, int wait)
164 {
165   socket_client_main_t *old_ctx;
166   int rv;
167
168   old_ctx = vl_socket_client_ctx_push (scm);
169   rv = vl_socket_client_read_internal (scm, wait);
170   vl_socket_client_ctx_pop (old_ctx);
171   return rv;
172 }
173
174 static int
175 vl_socket_client_write_internal (socket_client_main_t * scm)
176 {
177   int n;
178
179   msgbuf_t msgbuf = {
180     .q = 0,
181     .gc_mark_timestamp = 0,
182     .data_len = htonl (scm->socket_tx_nbytes),
183   };
184
185   n = write (scm->socket_fd, &msgbuf, sizeof (msgbuf));
186   if (n < sizeof (msgbuf))
187     {
188       clib_unix_warning ("socket write (msgbuf)");
189       return -1;
190     }
191
192   n = write (scm->socket_fd, scm->socket_tx_buffer, scm->socket_tx_nbytes);
193   if (n < scm->socket_tx_nbytes)
194     {
195       clib_unix_warning ("socket write (msg)");
196       return -1;
197     }
198
199   return n;
200 }
201
202 int
203 vl_socket_client_write (void)
204 {
205   return vl_socket_client_write_internal (socket_client_ctx);
206 }
207
208 int
209 vl_socket_client_write2 (socket_client_main_t * scm)
210 {
211   socket_client_main_t *old_ctx;
212   int rv;
213
214   old_ctx = vl_socket_client_ctx_push (scm);
215   rv = vl_socket_client_write_internal (scm);
216   vl_socket_client_ctx_pop (old_ctx);
217   return rv;
218 }
219
220 void *
221 vl_socket_client_msg_alloc2 (socket_client_main_t * scm, int nbytes)
222 {
223   scm->socket_tx_nbytes = nbytes;
224   return ((void *) scm->socket_tx_buffer);
225 }
226
227 void *
228 vl_socket_client_msg_alloc (int nbytes)
229 {
230   return vl_socket_client_msg_alloc2 (socket_client_ctx, nbytes);
231 }
232
233 void
234 vl_socket_client_disconnect2 (socket_client_main_t * scm)
235 {
236   if (vl_mem_client_is_connected ())
237     {
238       vl_client_disconnect_from_vlib_no_unmap ();
239       ssvm_delete_memfd (&scm->memfd_segment);
240     }
241   if (scm->socket_fd && (close (scm->socket_fd) < 0))
242     clib_unix_warning ("close");
243   scm->socket_fd = 0;
244 }
245
246 void
247 vl_socket_client_disconnect (void)
248 {
249   vl_socket_client_disconnect2 (socket_client_ctx);
250 }
251
252 void
253 vl_socket_client_enable_disable2 (socket_client_main_t * scm, int enable)
254 {
255   scm->socket_enable = enable;
256 }
257
258 void
259 vl_socket_client_enable_disable (int enable)
260 {
261   vl_socket_client_enable_disable2 (socket_client_ctx, enable);
262 }
263
264 static clib_error_t *
265 vl_sock_api_recv_fd_msg_internal (socket_client_main_t * scm, int fds[],
266                                   int n_fds, u32 wait)
267 {
268   char msgbuf[16];
269   char ctl[CMSG_SPACE (sizeof (int) * n_fds)
270            + CMSG_SPACE (sizeof (struct ucred))];
271   struct msghdr mh = { 0 };
272   struct iovec iov[1];
273   ssize_t size = 0;
274   struct ucred *cr = 0;
275   struct cmsghdr *cmsg;
276   pid_t pid __attribute__ ((unused));
277   uid_t uid __attribute__ ((unused));
278   gid_t gid __attribute__ ((unused));
279   int socket_fd;
280   f64 timeout;
281
282   socket_fd = scm->client_socket.fd;
283
284   iov[0].iov_base = msgbuf;
285   iov[0].iov_len = 5;
286   mh.msg_iov = iov;
287   mh.msg_iovlen = 1;
288   mh.msg_control = ctl;
289   mh.msg_controllen = sizeof (ctl);
290
291   clib_memset (ctl, 0, sizeof (ctl));
292
293   if (wait != ~0)
294     {
295       timeout = clib_time_now (&scm->clib_time) + wait;
296       while (size != 5 && clib_time_now (&scm->clib_time) < timeout)
297         size = recvmsg (socket_fd, &mh, MSG_DONTWAIT);
298     }
299   else
300     size = recvmsg (socket_fd, &mh, 0);
301
302   if (size != 5)
303     {
304       return (size == 0) ? clib_error_return (0, "disconnected") :
305         clib_error_return_unix (0, "recvmsg: malformed message (fd %d)",
306                                 socket_fd);
307     }
308
309   cmsg = CMSG_FIRSTHDR (&mh);
310   while (cmsg)
311     {
312       if (cmsg->cmsg_level == SOL_SOCKET)
313         {
314           if (cmsg->cmsg_type == SCM_CREDENTIALS)
315             {
316               cr = (struct ucred *) CMSG_DATA (cmsg);
317               uid = cr->uid;
318               gid = cr->gid;
319               pid = cr->pid;
320             }
321           else if (cmsg->cmsg_type == SCM_RIGHTS)
322             {
323               clib_memcpy_fast (fds, CMSG_DATA (cmsg), sizeof (int) * n_fds);
324             }
325         }
326       cmsg = CMSG_NXTHDR (&mh, cmsg);
327     }
328   return 0;
329 }
330
331 clib_error_t *
332 vl_sock_api_recv_fd_msg (int socket_fd, int fds[], int n_fds, u32 wait)
333 {
334   return vl_sock_api_recv_fd_msg_internal (socket_client_ctx, fds, n_fds,
335                                            wait);
336 }
337
338 clib_error_t *
339 vl_sock_api_recv_fd_msg2 (socket_client_main_t * scm, int socket_fd,
340                           int fds[], int n_fds, u32 wait)
341 {
342   socket_client_main_t *old_ctx;
343   clib_error_t *error;
344
345   old_ctx = vl_socket_client_ctx_push (scm);
346   error = vl_sock_api_recv_fd_msg_internal (scm, fds, n_fds, wait);
347   vl_socket_client_ctx_pop (old_ctx);
348   return error;
349 }
350
351 static void vl_api_sock_init_shm_reply_t_handler
352   (vl_api_sock_init_shm_reply_t * mp)
353 {
354   socket_client_main_t *scm = socket_client_ctx;
355   ssvm_private_t *memfd = &scm->memfd_segment;
356   i32 retval = ntohl (mp->retval);
357   api_main_t *am = vlibapi_get_main ();
358   clib_error_t *error;
359   int my_fd = -1;
360   u8 *new_name;
361
362   if (retval)
363     {
364       clib_warning ("failed to init shmem");
365       return;
366     }
367
368   /*
369    * Check the socket for the magic fd
370    */
371   error = vl_sock_api_recv_fd_msg (scm->socket_fd, &my_fd, 1, 5);
372   if (error)
373     {
374       clib_error_report (error);
375       retval = -99;
376       return;
377     }
378
379   clib_memset (memfd, 0, sizeof (*memfd));
380   memfd->fd = my_fd;
381
382   /* Note: this closes memfd.fd */
383   retval = ssvm_client_init_memfd (memfd);
384   if (retval)
385     clib_warning ("WARNING: segment map returned %d", retval);
386
387   /*
388    * Pivot to the memory client segment that vpp just created
389    */
390   am->vlib_rp = (void *) (memfd->requested_va + MMAP_PAGESIZE);
391   am->shmem_hdr = (void *) am->vlib_rp->user_ctx;
392
393   new_name = format (0, "%v[shm]%c", scm->name, 0);
394   vl_client_install_client_message_handlers ();
395   if (scm->want_shm_pthread)
396     {
397       vl_client_connect_to_vlib_no_map ("pvt", (char *) new_name,
398                                         32 /* input_queue_length */ );
399     }
400   else
401     {
402       vl_client_connect_to_vlib_no_rx_pthread_no_map ("pvt",
403                                                       (char *) new_name, 32
404                                                       /* input_queue_length */
405         );
406     }
407   vl_socket_client_enable_disable (0);
408   vec_free (new_name);
409 }
410
411 static void
412 vl_api_sockclnt_create_reply_t_handler (vl_api_sockclnt_create_reply_t * mp)
413 {
414   socket_client_main_t *scm = socket_client_ctx;
415   if (!mp->response)
416     {
417       scm->socket_enable = 1;
418       scm->client_index = clib_net_to_host_u32 (mp->index);
419     }
420 }
421
422 #define foreach_sock_client_api_msg                             \
423 _(SOCKCLNT_CREATE_REPLY, sockclnt_create_reply)                 \
424 _(SOCK_INIT_SHM_REPLY, sock_init_shm_reply)                     \
425
426 static void
427 noop_handler (void *notused)
428 {
429 }
430
431 void
432 vl_sock_client_install_message_handlers (void)
433 {
434
435 #define _(N,n)                                                  \
436     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
437                             vl_api_##n##_t_handler,             \
438                             noop_handler,                       \
439                             vl_api_##n##_t_endian,              \
440                             vl_api_##n##_t_print,               \
441                             sizeof(vl_api_##n##_t), 1);
442   foreach_sock_client_api_msg;
443 #undef _
444 }
445
446 int
447 vl_socket_client_connect_internal (socket_client_main_t * scm,
448                                    char *socket_path, char *client_name,
449                                    u32 socket_buffer_size)
450 {
451   vl_api_sockclnt_create_t *mp;
452   clib_socket_t *sock;
453   clib_error_t *error;
454
455   /* Already connected? */
456   if (scm->socket_fd)
457     return (-2);
458
459   /* bogus call? */
460   if (socket_path == 0 || client_name == 0)
461     return (-3);
462
463   sock = &scm->client_socket;
464   sock->config = socket_path;
465   sock->flags = CLIB_SOCKET_F_IS_CLIENT | CLIB_SOCKET_F_NON_BLOCKING_CONNECT;
466
467   if ((error = clib_socket_init (sock)))
468     {
469       clib_error_report (error);
470       return (-1);
471     }
472
473   vl_sock_client_install_message_handlers ();
474
475   scm->socket_fd = sock->fd;
476   scm->socket_buffer_size = socket_buffer_size ? socket_buffer_size :
477     SOCKET_CLIENT_DEFAULT_BUFFER_SIZE;
478   vec_validate (scm->socket_tx_buffer, scm->socket_buffer_size - 1);
479   vec_validate (scm->socket_rx_buffer, scm->socket_buffer_size - 1);
480   _vec_len (scm->socket_rx_buffer) = 0;
481   _vec_len (scm->socket_tx_buffer) = 0;
482   scm->name = format (0, "%s", client_name);
483
484   mp = vl_socket_client_msg_alloc2 (scm, sizeof (*mp));
485   mp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE);
486   strncpy ((char *) mp->name, client_name, sizeof (mp->name) - 1);
487   mp->name[sizeof (mp->name) - 1] = 0;
488   mp->context = 0xfeedface;
489
490   clib_time_init (&scm->clib_time);
491
492   if (vl_socket_client_write_internal (scm) <= 0)
493     return (-1);
494
495   if (vl_socket_client_read_internal (scm, 5))
496     return (-1);
497
498   return (0);
499 }
500
501 int
502 vl_socket_client_connect (char *socket_path, char *client_name,
503                           u32 socket_buffer_size)
504 {
505   return vl_socket_client_connect_internal (socket_client_ctx, socket_path,
506                                             client_name, socket_buffer_size);
507 }
508
509 int
510 vl_socket_client_connect2 (socket_client_main_t * scm, char *socket_path,
511                            char *client_name, u32 socket_buffer_size)
512 {
513   socket_client_main_t *old_ctx;
514   int rv;
515
516   old_ctx = vl_socket_client_ctx_push (scm);
517   rv = vl_socket_client_connect_internal (socket_client_ctx, socket_path,
518                                           client_name, socket_buffer_size);
519   vl_socket_client_ctx_pop (old_ctx);
520   return rv;
521 }
522
523 int
524 vl_socket_client_init_shm_internal (socket_client_main_t * scm,
525                                     vl_api_shm_elem_config_t * config,
526                                     int want_pthread)
527 {
528   vl_api_sock_init_shm_t *mp;
529   int rv, i;
530   u64 *cfg;
531
532   scm->want_shm_pthread = want_pthread;
533
534   mp = vl_socket_client_msg_alloc2 (scm, sizeof (*mp) +
535                                     vec_len (config) * sizeof (u64));
536   clib_memset (mp, 0, sizeof (*mp));
537   mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_SOCK_INIT_SHM);
538   mp->client_index = clib_host_to_net_u32 (scm->client_index);
539   mp->requested_size = 64 << 20;
540
541   if (config)
542     {
543       for (i = 0; i < vec_len (config); i++)
544         {
545           cfg = (u64 *) & config[i];
546           mp->configs[i] = *cfg;
547         }
548       mp->nitems = vec_len (config);
549     }
550   rv = vl_socket_client_write_internal (scm);
551   if (rv <= 0)
552     return rv;
553
554   if (vl_socket_client_read_internal (scm, 1))
555     return -1;
556
557   return 0;
558 }
559
560 int
561 vl_socket_client_init_shm (vl_api_shm_elem_config_t * config,
562                            int want_pthread)
563 {
564   return vl_socket_client_init_shm_internal (socket_client_ctx, config,
565                                              want_pthread);
566 }
567
568 int
569 vl_socket_client_init_shm2 (socket_client_main_t * scm,
570                             vl_api_shm_elem_config_t * config,
571                             int want_pthread)
572 {
573   socket_client_main_t *old_ctx;
574   int rv;
575
576   old_ctx = vl_socket_client_ctx_push (scm);
577   rv = vl_socket_client_init_shm_internal (socket_client_ctx, config,
578                                            want_pthread);
579   vl_socket_client_ctx_pop (old_ctx);
580   return rv;
581 }
582
583 clib_error_t *
584 vl_socket_client_recv_fd_msg2 (socket_client_main_t * scm, int fds[],
585                                int n_fds, u32 wait)
586 {
587   if (!scm->socket_fd)
588     return clib_error_return (0, "no socket");
589   return vl_sock_api_recv_fd_msg_internal (scm, fds, n_fds, wait);
590 }
591
592 clib_error_t *
593 vl_socket_client_recv_fd_msg (int fds[], int n_fds, u32 wait)
594 {
595   return vl_socket_client_recv_fd_msg2 (socket_client_ctx, fds, n_fds, wait);
596 }
597
598 /*
599  * fd.io coding-style-patch-verification: ON
600  *
601  * Local Variables:
602  * eval: (c-set-style "gnu")
603  * End:
604  */