1 /*
2  * socket.c - socket management implementation
3  *
4  * Copyright (C) 2011-2013 Thien-Thi Nguyen
5  * Copyright (C) 2000, 2001, 2002, 2003 Stefan Jahn <stefan@lkcc.org>
6  * Copyright (C) 1999 Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
7  *
8  * This is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3, or (at your option)
11  * any later version.
12  *
13  * This software is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this package.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include "timidity.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <sys/types.h>
32 #include <signal.h>
33 #include <time.h>
34 
35 #if HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 
39 #if HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42 
43 #ifndef __MINGW32__
44 # include <sys/types.h>
45 # include <sys/socket.h>
46 # include <netdb.h>
47 #endif
48 
49 #include "networking-headers.h"
50 #include "libserveez/alloc.h"
51 #include "libserveez/util.h"
52 #include "libserveez/socket.h"
53 #include "libserveez/core.h"
54 #include "libserveez/pipe-socket.h"
55 #include "libserveez/tcp-socket.h"
56 #include "libserveez/server-core.h"
57 #include "libserveez/server.h"
58 #include "libserveez/binding.h"
59 
60 /*
61  * The number of currently connected sockets.
62  */
63 int svz_sock_connections = 0;
64 
65 /**
66  * Return the number of currently connected sockets.
67  */
68 int
svz_sock_nconnections(void)69 svz_sock_nconnections (void)
70 {
71   return svz_sock_connections;
72 }
73 
74 /*
75  * User-supplied functions called immediately prior to
76  * a @code{svz_socket_t} being freed.
77  */
78 static svz_array_t *prefree;
79 
80 /**
81  * Register (if @var{addsub} is non-zero), or unregister (otherwise)
82  * the function @var{fn} to be called immediately
83  * prior to a @code{svz_socket_t} being freed.
84  * @var{fn} is called with one arg @code{sock},
85  * and should not return anything.  In other words:
86  *
87  * @vindex svz_sock_prefree_fn
88  * @example
89  * typedef void (svz_sock_prefree_fn) (const svz_socket_t *);
90  * @end example
91  *
92  * Note the @code{const}!
93  */
94 void
svz_sock_prefree(int addsub,svz_sock_prefree_fn fn)95 svz_sock_prefree (int addsub, svz_sock_prefree_fn fn)
96 {
97   if (prefree == NULL)
98     prefree = svz_array_create (1, NULL);
99 
100   if (addsub)
101     /* Add.  */
102     svz_array_add (prefree, fn);
103   else
104     /* Subtract.  */
105     {
106       size_t i;
107 
108       for (i = 0; i < svz_array_size (prefree); i++)
109         if (fn == svz_array_get (prefree, i))
110           {
111             svz_array_del (prefree, i);
112             i--;
113           }
114     }
115 }
116 
117 /*
118  * This routine can be called if flood protection is wished for
119  * socket readers.  Return non-zero if the socket should be kicked
120  * because of flood.
121  *
122  * @strong{Note}: This always returns 0 if flood protection is not enabled.
123  */
124 int
svz_sock_flood_protect(svz_socket_t * sock,int num_read)125 svz_sock_flood_protect (svz_socket_t *sock, int num_read)
126 {
127 #ifdef ENABLE_FLOOD_PROTECTION
128   if (!(sock->flags & SVZ_SOFLG_NOFLOOD))
129     {
130       /*
131        * Since the default flood limit is 100 a reader can produce
132        * 5000 bytes per second before it gets kicked.
133        */
134       sock->flood_points += 1 + (num_read / 50);
135 
136       if (sock->flood_points > sock->flood_limit)
137         {
138           if (sock->kicked_socket)
139             sock->kicked_socket (sock, 0);
140           return -1;
141         }
142     }
143 #endif  /* ENABLE_FLOOD_PROTECTION */
144   return 0;
145 }
146 
147 /*
148  * The default function which gets called when a client shuts down
149  * its socket.  @var{sock} is the socket which was closed.
150  */
151 static int
maybe_log_disconnect(svz_socket_t * sock)152 maybe_log_disconnect (svz_socket_t *sock)
153 {
154 #if ENABLE_DEBUG
155   svz_log (SVZ_LOG_DEBUG, "socket id %d disconnected\n", sock->id);
156 #endif
157 
158   return 0;
159 }
160 
161 /*
162  * This routine gets called whenever data is read from a client socket
163  * accepted by any connection oriented protocol layer (TCP or PIPE).  We
164  * try to detect the data streams protocol here.
165  */
166 int
svz_sock_detect_proto(svz_socket_t * sock)167 svz_sock_detect_proto (svz_socket_t *sock)
168 {
169   size_t n;
170   svz_server_t *server;
171   svz_binding_t *binding;
172   svz_portcfg_t *port;
173   svz_array_t *bindings;
174 
175   /* return if there are no servers bound to this socket */
176   if (svz_sock_bindings (sock) == NULL)
177     return -1;
178 
179   /* get port configuration of parent */
180   port = svz_sock_portcfg (sock);
181 
182   /* go through each server stored in the data field of this socket */
183   bindings = svz_binding_filter (sock);
184   svz_array_foreach (bindings, binding, n)
185     {
186       server = binding->server;
187 
188       /* can occur if it is actually a packet oriented server */
189       if (server->detect_proto == NULL)
190         {
191           svz_log (SVZ_LOG_ERROR, "%s: no detect-proto routine\n",
192                    server->type->prefix);
193         }
194       /* call protocol detection routine of the server */
195       else if (server->detect_proto (server, sock))
196         {
197           svz_array_destroy (bindings);
198           sock->idle_func = NULL;
199           svz_sock_bindings_set (sock, NULL);
200           sock->cfg = server->cfg;
201           sock->port = binding->port;
202           if (!server->connect_socket)
203             return -1;
204           if (server->connect_socket (server, sock))
205             return -1;
206           if (sock->check_request == svz_sock_detect_proto)
207             {
208               svz_log (SVZ_LOG_ERROR, "%s: check-request callback unchanged\n",
209                        server->type->prefix);
210               sock->check_request = NULL;
211             }
212           if (sock->check_request)
213             return sock->check_request (sock);
214           return 0;
215         }
216     }
217   svz_array_destroy (bindings);
218 
219   /*
220    * Discard this socket if there were not any valid protocol
221    * detected and its receive buffer fill exceeds a maximum value.
222    */
223   if (sock->recv_buffer_fill > port->detection_fill)
224     {
225 #if ENABLE_DEBUG
226       svz_log (SVZ_LOG_DEBUG, "socket id %d detection failed\n", sock->id);
227 #endif
228       return -1;
229     }
230 
231   return 0;
232 }
233 
234 /*
235  * This @code{check_request} routine could be used by any protocol to
236  * detect and finally handle packets depending on a specific packet
237  * boundary.  The appropriate @code{handle_request} is called for each packet
238  * explicitly with the packet length inclusive the packet boundary.
239  */
240 static int
split_packet_and_dispatch(svz_socket_t * sock)241 split_packet_and_dispatch (svz_socket_t *sock)
242 {
243   int len = 0;
244   char *p, *packet, *end;
245 
246   packet = p = sock->recv_buffer;
247   end = p + sock->recv_buffer_fill - sock->boundary_size + 1;
248 
249   do
250     {
251       /* Find packet boundary in the receive buffer.  */
252       while (p < end && memcmp (p, sock->boundary, sock->boundary_size))
253         p++;
254 
255       /* Found?  */
256       if (p < end && !memcmp (p, sock->boundary, sock->boundary_size))
257         {
258           p += sock->boundary_size;
259           len += (p - packet);
260 
261           /* Call the handle request callback.  */
262           if (sock->handle_request)
263             {
264               if (sock->handle_request (sock, packet, p - packet))
265                 return -1;
266             }
267           packet = p;
268         }
269     }
270   while (p < end);
271 
272   /* Shuffle data in the receive buffer around.  */
273   svz_sock_reduce_recv (sock, len);
274 
275   return 0;
276 }
277 
278 /*
279  * This is just the same routine as above, but optimized for one byte
280  * packet delimiters.
281  */
282 static int
split_packet_unibyte_and_dispatch(svz_socket_t * sock)283 split_packet_unibyte_and_dispatch (svz_socket_t *sock)
284 {
285   int len = 0;
286   char *p, *packet, *end;
287 
288   packet = p = sock->recv_buffer;
289   end = p + sock->recv_buffer_fill;
290 
291   do
292     {
293       /* Find packet boundary in the receive buffer.  */
294       while (p < end && *p != *sock->boundary)
295         p++;
296 
297       /* Found?  */
298       if (p < end && *p == *sock->boundary)
299         {
300           p++;
301           len += (p - packet);
302 
303           /* Call the handle request callback.  */
304           if (sock->handle_request)
305             {
306               if (sock->handle_request (sock, packet, p - packet))
307                 return -1;
308             }
309           packet = p;
310         }
311     }
312   while (p < end);
313 
314   /* Shuffle data in the receive buffer around.  */
315   svz_sock_reduce_recv (sock, len);
316 
317   return 0;
318 }
319 
320 /*
321  * The following routine checks for fixed size packets in the receive queue
322  * of the socket structure @var{sock} and calls the @code{handle_request}
323  * callback if so.  It is possible to change the fixed packet size in the
324  * @code{handle_request} callback dynamically.
325  */
326 static int
split_packet_fixed_and_dispatch(svz_socket_t * sock)327 split_packet_fixed_and_dispatch (svz_socket_t *sock)
328 {
329   int len = 0;
330   char *p, *packet, *end;
331 
332   packet = p = sock->recv_buffer;
333   end = p + sock->recv_buffer_fill;
334 
335   while (p + sock->boundary_size < end)
336     {
337       len += sock->boundary_size;
338       p += sock->boundary_size;
339 
340       /* Call the handle request callback.  */
341       if (sock->handle_request)
342         {
343           if (sock->handle_request (sock, packet, sock->boundary_size))
344             return -1;
345         }
346       packet = p;
347     }
348 
349   /* Shuffle data in the receive buffer around.  */
350   svz_sock_reduce_recv (sock, len);
351 
352   return 0;
353 }
354 
355 /**
356  * Check for the kind of packet delimiter within @var{sock} and
357  * and assign one of the default @code{check_request} routines
358  * (one or more byte delimiters or a fixed size).
359  *
360  * Afterwards this function will never ever be called again because
361  * the callback gets overwritten here.
362  */
363 int
svz_sock_check_request(svz_socket_t * sock)364 svz_sock_check_request (svz_socket_t *sock)
365 {
366   if (sock->boundary_size <= 0)
367     {
368       svz_log (SVZ_LOG_ERROR, "invalid boundary size: %d\n", sock->boundary_size);
369       return -1;
370     }
371 
372   if (sock->boundary == NULL)
373     sock->check_request = split_packet_fixed_and_dispatch;
374   else if (sock->boundary_size > 1)
375     sock->check_request = split_packet_and_dispatch;
376   else
377     sock->check_request = split_packet_unibyte_and_dispatch;
378 
379   return sock->check_request (sock);
380 }
381 
382 /*
383  * Allocate a structure of type @code{svz_socket_t} and initialize its data
384  * fields.  Assign some of the default callbacks for TCP connections.
385  */
386 svz_socket_t *
svz_sock_alloc(void)387 svz_sock_alloc (void)
388 {
389   svz_socket_t *sock;
390   char *in;
391   char *out;
392 
393   sock = svz_calloc (sizeof (svz_socket_t));
394   in = svz_malloc (RECV_BUF_SIZE);
395   out = svz_malloc (SEND_BUF_SIZE);
396 
397   sock->proto = SVZ_SOFLG_INIT;
398   sock->flags = SVZ_SOFLG_INIT | SVZ_SOFLG_INBUF | SVZ_SOFLG_OUTBUF;
399   sock->userflags = SVZ_SOFLG_INIT;
400   sock->file_desc = -1;
401   sock->sock_desc = (svz_t_socket) -1;
402   svz_invalidate_handle (&sock->pipe_desc[SVZ_READ]);
403   svz_invalidate_handle (&sock->pipe_desc[SVZ_WRITE]);
404   svz_invalidate_handle (&sock->pid);
405 
406   sock->read_socket = svz_tcp_read_socket;
407   sock->read_socket_oob = svz_tcp_recv_oob;
408   sock->write_socket = svz_tcp_write_socket;
409   sock->check_request = svz_sock_detect_proto;
410   sock->disconnected_socket = maybe_log_disconnect;
411 
412   sock->recv_buffer = in;
413   sock->recv_buffer_size = RECV_BUF_SIZE;
414   sock->send_buffer = out;
415   sock->send_buffer_size = SEND_BUF_SIZE;
416   sock->last_send = time (NULL);
417   sock->last_recv = time (NULL);
418 
419 #if ENABLE_FLOOD_PROTECTION
420   sock->flood_limit = 100;
421 #endif /* ENABLE_FLOOD_PROTECTION */
422 
423   return sock;
424 }
425 
426 /**
427  * Resize the send and receive buffers for the socket @var{sock}.
428  * @var{send_buf_size} is the new size for the send buffer,
429  * @var{recv_buf_size} for the receive buffer.  Note that data may be lost
430  * when the buffers shrink.  For a new buffer size of 0 the buffer is
431  * freed and the pointer set to NULL.
432  */
433 int
svz_sock_resize_buffers(svz_socket_t * sock,int send_buf_size,int recv_buf_size)434 svz_sock_resize_buffers (svz_socket_t *sock,
435                          int send_buf_size, int recv_buf_size)
436 {
437   char *send, *recv;
438 
439   if (send_buf_size == 0)
440     {
441       svz_free (sock->send_buffer);
442       send = NULL;
443     }
444   else if (sock->send_buffer_size != send_buf_size)
445     send = svz_realloc (sock->send_buffer, send_buf_size);
446   else
447     send = sock->send_buffer;
448 
449   if (recv_buf_size == 0)
450     {
451       svz_free (sock->recv_buffer);
452       recv = NULL;
453     }
454   else if (sock->recv_buffer_size != recv_buf_size)
455     recv = svz_realloc (sock->recv_buffer, recv_buf_size);
456   else
457     recv = sock->recv_buffer;
458 
459   sock->send_buffer = send;
460   sock->recv_buffer = recv;
461   sock->send_buffer_size = send_buf_size;
462   sock->recv_buffer_size = recv_buf_size;
463 
464   return 0;
465 }
466 
467 /*
468  * Free the socket structure @var{sock}.  Return a non-zero value on error.
469  */
470 int
svz_sock_free(svz_socket_t * sock)471 svz_sock_free (svz_socket_t *sock)
472 {
473   size_t i = svz_array_size (prefree);
474   svz_sock_prefree_fn *fn;
475 
476   while (i--)
477     {
478       fn = svz_array_get (prefree, i);
479       fn (sock);
480     }
481 
482   if (sock->remote_addr)
483     svz_free (sock->remote_addr);
484   if (sock->local_addr)
485     svz_free (sock->local_addr);
486   if (sock->recv_buffer)
487     svz_free (sock->recv_buffer);
488   if (sock->send_buffer)
489     svz_free (sock->send_buffer);
490   if (sock->recv_pipe)
491     svz_free (sock->recv_pipe);
492   if (sock->send_pipe)
493     svz_free (sock->send_pipe);
494 
495 #ifdef __MINGW32__
496   if (sock->overlap[SVZ_READ])
497     svz_free (sock->overlap[SVZ_READ]);
498   if (sock->overlap[SVZ_WRITE])
499     svz_free (sock->overlap[SVZ_WRITE]);
500 #endif /* __MINGW32__ */
501 
502   svz_free (sock);
503 
504   return 0;
505 }
506 
507 /*
508  * Get local and remote addresses and ports of socket @var{sock} and save
509  * them into the socket structure.
510  */
511 int
svz_sock_intern_connection_info(svz_socket_t * sock)512 svz_sock_intern_connection_info (svz_socket_t *sock)
513 {
514   struct sockaddr_in s;
515   socklen_t size = sizeof (s);
516   in_port_t port;
517   in_addr_t addr;
518 
519   if (!getpeername (sock->sock_desc, (struct sockaddr *) &s, &size))
520     {
521       addr = s.sin_addr.s_addr;
522       port = s.sin_port;
523     }
524   else
525     {
526       addr = INADDR_ANY;
527       port = 0;
528     }
529   sock->remote_port = port;
530   SVZ_SET_ADDR (sock->remote_addr, AF_INET, &addr);
531 
532   size = sizeof (s);
533   if (!getsockname (sock->sock_desc, (struct sockaddr *) &s, &size))
534     {
535       addr = s.sin_addr.s_addr;
536       port = s.sin_port;
537     }
538   else
539     {
540       addr = INADDR_ANY;
541       port = 0;
542     }
543   sock->local_port = port;
544   SVZ_SET_ADDR (sock->local_addr, AF_INET, &addr);
545 
546   return 0;
547 }
548 
549 /*
550  * Create a socket structure from the file descriptor @var{fd}.  Set the
551  * socket descriptor to non-blocking I/O.  Return @code{NULL} on errors.
552  */
553 svz_socket_t *
svz_sock_create(int fd)554 svz_sock_create (int fd)
555 {
556   svz_socket_t *sock;
557 
558   if (svz_fd_nonblock (fd) != 0)
559     return NULL;
560   if (svz_fd_cloexec (fd) != 0)
561     return NULL;
562 
563   if ((sock = svz_sock_alloc ()) != NULL)
564     {
565       svz_sock_unique_id (sock);
566       sock->sock_desc = fd;
567       sock->flags |= (SVZ_SOFLG_CONNECTED | SVZ_SOFLG_SOCK);
568       svz_sock_intern_connection_info (sock);
569     }
570   return sock;
571 }
572 
573 /*
574  * Disconnect the socket @var{sock} from the network and calls the disconnect
575  * function for the socket if set.  Return a non-zero value on errors.
576  */
577 int
svz_sock_disconnect(svz_socket_t * sock)578 svz_sock_disconnect (svz_socket_t *sock)
579 {
580   /* shutdown client connection */
581   if (sock->flags & SVZ_SOFLG_CONNECTED)
582     {
583       if (!(sock->flags & SVZ_SOFLG_NOSHUTDOWN))
584         {
585           if (shutdown (sock->sock_desc, 2) < 0)
586             svz_log_net_error ("shutdown");
587         }
588       svz_sock_connections--;
589     }
590 
591   /* close the server/client socket */
592   if (svz_closesocket (sock->sock_desc) < 0)
593     svz_log_net_error ("close");
594 
595 #if ENABLE_DEBUG
596   svz_log (SVZ_LOG_DEBUG, "socket %d disconnected\n", sock->sock_desc);
597 #endif
598 
599   sock->sock_desc = INVALID_SOCKET;
600   return 0;
601 }
602 
603 /**
604  * Write @var{len} bytes from the memory location pointed to by @var{buf}
605  * to the output buffer of the socket @var{sock}.  Also try to flush the
606  * buffer to the socket of @var{sock} if possible.  Return a non-zero value
607  * on error, which normally means a buffer overflow.
608  */
609 int
svz_sock_write(svz_socket_t * sock,char * buf,int len)610 svz_sock_write (svz_socket_t *sock, char *buf, int len)
611 {
612   int ret;
613   int space;
614   int orig_len = len;
615 
616   if (sock->flags & SVZ_SOFLG_KILLED)
617     return 0;
618 
619   while (len > 0)
620     {
621       /* Try to flush the queue of this socket.  */
622       if (sock->write_socket && !sock->unavailable &&
623           sock->flags & SVZ_SOFLG_CONNECTED && sock->send_buffer_fill)
624         {
625           /* TCP-specific hack: If ‘SVZ_SOFLG_FINAL_WRITE’ is set, but
626              we are flushing from a previous write, temporarily inhibit
627              it around the next call to ‘sock->write_socket’ to prevent
628              it (specifically, ‘svz_tcp_write_socket’) from scheduling a
629              shutdown prematurely (with consequent early return from
630              this function, silently dropping the current write).  */
631           int inhibitp = (sock->flags & SVZ_SOFLG_FINAL_WRITE)
632             && svz_tcp_write_socket == sock->write_socket
633             && orig_len == len;
634 
635           if (inhibitp)
636             sock->flags &= ~SVZ_SOFLG_FINAL_WRITE;
637           if ((ret = sock->write_socket (sock)) != 0)
638             return ret;
639           if (inhibitp)
640             sock->flags |= SVZ_SOFLG_FINAL_WRITE;
641         }
642 
643       if (sock->send_buffer_fill >= sock->send_buffer_size)
644         {
645           /* Queue is full, unlucky socket or pipe ...  */
646           if (sock->flags & SVZ_SOFLG_SEND_PIPE)
647             svz_log (SVZ_LOG_ERROR,
648                      "send buffer overflow on pipe (%d-%d) (id %d)\n",
649                      sock->pipe_desc[SVZ_READ], sock->pipe_desc[SVZ_WRITE],
650                      sock->id);
651           else
652             svz_log (SVZ_LOG_ERROR,
653                      "send buffer overflow on socket %d (id %d)\n",
654                      sock->sock_desc, sock->id);
655 
656           if (sock->kicked_socket)
657             sock->kicked_socket (sock, 1);
658 
659           return -1;
660         }
661 
662       /* Now move as much of BUF into the send queue.  */
663       if (sock->send_buffer_fill + len < sock->send_buffer_size)
664         {
665           memcpy (sock->send_buffer + sock->send_buffer_fill, buf, len);
666           sock->send_buffer_fill += len;
667           len = 0;
668         }
669       else
670         {
671           space = sock->send_buffer_size - sock->send_buffer_fill;
672           memcpy (sock->send_buffer + sock->send_buffer_fill, buf, space);
673           sock->send_buffer_fill += space;
674           len -= space;
675           buf += space;
676         }
677     }
678 
679   return 0;
680 }
681 
682 /**
683  * Print a formatted string on the socket @var{sock}.  @var{fmt} is the
684  * @code{printf}-style format string, which describes how to format the
685  * optional arguments.
686  */
687 int
svz_sock_printf(svz_socket_t * sock,const char * fmt,...)688 svz_sock_printf (svz_socket_t *sock, const char *fmt, ...)
689 {
690   va_list args;
691   static char buffer[VSNPRINTF_BUF_SIZE];
692   unsigned len;
693 
694   if (sock->flags & SVZ_SOFLG_KILLED)
695     return 0;
696 
697   va_start (args, fmt);
698   len = vsnprintf (buffer, VSNPRINTF_BUF_SIZE, fmt, args);
699   va_end (args);
700 
701   /* Just to be sure...  */
702   if (len > sizeof (buffer))
703     len = sizeof (buffer);
704 
705   return svz_sock_write (sock, buffer, len);
706 }
707 
708 /*
709  * If @code{svz_socket_unavailable_error_p} returns non-zero, set @var{sock}
710  * member @code{unavailable} to time @var{t} (or current time if zero) plus
711  * @var{relax} seconds and return 1.  Otherwise, do nothing and return 0.
712  */
713 int
svz_wait_if_unavailable(svz_socket_t * sock,unsigned int relax)714 svz_wait_if_unavailable (svz_socket_t *sock, unsigned int relax)
715 {
716   if (svz_socket_unavailable_error_p ())
717     {
718       sock->unavailable = relax + time (NULL);
719       return 1;
720     }
721   return 0;
722 }
723 
724 /**
725  * Shorten the receive buffer of @var{sock} by @var{len} bytes.
726  */
727 void
svz_sock_reduce_recv(svz_socket_t * sock,int len)728 svz_sock_reduce_recv (svz_socket_t *sock, int len)
729 {
730   /* FIXME: What about the ‘0 > len’ case?  */
731   if (len && sock->recv_buffer_fill > len)
732     memmove (sock->recv_buffer, sock->recv_buffer + len,
733              sock->recv_buffer_fill - len);
734   sock->recv_buffer_fill -= len;
735 }
736 
737 /**
738  * Reduce the send buffer of @var{sock} by @var{len} bytes.
739  */
740 void
svz_sock_reduce_send(svz_socket_t * sock,int len)741 svz_sock_reduce_send (svz_socket_t *sock, int len)
742 {
743   /* FIXME: What about the ‘0 > len’ case?  */
744   if (len && sock->send_buffer_fill > len)
745     memmove (sock->send_buffer, sock->send_buffer + len,
746              sock->send_buffer_fill - len);
747   sock->send_buffer_fill -= len;
748 }
749