2 *------------------------------------------------------------------
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:
10 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <sys/ioctl.h>
24 #include <vppinfra/byte_order.h>
29 #include <vlibsocket/api.h>
30 #include <vlibmemory/api.h>
32 #include <vlibsocket/vl_socket_msg_enum.h> /* enumerate all vlib messages */
34 #define vl_typedefs /* define message structures */
35 #include <vlibsocket/vl_socket_api_h.h>
38 /* instantiate all the print functions we know about */
39 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
41 #include <vlibsocket/vl_socket_api_h.h>
44 /* instantiate all the endian swap functions we know about */
46 #include <vlibsocket/vl_socket_api_h.h>
49 socket_main_t socket_main;
52 dump_socket_clients (vlib_main_t * vm, api_main_t * am)
54 vl_api_registration_t *reg;
55 socket_main_t *sm = &socket_main;
56 unix_main_t *um = &unix_main;
60 * Must have at least one active client, not counting the
61 * REGISTRATION_TYPE_SOCKET_LISTEN bind/accept socket
63 if (pool_elts (sm->registration_pool) < 2)
66 vlib_cli_output (vm, "TCP socket clients");
67 vlib_cli_output (vm, "%16s %8s", "Name", "Fildesc");
69 pool_foreach (reg, sm->registration_pool,
71 if (reg->registration_type == REGISTRATION_TYPE_SOCKET_SERVER) {
72 f = pool_elt_at_index (um->file_pool, reg->unix_file_index);
73 vlib_cli_output (vm, "%16s %8d",
74 reg->name, f->file_descriptor);
81 vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
83 u32 nbytes = 4; /* for the length... */
84 u16 msg_id = ntohs (*(u16 *) elem);
87 api_main_t *am = &api_main;
89 ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
91 if (msg_id >= vec_len (am->api_trace_cfg))
93 clib_warning ("id out of range: %d", msg_id);
94 vl_msg_api_free ((void *) elem);
98 msg_length = am->api_trace_cfg[msg_id].size;
100 tmp = clib_host_to_net_u32 (nbytes);
102 vl_socket_add_pending_output (rp->unix_file_index
103 + unix_main.file_pool,
104 rp->vl_api_registration_pool_index
105 + socket_main.registration_pool,
106 (u8 *) & tmp, sizeof (tmp));
107 vl_socket_add_pending_output (rp->unix_file_index
108 + unix_main.file_pool,
109 rp->vl_api_registration_pool_index
110 + socket_main.registration_pool,
112 vl_msg_api_free ((void *) elem);
116 vl_socket_api_send_with_data (vl_api_registration_t * rp,
117 u8 * elem, u8 * data_vector)
119 u32 nbytes = 4; /* for the length... */
120 u16 msg_id = ntohs (*(u16 *) elem);
123 api_main_t *am = &api_main;
125 ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
127 if (msg_id >= vec_len (am->api_trace_cfg))
129 clib_warning ("id out of range: %d", msg_id);
130 vec_free (data_vector);
131 vl_msg_api_free ((void *) elem);
135 msg_length = am->api_trace_cfg[msg_id].size;
136 nbytes += msg_length;
137 nbytes += vec_len (data_vector);
139 /* Length in network byte order */
140 tmp = clib_host_to_net_u32 (nbytes);
142 vl_socket_add_pending_output (rp->unix_file_index
143 + unix_main.file_pool,
144 rp->vl_api_registration_pool_index
145 + socket_main.registration_pool,
146 (u8 *) & tmp, sizeof (tmp));
147 vl_socket_add_pending_output (rp->unix_file_index
148 + unix_main.file_pool,
149 rp->vl_api_registration_pool_index
150 + socket_main.registration_pool,
152 vl_socket_add_pending_output (rp->unix_file_index
153 + unix_main.file_pool,
154 rp->vl_api_registration_pool_index
155 + socket_main.registration_pool,
156 data_vector, vec_len (data_vector));
157 vl_msg_api_free ((void *) elem);
161 vl_socket_api_send_with_length_internal (vl_api_registration_t * rp,
162 u8 * elem, u32 msg_length, int free)
164 u32 nbytes = 4; /* for the length... */
165 u16 msg_id = ntohs (*(u16 *) elem);
167 api_main_t *am = &api_main;
169 ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
171 if (msg_id >= vec_len (am->api_trace_cfg))
173 clib_warning ("id out of range: %d", msg_id);
175 vl_msg_api_free ((void *) elem);
179 nbytes += msg_length;
181 /* Length in network byte order */
182 tmp = clib_host_to_net_u32 (nbytes);
184 vl_socket_add_pending_output (rp->unix_file_index
185 + unix_main.file_pool,
186 rp->vl_api_registration_pool_index
187 + socket_main.registration_pool,
188 (u8 *) & tmp, sizeof (tmp));
189 vl_socket_add_pending_output (rp->unix_file_index
190 + unix_main.file_pool,
191 rp->vl_api_registration_pool_index
192 + socket_main.registration_pool,
195 vl_msg_api_free ((void *) elem);
199 vl_socket_api_send_with_length (vl_api_registration_t * rp,
200 u8 * elem, u32 msg_length)
202 vl_socket_api_send_with_length_internal (rp, elem, msg_length,
207 vl_socket_api_send_with_length_no_free (vl_api_registration_t * rp,
208 u8 * elem, u32 msg_length)
210 vl_socket_api_send_with_length_internal (rp, elem, msg_length,
215 vl_free_socket_registration_index (u32 pool_index)
217 vl_api_registration_t *rp;
218 if (pool_is_free_index (socket_main.registration_pool, pool_index))
220 clib_warning ("main pool index %d already free", pool_index);
223 rp = pool_elt_at_index (socket_main.registration_pool, pool_index);
225 ASSERT (rp->registration_type != REGISTRATION_TYPE_FREE);
227 vec_free (rp->unprocessed_input);
228 vec_free (rp->output_vector);
229 rp->registration_type = REGISTRATION_TYPE_FREE;
230 pool_put (socket_main.registration_pool, rp);
234 socket_process_msg (unix_file_t * uf, vl_api_registration_t * rp,
237 u8 *the_msg = (u8 *) (input_v + sizeof (u32));
238 socket_main.current_uf = uf;
239 socket_main.current_rp = rp;
240 vl_msg_api_socket_handler (the_msg);
241 socket_main.current_uf = 0;
242 socket_main.current_rp = 0;
246 vl_socket_read_ready (unix_file_t * uf)
248 unix_main_t *um = &unix_main;
249 vl_api_registration_t *rp;
253 u32 save_input_buffer_length = vec_len (socket_main.input_buffer);
255 rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
257 n = read (uf->file_descriptor, socket_main.input_buffer,
258 vec_len (socket_main.input_buffer));
260 if (n <= 0 && errno != EAGAIN)
262 unix_file_del (um, uf);
264 if (!pool_is_free (socket_main.registration_pool, rp))
266 u32 index = rp - socket_main.registration_pool;
267 vl_free_socket_registration_index (index);
271 clib_warning ("client index %d already free?",
272 rp->vl_api_registration_pool_index);
277 _vec_len (socket_main.input_buffer) = n;
280 * Look for bugs here. This code is tricky because
281 * data read from a stream socket does honor message
282 * boundaries. In the case of a long message (>4K bytes)
283 * we have to do (at least) 2 reads, etc.
287 if (vec_len (rp->unprocessed_input))
289 vec_append (rp->unprocessed_input, socket_main.input_buffer);
290 msg_buffer = rp->unprocessed_input;
291 msg_len = rp->unprocessed_msg_length;
295 msg_buffer = socket_main.input_buffer;
301 /* Length may be split across two reads */
302 if (vec_len (msg_buffer) < sizeof (u32))
305 /* total length, including msg_len itself, in network byte order */
306 msg_len = clib_net_to_host_u32 (*((u32 *) msg_buffer));
309 /* Happens if the client sent msg_len == 0 */
312 clib_warning ("msg_len == 0");
316 /* We don't have the entire message yet. */
317 if (msg_len > vec_len (msg_buffer))
321 * if we were using the shared input buffer,
324 if (msg_buffer == socket_main.input_buffer)
326 ASSERT (vec_len (rp->unprocessed_input) == 0);
327 vec_validate (rp->unprocessed_input, vec_len (msg_buffer) - 1);
328 clib_memcpy (rp->unprocessed_input, msg_buffer,
329 vec_len (msg_buffer));
330 _vec_len (rp->unprocessed_input) = vec_len (msg_buffer);
332 _vec_len (socket_main.input_buffer) = save_input_buffer_length;
333 rp->unprocessed_msg_length = msg_len;
337 socket_process_msg (uf, rp, msg_buffer);
339 vec_delete (msg_buffer, msg_len, 0);
341 _vec_len (msg_buffer) = 0;
344 rp->unprocessed_msg_length = 0;
349 _vec_len (socket_main.input_buffer) = save_input_buffer_length;
355 vl_socket_add_pending_output (unix_file_t * uf,
356 vl_api_registration_t * rp,
357 u8 * buffer, uword buffer_bytes)
359 unix_main_t *um = &unix_main;
361 vec_add (rp->output_vector, buffer, buffer_bytes);
362 if (vec_len (rp->output_vector) > 0)
364 int skip_update = 0 != (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE);
365 uf->flags |= UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
367 um->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
372 socket_del_pending_output (unix_file_t * uf,
373 vl_api_registration_t * rp, uword n_bytes)
375 unix_main_t *um = &unix_main;
377 vec_delete (rp->output_vector, n_bytes, 0);
378 if (vec_len (rp->output_vector) <= 0)
380 int skip_update = 0 == (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE);
381 uf->flags &= ~UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
383 um->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
388 vl_socket_write_ready (unix_file_t * uf)
390 unix_main_t *um = &unix_main;
391 vl_api_registration_t *rp;
394 rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
396 /* Flush output vector. */
397 n = write (uf->file_descriptor,
398 rp->output_vector, vec_len (rp->output_vector));
403 clib_warning ("write error, close the file...\n");
405 unix_file_del (um, uf);
407 vl_free_socket_registration_index (rp - socket_main.registration_pool);
412 socket_del_pending_output (uf, rp, n);
418 vl_socket_error_ready (unix_file_t * uf)
420 vl_api_registration_t *rp;
421 unix_main_t *um = &unix_main;
423 rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
424 unix_file_del (um, uf);
425 vl_free_socket_registration_index (rp - socket_main.registration_pool);
431 socksvr_file_add (unix_main_t * um, int fd)
433 vl_api_registration_t *rp;
434 unix_file_t template = { 0 };
436 pool_get (socket_main.registration_pool, rp);
437 memset (rp, 0, sizeof (*rp));
439 template.read_function = vl_socket_read_ready;
440 template.write_function = vl_socket_write_ready;
441 template.error_function = vl_socket_error_ready;
442 template.file_descriptor = fd;
443 template.private_data = rp - socket_main.registration_pool;
445 rp->registration_type = REGISTRATION_TYPE_SOCKET_SERVER;
446 rp->vl_api_registration_pool_index = rp - socket_main.registration_pool;
447 rp->unix_file_index = unix_file_add (um, &template);
450 static clib_error_t *
451 socksvr_accept_ready (unix_file_t * uf)
453 unix_main_t *um = &unix_main;
454 struct sockaddr_in client_addr;
458 client_len = sizeof (client_addr);
461 * Supposedly acquires the non-blocking attrib from the
464 client_fd = accept (uf->file_descriptor,
465 (struct sockaddr *) &client_addr,
466 (socklen_t *) & client_len);
469 return clib_error_return_unix (0, "socksvr_accept_ready: accept");
471 socksvr_file_add (um, client_fd);
475 static clib_error_t *
476 socksvr_bogus_write (unix_file_t * uf)
478 clib_warning ("why am I here?");
483 * vl_api_sockclnt_create_t_handler
486 vl_api_sockclnt_create_t_handler (vl_api_sockclnt_create_t * mp)
488 vl_api_registration_t *regp;
489 vl_api_sockclnt_create_reply_t *rp;
492 regp = socket_main.current_rp;
494 ASSERT (regp->registration_type == REGISTRATION_TYPE_SOCKET_SERVER);
496 regp->name = format (0, "%s%c", mp->name, 0);
498 rp = vl_msg_api_alloc (sizeof (*rp));
499 rp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE_REPLY);
500 rp->handle = (uword) regp;
501 rp->index = (uword) regp->vl_api_registration_pool_index;
502 rp->context = mp->context;
503 rp->response = htonl (rv);
505 vl_msg_api_send (regp, (u8 *) rp);
509 * vl_api_sockclnt_delete_t_handler
512 vl_api_sockclnt_delete_t_handler (vl_api_sockclnt_delete_t * mp)
514 vl_api_registration_t *regp;
515 vl_api_sockclnt_delete_reply_t *rp;
517 if (!pool_is_free_index (socket_main.registration_pool, mp->index))
519 regp = pool_elt_at_index (socket_main.registration_pool, mp->index);
521 rp = vl_msg_api_alloc (sizeof (*rp));
522 rp->_vl_msg_id = htons (VL_API_SOCKCLNT_DELETE_REPLY);
523 rp->handle = mp->handle;
524 rp->response = htonl (1);
526 vl_msg_api_send (regp, (u8 *) rp);
528 unix_file_del (&unix_main, unix_main.file_pool + regp->unix_file_index);
530 vl_free_socket_registration_index (mp->index);
534 clib_warning ("unknown client ID %d", mp->index);
538 #define foreach_vlib_api_msg \
539 _(SOCKCLNT_CREATE, sockclnt_create) \
540 _(SOCKCLNT_DELETE, sockclnt_delete)
542 static clib_error_t *
543 socksvr_api_init (vlib_main_t * vm)
545 unix_main_t *um = &unix_main;
546 unix_file_t template = { 0 };
550 struct sockaddr_in serv_addr;
551 vl_api_registration_t *rp;
556 vl_msg_api_set_handlers(VL_API_##N, #n, \
557 vl_api_##n##_t_handler, \
559 vl_api_##n##_t_endian, \
560 vl_api_##n##_t_print, \
561 sizeof(vl_api_##n##_t), 1);
562 foreach_vlib_api_msg;
565 vec_resize (socket_main.input_buffer, 4096);
567 /* Set up non-blocking server socket on CLIENT_API_SERVER_PORT */
568 sockfd = socket (AF_INET, SOCK_STREAM, 0);
572 return clib_error_return_unix (0, "socket");
575 rv = ioctl (sockfd, FIONBIO, &one);
579 return clib_error_return_unix (0, "FIONBIO");
582 rv = setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (one));
586 return clib_error_return_unix (0, "SO_REUSEADDR");
589 bzero ((char *) &serv_addr, sizeof (serv_addr));
590 serv_addr.sin_family = AF_INET;
592 if (socket_main.bind_address)
593 bind_address = socket_main.bind_address;
595 bind_address = INADDR_LOOPBACK;
597 if (socket_main.portno)
598 portno = socket_main.portno;
600 portno = SOCKSVR_DEFAULT_PORT;
602 serv_addr.sin_port = clib_host_to_net_u16 (portno);
603 serv_addr.sin_addr.s_addr = clib_host_to_net_u32 (bind_address);
605 if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
608 return clib_error_return_unix (0, "bind");
611 rv = listen (sockfd, 5);
615 return clib_error_return_unix (0, "listen");
618 pool_get (socket_main.registration_pool, rp);
619 memset (rp, 0, sizeof (*rp));
621 rp->registration_type = REGISTRATION_TYPE_SOCKET_LISTEN;
623 template.read_function = socksvr_accept_ready;
624 template.write_function = socksvr_bogus_write;
625 template.file_descriptor = sockfd;
626 template.private_data = rp - socket_main.registration_pool;
628 rp->unix_file_index = unix_file_add (um, &template);
632 static clib_error_t *
633 socket_exit (vlib_main_t * vm)
635 unix_main_t *um = &unix_main;
636 vl_api_registration_t *rp;
638 /* Defensive driving in case something wipes out early */
639 if (socket_main.registration_pool)
643 pool_foreach (rp, socket_main.registration_pool, ({
644 unix_file_del (um, um->file_pool + rp->unix_file_index);
645 index = rp->vl_api_registration_pool_index;
646 vl_free_socket_registration_index (index);
654 VLIB_MAIN_LOOP_EXIT_FUNCTION (socket_exit);
656 static clib_error_t *
657 socksvr_config (vlib_main_t * vm, unformat_input_t * input)
661 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
663 if (unformat (input, "port %d", &portno))
665 socket_main.portno = portno;
669 return clib_error_return (0, "unknown input '%U'",
670 format_unformat_error, input);
673 return socksvr_api_init (vm);
676 VLIB_CONFIG_FUNCTION (socksvr_config, "socksvr");
678 /* argument in host byte order */
680 socksvr_set_port (u16 port)
682 socket_main.portno = port;
685 /* argument in host byte order */
687 socksvr_set_bind_address (u32 bind_address)
689 socket_main.bind_address = bind_address;
693 vlibsocket_init (vlib_main_t * vm)
698 VLIB_INIT_FUNCTION (vlibsocket_init);
701 * fd.io coding-style-patch-verification: ON
704 * eval: (c-set-style "gnu")