1 /*
2  * guile-api.c - export additional Serveez functionality to Guile
3  *
4  * Copyright (C) 2011-2013 Thien-Thi Nguyen
5  * Copyright (C) 2001, 2002, 2003 Stefan Jahn <stefan@lkcc.org>
6  *
7  * This is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this package.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #if ENABLE_GUILE_SERVER
24 
25 #include <string.h>
26 #include <errno.h>
27 
28 #ifndef __MINGW32__
29 # include <sys/socket.h>
30 # include <netdb.h>
31 #endif
32 
33 #if HAVE_RPC_RPCENT_H
34 # include <rpc/rpcent.h>
35 #endif
36 #if HAVE_RPC_RPC_H
37 # include <rpc/rpc.h>
38 #endif
39 #if HAVE_RPC_CLNT_SOC_H
40 # include <rpc/clnt_soc.h>
41 #endif
42 #if HAVE_RPC_PMAP_CLNT_H
43 # include <rpc/pmap_clnt.h>
44 #endif
45 #if HAVE_RPC_PMAP_PROT_H
46 # include <rpc/pmap_prot.h>
47 #endif
48 #if HAVE_UNISTD_H
49 # include <unistd.h>
50 #endif
51 #if HAVE_IO_H
52 # include <io.h>
53 #endif
54 
55 #include <libguile.h>
56 #include "networking-headers.h"
57 #include "libserveez.h"
58 #include "guile-missing.h"
59 
60 /* Validate network port range.  */
61 #define VALIDATE_NETPORT(port, cell, arg) do {                       \
62     (port) = gi_scm2long (cell);                                     \
63     if ((port) < 0 || (port) >= 65536) SCM_OUT_OF_RANGE (arg, cell); \
64   } while (0)
65 
66 
67 /* Converts the given hostname @var{host} into a Internet address in host
68    byte order and stores it into @var{addr}.  Returns zero on success.  This
69    is a blocking operation.  */
70 static int
guile_resolve(char * host,in_addr_t * addr)71 guile_resolve (char *host, in_addr_t *addr)
72 {
73   struct hostent *ent;
74 
75   if ((ent = gethostbyname (host)) == NULL)
76     return -1;
77   if (ent->h_addrtype == AF_INET)
78     {
79       memcpy (addr, ent->h_addr_list[0], ent->h_length);
80       return 0;
81     }
82   return -1;
83 }
84 
85 SCM_DEFINE
86 (guile_sock_connect,
87  "svz:sock:connect", 2, 1, 0,
88  (SCM host, SCM proto, SCM port),
89  doc: /***********
90 Establish a network connection to the given @var{host} [ :@var{port} ].
91 If @var{proto} equals @code{PROTO_ICMP} the @var{port} argument is
92 ignored.  Valid identifiers for @var{proto} are @code{PROTO_TCP},
93 @code{PROTO_UDP} and @code{PROTO_ICMP}.  The @var{host} argument must be
94 either a string in dotted decimal form, a valid hostname or an exact number
95 in host byte order.  When giving a hostname this operation might block.
96 The @var{port} argument must be an exact number in the range from
97 0 to 65535, also in host byte order.  Return a valid @code{#<svz-socket>}
98 or @code{#f} on failure.  */)
99 {
100 #define FUNC_NAME s_guile_sock_connect
101   svz_socket_t *sock;
102   in_addr_t v4addr;
103   svz_address_t *xhost;
104   in_port_t xport = 0;
105   long p;
106   int xproto;
107   struct sockaddr_in addr;
108   SCM ret = SCM_BOOL_F;
109 
110   SCM_ASSERT_TYPE (gi_exactp (host) || gi_stringp (host),
111                    host, SCM_ARG1, FUNC_NAME, "string or exact");
112   ASSERT_EXACT (2, proto);
113 
114   /* Extract host to connect to.  */
115   if (gi_exactp (host))
116     v4addr = htonl (gi_scm2int (host));
117   else
118     {
119       char str[128];
120 
121       GI_GET_XREP (str, host);
122       if (svz_inet_aton (str, &addr) == -1)
123         {
124           if (guile_resolve (str, &v4addr) == -1)
125             {
126               guile_error ("%s: IP in dotted decimals or hostname expected",
127                            FUNC_NAME);
128               return ret;
129             }
130         }
131       else
132         v4addr = addr.sin_addr.s_addr;
133     }
134   xhost = svz_address_make (AF_INET, &v4addr);
135 
136   /* Extract protocol to use.  */
137   xproto = gi_scm2int (proto);
138 
139   /* Find out about given port.  */
140   if (BOUNDP (port))
141     {
142       ASSERT_EXACT (3, port);
143       VALIDATE_NETPORT (p, port, SCM_ARG3);
144       xport = htons (p);
145     }
146 
147   /* Depending on the requested protocol; create different kinds of
148      socket structures.  */
149   switch (xproto)
150     {
151     case SVZ_PROTO_TCP:
152       sock = svz_tcp_connect (xhost, xport);
153       break;
154     case SVZ_PROTO_UDP:
155       sock = svz_udp_connect (xhost, xport);
156       break;
157     case SVZ_PROTO_ICMP:
158       sock = svz_icmp_connect (xhost, xport, SVZ_ICMP_SERVEEZ);
159       break;
160     default:
161       SCM_OUT_OF_RANGE (SCM_ARG2, proto);
162     }
163   svz_free (xhost);
164 
165   if (sock == NULL)
166     return ret;
167 
168   sock->disconnected_socket = guile_func_disconnected_socket;
169   return socket_smob (sock);
170 #undef FUNC_NAME
171 }
172 
173 #if GUILE_MISSING_inet_ntoa
174 SCM_DEFINE
175 (guile_svz_inet_ntoa,
176  "inet-ntoa", 1, 0, 0,
177  (SCM address),
178  doc: /***********
179 Convert the Internet host address
180 @var{address} given in network byte order to a string in standard
181 numbers-and-dots notation.  */)
182 {
183 #define FUNC_NAME s_guile_svz_inet_ntoa
184   char *str;
185   ASSERT_EXACT (1, address);
186   str = svz_inet_ntoa (gi_scm2ulong (address));
187   return gi_string2scm (str);
188 #undef FUNC_NAME
189 }
190 #endif  /* GUILE_MISSING_inet_ntoa */
191 
192 #if GUILE_MISSING_inet_aton
193 SCM_DEFINE
194 (guile_svz_inet_aton,
195  "inet-aton", 1, 0, 0,
196  (SCM address),
197  doc: /***********
198 Convert the Internet host address @var{address} from the standard
199 numbers-and-dots notation into binary data in network byte order.
200 Return @code{#f} if the address is invalid.  */)
201 {
202 #define FUNC_NAME s_guile_svz_inet_aton
203   struct sockaddr_in addr;
204   char str[48];
205 
206   ASSERT_STRING (1, address);
207   GI_GET_XREP (str, address);
208   if (svz_inet_aton (str, &addr) == -1)
209     {
210       guile_error ("%s: IP address in dotted decimals expected", FUNC_NAME);
211       return SCM_BOOL_F;
212     }
213   return gi_nnint2scm (addr.sin_addr.s_addr);
214 #undef FUNC_NAME
215 }
216 #endif  /* GUILE_MISSING_inet_aton */
217 
218 #if GUILE_MISSING_ntohl
219 SCM_DEFINE
220 (guile_svz_ntohl,
221  "ntohl", 1, 0, 0,
222  (SCM netlong),
223  doc: /***********
224 Convert the 32 bit long integer
225 @var{netlong} from network byte order to host byte order.  */)
226 {
227 #define FUNC_NAME s_guile_svz_ntohl
228   ASSERT_EXACT (1, netlong);
229   return gi_nnint2scm (ntohl (gi_scm2ulong (netlong)));
230 #undef FUNC_NAME
231 }
232 #endif  /* GUILE_MISSING_ntohl */
233 
234 #if GUILE_MISSING_htonl
235 SCM_DEFINE
236 (guile_svz_htonl,
237  "htonl", 1, 0, 0,
238  (SCM hostlong),
239  doc: /***********
240 Convert the 32 bit long integer
241 @var{hostlong} from host byte order to network byte order.  */)
242 {
243 #define FUNC_NAME s_guile_svz_htonl
244   ASSERT_EXACT (1, hostlong);
245   return gi_nnint2scm (htonl (gi_scm2ulong (hostlong)));
246 #undef FUNC_NAME
247 }
248 #endif  /* GUILE_MISSING_htonl */
249 
250 #if GUILE_MISSING_ntohs
251 SCM_DEFINE
252 (guile_svz_ntohs,
253  "ntohs", 1, 0, 0,
254  (SCM netshort),
255  doc: /***********
256 Convert the 16 bit short integer
257 @var{netshort} from network byte order to host byte order.  */)
258 {
259 #define FUNC_NAME s_guile_svz_ntohs
260   long i;
261   ASSERT_EXACT (1, netshort);
262   VALIDATE_NETPORT (i, netshort, SCM_ARG1);
263   return gi_integer2scm (ntohs (i));
264 #undef FUNC_NAME
265 }
266 #endif  /* GUILE_MISSING_ntohs */
267 
268 #if GUILE_MISSING_htons
269 SCM_DEFINE
270 (guile_svz_htons,
271  "htons", 1, 0, 0,
272  (SCM hostshort),
273  doc: /***********
274 Convert the 16 bit short integer
275 @var{hostshort} from host byte order to network byte order.  */)
276 {
277 #define FUNC_NAME s_guile_svz_htons
278   long i;
279   ASSERT_EXACT (1, hostshort);
280   VALIDATE_NETPORT (i, hostshort, SCM_ARG1);
281   return gi_integer2scm (htons (i));
282 #undef FUNC_NAME
283 }
284 #endif  /* GUILE_MISSING_htons */
285 
286 SCM_DEFINE
287 (guile_sock_receive_buffer,
288  "svz:sock:receive-buffer", 1, 0, 0,
289  (SCM sock),
290  doc: /***********
291 Return the receive buffer of the
292 socket @var{sock} as a binary smob.  */)
293 {
294 #define FUNC_NAME s_guile_sock_receive_buffer
295   svz_socket_t *xsock;
296   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
297   return guile_data_to_bin (xsock->recv_buffer, xsock->recv_buffer_fill);
298 #undef FUNC_NAME
299 }
300 
301 SCM_DEFINE
302 (guile_sock_receive_buffer_size,
303  "svz:sock:receive-buffer-size", 1, 1, 0,
304  (SCM sock, SCM size),
305  doc: /***********
306 Return the current receive buffers size and fill status in bytes of
307 the socket @var{sock} as a pair of exact numbers.  If the optional
308 argument @var{size} is given, set the receive buffer to the
309 specified size in bytes.  */)
310 {
311 #define FUNC_NAME s_guile_sock_receive_buffer_size
312   svz_socket_t *xsock;
313   int len;
314 
315   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
316   if (BOUNDP (size))
317     {
318       ASSERT_EXACT (2, size);
319       len = gi_scm2int (size);
320       svz_sock_resize_buffers (xsock, xsock->send_buffer_size, len);
321     }
322   return scm_cons (gi_integer2scm (xsock->recv_buffer_size),
323                    gi_integer2scm (xsock->recv_buffer_fill));
324 #undef FUNC_NAME
325 }
326 
327 SCM_DEFINE
328 (guile_sock_send_buffer,
329  "svz:sock:send-buffer", 1, 0, 0,
330  (SCM sock),
331  doc: /***********
332 Return the send buffer of the
333 socket @var{sock} as a binary smob.  */)
334 {
335 #define FUNC_NAME s_guile_sock_send_buffer
336   svz_socket_t *xsock;
337   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
338   return guile_data_to_bin (xsock->send_buffer, xsock->send_buffer_fill);
339 #undef FUNC_NAME
340 }
341 
342 SCM_DEFINE
343 (guile_sock_send_buffer_size,
344  "svz:sock:send-buffer-size", 1, 1, 0,
345  (SCM sock, SCM size),
346  doc: /***********
347 Return the current send buffer size and fill status in
348 bytes of the socket @var{sock} as a pair of exact numbers.  If the
349 optional argument @var{size} is given, set the send buffer to
350 the specified size in bytes.  */)
351 {
352 #define FUNC_NAME s_guile_sock_send_buffer_size
353   svz_socket_t *xsock;
354   int len;
355 
356   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
357   if (BOUNDP (size))
358     {
359       ASSERT_EXACT (2, size);
360       len = gi_scm2int (size);
361       svz_sock_resize_buffers (xsock, len, xsock->recv_buffer_size);
362     }
363   return scm_cons (gi_integer2scm (xsock->send_buffer_size),
364                    gi_integer2scm (xsock->send_buffer_fill));
365 #undef FUNC_NAME
366 }
367 
368 SCM_DEFINE
369 (guile_sock_receive_buffer_reduce,
370  "svz:sock:receive-buffer-reduce", 1, 1, 0,
371  (SCM sock, SCM length),
372  doc: /***********
373 Dequeue @var{length} bytes from the receive buffer of the
374 socket @var{sock}, or all bytes if @var{length} is omitted.
375 Return the number of bytes actually shuffled away.  */)
376 {
377 #define FUNC_NAME s_guile_sock_receive_buffer_reduce
378   svz_socket_t *xsock;
379   int len;
380 
381   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
382 
383   /* Check if second length argument is given.  */
384   if (BOUNDP (length))
385     {
386       ASSERT_EXACT (2, length);
387       len = gi_scm2int (length);
388       if (len < 0 || len > xsock->recv_buffer_fill)
389         SCM_OUT_OF_RANGE (SCM_ARG2, length);
390     }
391   else
392     {
393       len = xsock->recv_buffer_fill;
394     }
395   svz_sock_reduce_recv (xsock, len);
396   return gi_integer2scm (len);
397 #undef FUNC_NAME
398 }
399 
400 SCM_DEFINE
401 (guile_sock_remote_address,
402  "svz:sock:remote-address", 1, 1, 0,
403  (SCM sock, SCM address),
404  doc: /***********
405 Return the current remote address as a pair like
406 @code{(host . port)} with both entries in network byte order.  If you pass
407 the optional argument @var{address}, you can set the remote address of
408 the socket @var{sock}.  */)
409 {
410 #define FUNC_NAME s_guile_sock_remote_address
411   svz_socket_t *xsock;
412   in_addr_t v4addr;
413   long port;
414   SCM pair;
415 
416   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
417   svz_address_to (&v4addr, xsock->remote_addr);
418   pair = scm_cons (gi_nnint2scm (v4addr),
419                    gi_integer2scm ((int) xsock->remote_port));
420   if (BOUNDP (address))
421     {
422       SCM_ASSERT_TYPE (SCM_PAIRP (address) && gi_exactp (SCM_CAR (address))
423                        && gi_exactp (SCM_CDR (address)), address, SCM_ARG2,
424                        FUNC_NAME, "pair of exact");
425       VALIDATE_NETPORT (port, SCM_CDR (address), SCM_ARG2);
426       v4addr = gi_scm2ulong (SCM_CAR (address));
427       SVZ_SET_ADDR (xsock->remote_addr, AF_INET, &v4addr);
428       xsock->remote_port = port;
429     }
430   return pair;
431 #undef FUNC_NAME
432 }
433 
434 SCM_DEFINE
435 (guile_sock_local_address,
436  "svz:sock:local-address", 1, 1, 0,
437  (SCM sock, SCM address),
438  doc: /***********
439 Return the current local address as a pair like
440 @code{(host . port)} with both entries in network byte order.  If you pass
441 the optional argument @var{address}, you can set the local address of
442 the socket @var{sock}.  */)
443 {
444 #define FUNC_NAME s_guile_sock_local_address
445   svz_socket_t *xsock;
446   in_addr_t v4addr;
447   long port;
448   SCM pair;
449 
450   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
451   svz_address_to (&v4addr, xsock->local_addr);
452   pair = scm_cons (gi_nnint2scm (v4addr),
453                    gi_integer2scm ((int) xsock->local_port));
454   if (BOUNDP (address))
455     {
456       SCM_ASSERT_TYPE (SCM_PAIRP (address) && gi_exactp (SCM_CAR (address))
457                        && gi_exactp (SCM_CDR (address)), address, SCM_ARG2,
458                        FUNC_NAME, "pair of exact");
459       VALIDATE_NETPORT (port, SCM_CDR (address), SCM_ARG2);
460       v4addr = gi_scm2ulong (SCM_CAR (address));
461       SVZ_SET_ADDR (xsock->local_addr, AF_INET, &v4addr);
462       xsock->local_port = port;
463     }
464   return pair;
465 #undef FUNC_NAME
466 }
467 
468 SCM_DEFINE
469 (guile_sock_parent,
470  "svz:sock:parent", 1, 1, 0,
471  (SCM sock, SCM parent),
472  doc: /***********
473 Return the given socket's @var{sock} parent and optionally set it to the
474 socket @var{parent}.  Return either a valid
475 @code{#<svz-socket>} object or an empty list.  */)
476 {
477 #define FUNC_NAME s_guile_sock_parent
478   SCM oparent = SCM_EOL;
479   svz_socket_t *xsock, *xparent;
480 
481   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
482   if ((xparent = svz_sock_getparent (xsock)) != NULL)
483     oparent = socket_smob (xparent);
484   if (BOUNDP (parent))
485     {
486       CHECK_SMOB_ARG (socket, parent, SCM_ARG2, "svz-socket", xparent);
487       svz_sock_setparent (xsock, xparent);
488     }
489   return oparent;
490 #undef FUNC_NAME
491 }
492 
493 SCM_DEFINE
494 (guile_sock_referrer,
495  "svz:sock:referrer", 1, 1, 0,
496  (SCM sock, SCM referrer),
497  doc: /***********
498 Return the given socket's @var{sock} referrer and optionally set it to the
499 socket @var{referrer}.  Return either a valid
500 @code{#<svz-socket>} or an empty list.  */)
501 {
502 #define FUNC_NAME s_guile_sock_referrer
503   SCM oreferrer = SCM_EOL;
504   svz_socket_t *xsock, *xreferrer;
505 
506   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
507   if ((xreferrer = svz_sock_getreferrer (xsock)) != NULL)
508     oreferrer = socket_smob (xreferrer);
509   if (BOUNDP (referrer))
510     {
511       CHECK_SMOB_ARG (socket, referrer, SCM_ARG2, "svz-socket", xreferrer);
512       svz_sock_setreferrer (xsock, xreferrer);
513     }
514   return oreferrer;
515 #undef FUNC_NAME
516 }
517 
518 SCM_DEFINE
519 (guile_sock_server,
520  "svz:sock:server", 1, 1, 0,
521  (SCM sock, SCM server),
522  doc: /***********
523 Return the @code{#<svz-server>} object associated with the
524 given argument @var{sock}.  The optional argument @var{server} can be used
525 to redefine this association and must be a valid @code{#<svz-server>}
526 object.  For a usual socket callback like @code{connect-socket} or
527 @code{handle-request}, the association is already in place.  But for sockets
528 created by @code{svz:sock:connect}, you can use it in order to make the
529 returned socket object part of a server.  */)
530 {
531 #define FUNC_NAME s_guile_sock_server
532   SCM oserver = SCM_EOL;
533   svz_socket_t *xsock;
534   svz_server_t *xserver;
535 
536   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
537   if ((xserver = svz_server_find (xsock->cfg)) != NULL)
538     oserver = server_smob (xserver);
539   if (BOUNDP (server))
540     {
541       CHECK_SMOB_ARG (server, server, SCM_ARG2, "svz-server", xserver);
542       xsock->cfg = xserver->cfg;
543     }
544   return oserver;
545 #undef FUNC_NAME
546 }
547 
548 SCM_DEFINE
549 (guile_sock_protocol,
550  "svz:sock:protocol", 1, 0, 0,
551  (SCM sock),
552  doc: /***********
553 Return one of the @code{PROTO_TCP}, @code{PROTO_UDP}, @code{PROTO_ICMP},
554 @code{PROTO_RAW} or @code{PROTO_PIPE} constants indicating the type of
555 the socket structure @var{sock}.  If there is no protocol information
556 available, return @code{#f}.  */)
557 {
558 #define FUNC_NAME s_guile_sock_protocol
559   svz_socket_t *xsock;
560 
561   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
562   return gi_integer2scm (xsock->proto);
563 #undef FUNC_NAME
564 }
565 
566 SCM_DEFINE
567 (guile_sock_final_print,
568  "svz:sock:final-print", 1, 0, 0,
569  (SCM sock),
570  doc: /***********
571 Schedule the socket @var{sock} for shutdown after all data
572 within the send buffer queue has been sent.  You should call this
573 right @strong{before} the last call to @code{svz:sock:print}.  */)
574 {
575 #define FUNC_NAME s_guile_sock_final_print
576   svz_socket_t *xsock;
577 
578   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
579   xsock->flags |= SVZ_SOFLG_FINAL_WRITE;
580   return SCM_UNSPECIFIED;
581 #undef FUNC_NAME
582 }
583 
584 SCM_DEFINE
585 (guile_sock_no_delay,
586  "svz:sock:no-delay", 1, 1, 0,
587  (SCM sock, SCM enable),
588  doc: /***********
589 Turn the Nagle algorithm for the TCP socket @var{sock} on or off depending
590 on the optional @var{enable} argument.  Return the previous state of this
591 flag (@code{#f} if Nagle is active, @code{#t} otherwise).  By default this
592 flag is switched off.  This socket option is useful when dealing with small
593 packet transfer in order to disable unnecessary delays.  */)
594 {
595 #define FUNC_NAME s_guile_sock_no_delay
596   svz_socket_t *xsock;
597   int old = 0, set = 0;
598 
599   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
600   if (xsock->proto & SVZ_PROTO_TCP)
601     {
602       if (BOUNDP (enable))
603         {
604           SCM_ASSERT_TYPE (SCM_BOOLP (enable) || gi_exactp (enable),
605                            enable, SCM_ARG2, FUNC_NAME, "boolean or exact");
606           if ((SCM_BOOLP (enable) && gi_nfalsep (enable) != 0) ||
607               (gi_exactp (enable) && gi_scm2int (enable) != 0))
608             set = 1;
609         }
610       if (svz_tcp_nodelay (xsock->sock_desc, set, &old) < 0)
611         old = 0;
612       else if (!BOUNDP (enable))
613         svz_tcp_nodelay (xsock->sock_desc, old, NULL);
614     }
615   return SCM_BOOL (old);
616 #undef FUNC_NAME
617 }
618 
619 SCM_DEFINE
620 (guile_sock_p,
621  "svz:sock?", 1, 0, 0,
622  (SCM sock),
623  doc: /***********
624 Return @code{#t} if the given cell @var{sock} is an instance of a valid
625 @code{#<svz-socket>}, otherwise @code{#f}.  */)
626 {
627 #define FUNC_NAME s_guile_sock_p
628   return CHECK_SMOB (socket, sock) ? SCM_BOOL_T : SCM_BOOL_F;
629 #undef FUNC_NAME
630 }
631 
632 SCM_DEFINE
633 (guile_server_p,
634  "svz:server?", 1, 0, 0,
635  (SCM server),
636  doc: /***********
637 Return @code{#t} if the given cell @var{server} is an instance of a valid
638 @code{#<svz-server>}, otherwise @code{#f}.  */)
639 {
640 #define FUNC_NAME s_guile_server_p
641   return CHECK_SMOB (server, server) ? SCM_BOOL_T : SCM_BOOL_F;
642 #undef FUNC_NAME
643 }
644 
645 SCM_DEFINE
646 (guile_sock_disconnected_socket,
647  "svz:sock:disconnected", 1, 1, 0,
648  (SCM sock, SCM proc),
649  doc: /***********
650 Set the @code{disconnected-socket} member of the socket structure
651 @var{sock} to @var{proc}.  The given callback
652 runs whenever the socket is lost for some external reason.
653 Return the previously set handler if there is one.  */)
654 {
655 #define FUNC_NAME s_guile_sock_disconnected_socket
656   SOCK_CALLBACK_BODY (disconnected_socket, sfn_disconnected);
657 #undef FUNC_NAME
658 }
659 
660 SCM_DEFINE
661 (guile_sock_kicked_socket,
662  "svz:sock:kicked", 1, 1, 0,
663  (SCM sock, SCM proc),
664  doc: /***********
665 Set the @code{kicked-socket} callback of the given socket structure
666 @var{sock} to @var{proc} and return any previously
667 set procedure.  This callback gets called whenever the socket gets
668 closed by Serveez intentionally.  */)
669 {
670 #define FUNC_NAME s_guile_sock_kicked_socket
671   SOCK_CALLBACK_BODY (kicked_socket, sfn_kicked);
672 #undef FUNC_NAME
673 }
674 
675 SCM_DEFINE
676 (guile_sock_trigger_cond,
677  "svz:sock:trigger-condition", 1, 1, 0,
678  (SCM sock, SCM proc),
679  doc: /***********
680 Set the @code{trigger-condition} callback for the socket
681 structure @var{sock} to @var{proc}.  Return the
682 previously set procedure if available.  The callback is run once every
683 server loop indicating whether the @code{trigger} callback should be
684 run or not.  */)
685 {
686 #define FUNC_NAME s_guile_sock_trigger_cond
687   SOCK_CALLBACK_BODY (trigger_cond, sfn_trigger_condition);
688 #undef FUNC_NAME
689 }
690 
691 SCM_DEFINE
692 (guile_sock_trigger_func,
693  "svz:sock:trigger", 1, 1, 0,
694  (SCM sock, SCM proc),
695  doc: /***********
696 Set the @code{trigger} callback of the socket structure @var{sock} to
697 @var{proc} and return any previously set procedure.
698 The callback is run when the @code{trigger-condition} callback returns
699 @code{#t}.  */)
700 {
701 #define FUNC_NAME s_guile_sock_trigger_func
702   SOCK_CALLBACK_BODY (trigger_func, sfn_trigger);
703 #undef FUNC_NAME
704 }
705 
706 SCM_DEFINE
707 (guile_sock_idle_func,
708  "svz:sock:idle", 1, 1, 0,
709  (SCM sock, SCM proc),
710  doc: /***********
711 Set the @code{idle} callback of the socket structure
712 @var{sock} to @var{proc}.  Return any previously
713 set procedure.  The callback is run by the periodic task scheduler when the
714 @code{idle-counter} of the socket structure drops to zero.  If this counter
715 is not zero it gets decremented once a second.  The @code{idle}
716 callback can reset @code{idle-counter} to some value and thus can
717 re-schedule itself for a later task.  */)
718 {
719 #define FUNC_NAME s_guile_sock_idle_func
720   SOCK_CALLBACK_BODY (idle_func, sfn_idle);
721 #undef FUNC_NAME
722 }
723 
724 SCM_DEFINE
725 (guile_sock_check_request_oob,
726  "svz:sock:check-oob-request", 1, 1, 0,
727  (SCM sock, SCM proc),
728  doc: /***********
729 Set the @code{check-oob-request} callback of the given socket
730 structure @var{sock} to @var{proc}, returning
731 the previous callback (if there was any set before).
732 The callback is run whenever urgent data (out-of-band)
733 has been detected on the socket.  */)
734 {
735 #define FUNC_NAME s_guile_sock_check_request_oob
736   SOCK_CALLBACK_BODY (check_request_oob, sfn_check_oob_request);
737 #undef FUNC_NAME
738 }
739 
740 SCM_DEFINE
741 (guile_sock_idle_counter,
742  "svz:sock:idle-counter", 1, 1, 0,
743  (SCM sock, SCM counter),
744  doc: /***********
745 Return the socket structure @var{sock}'s current
746 @code{idle-counter} value.  If the optional argument @var{counter} is
747 given, the set the @code{idle-counter}.  Please have a look at the
748 @code{svz:sock:idle} procedure for the exact meaning of this value.  */)
749 {
750 #define FUNC_NAME s_guile_sock_idle_counter
751   svz_socket_t *xsock;
752   int ocounter;
753 
754   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
755   ocounter = xsock->idle_counter;
756   if (BOUNDP (counter))
757     {
758       ASSERT_EXACT (2, counter);
759       xsock->idle_counter = gi_scm2int (counter);
760     }
761   return gi_integer2scm (ocounter);
762 #undef FUNC_NAME
763 }
764 
765 static svz_server_t *
named_instance_or_smob(SCM server,const char * FUNC_NAME)766 named_instance_or_smob (SCM server, const char *FUNC_NAME)
767 {
768   char name[64];
769   svz_server_t *rv = NULL;
770 
771   if (GI_GET_XREP_MAYBE (name, server))
772     rv = svz_server_get (name);
773   if (! rv)
774     CHECK_SMOB_ARG (server, server, SCM_ARG1, "svz-server or string", rv);
775   return rv;
776 }
777 
778 SCM_DEFINE
779 (guile_server_listeners,
780  "svz:server:listeners", 1, 0, 0,
781  (SCM server),
782  doc: /***********
783 Return a list of listening @code{#<svz-socket>} smobs to which the
784 given server instance @var{server} is currently bound, or an empty list
785 if there is no such binding yet.  */)
786 {
787 #define FUNC_NAME s_guile_server_listeners
788   svz_server_t *xserver = named_instance_or_smob (server, FUNC_NAME);
789   svz_array_t *listeners;
790   size_t i;
791   SCM list = SCM_EOL;
792 
793   /* Create a list of socket smobs for the server.  */
794   if ((listeners = svz_server_listeners (xserver)) != NULL)
795     {
796       for (i = 0; i < svz_array_size (listeners); i++)
797         list = scm_cons (socket_smob ((svz_socket_t *)
798                                       svz_array_get (listeners, i)),
799                          list);
800       svz_array_destroy (listeners);
801     }
802   return scm_reverse (list);
803 #undef FUNC_NAME
804 }
805 
806 SCM_DEFINE
807 (guile_server_clients,
808  "svz:server:clients", 1, 0, 0,
809  (SCM server),
810  doc: /***********
811 Return a list of @code{#<svz-socket>} client smobs associated with
812 the given server instance @var{server} in arbitrary order, or an
813 empty list if there is no such client.  */)
814 {
815 #define FUNC_NAME s_guile_server_clients
816   svz_server_t *xserver = named_instance_or_smob (server, FUNC_NAME);
817   svz_array_t *clients;
818   svz_socket_t *sock;
819   size_t i;
820   SCM list = SCM_EOL;
821 
822   /* Create a list of socket smobs for the server.  */
823   if ((clients = svz_server_clients (xserver)) != NULL)
824     {
825       svz_array_foreach (clients, sock, i)
826         list = scm_cons (socket_smob (sock), list);
827       svz_array_destroy (clients);
828     }
829   return list;
830 #undef FUNC_NAME
831 }
832 
833 #if HAVE_GETRPCENT || HAVE_GETRPCBYNAME || HAVE_GETRPCBYNUMBER
834 static SCM
scm_return_rpcentry(struct rpcent * entry)835 scm_return_rpcentry (struct rpcent *entry)
836 {
837   return scm_vector
838     (gi_list_3 (gi_string2scm (entry->r_name),
839                 scm_makfromstrs (-1, entry->r_aliases),
840                 gi_integer2scm (entry->r_number)));
841 }
842 
843 SCM_DEFINE
844 (scm_getrpc,
845  "getrpc", 0, 1, 0,
846  (SCM arg),
847  doc: /***********
848 Lookup a network rpc service @var{arg} (name or service number),
849 and return a network rpc service object.
850 If given no arguments, it behave like @code{getrpcent}.  */)
851 {
852 #define FUNC_NAME s_scm_getrpc
853   struct rpcent *entry = NULL;
854 
855 #if HAVE_GETRPCENT
856   if (!BOUNDP (arg))
857     {
858       if ((entry = getrpcent ()) == NULL)
859         return SCM_BOOL_F;
860       return scm_return_rpcentry (entry);
861     }
862 #endif /* HAVE_GETRPCENT */
863 #if HAVE_GETRPCBYNAME
864   if (gi_stringp (arg))
865     {
866       char name[64];
867 
868       GI_GET_XREP (name, arg);
869       entry = getrpcbyname (name);
870     }
871   else
872 #endif /* HAVE_GETRPCBYNAME */
873 #if HAVE_GETRPCBYNUMBER
874     {
875       ASSERT_EXACT (1, arg);
876       entry = getrpcbynumber (gi_scm2int (arg));
877     }
878 #endif /* #if HAVE_GETRPCBYNUMBER */
879 
880   if (!entry)
881     scm_syserror_msg (FUNC_NAME, "no such rpc service ~A",
882                       scm_cons (arg, SCM_EOL), errno);
883   return scm_return_rpcentry (entry);
884 #undef FUNC_NAME
885 }
886 #endif /* HAVE_GETRPCENT || HAVE_GETRPCBYNAME || HAVE_GETRPCBYNUMBER */
887 
888 #if !HAVE_DECL_SETRPCENT
889 extern void setrpcent (int);
890 #endif
891 #if !HAVE_DECL_ENDRPCENT
892 extern void endrpcent (void);
893 #endif
894 
895 #if HAVE_SETRPCENT && HAVE_ENDRPCENT
896 SCM_DEFINE
897 (scm_setrpc,
898  "setrpc", 0, 1, 0,
899  (SCM stayopen),
900  doc: /***********
901 Open and rewind the file @file{/etc/rpc}.
902 If the @var{stayopen} flag is non-zero, the net data base will not be
903 closed after each call to @code{getrpc}.  If @var{stayopen} is omitted,
904 this is equivalent to calling @code{endrpcent}.  Otherwise it is
905 equivalent to calling @code{setrpcent} with arg 1.  */)
906 {
907 #define FUNC_NAME s_scm_setrpc
908   if (!BOUNDP (stayopen))
909     endrpcent ();
910   else
911     setrpcent (!SCM_FALSEP (stayopen));
912   return SCM_UNSPECIFIED;
913 #undef FUNC_NAME
914 }
915 #endif /* HAVE_SETRPCENT && HAVE_ENDRPCENT */
916 
917 #if HAVE_PMAP_GETMAPS
918 SCM_DEFINE
919 (scm_portmap_list,
920  "portmap-list", 0, 1, 0,
921  (SCM address),
922  doc: /***********
923 Return a list of the current RPC program-to-port mappings
924 on the host located at IP address @var{address}, which
925 defaults to the local machine's IP address.
926 Return an empty list if either there is no such list
927 available or an error occurred while fetching the list.  */)
928 {
929 #define FUNC_NAME s_scm_portmap_list
930   struct sockaddr_in addr, raddr;
931   struct pmaplist *map;
932   char str[48];
933   SCM list = SCM_EOL, mapping;
934 
935   memset (&addr, 0, sizeof (struct sockaddr_in));
936 #if HAVE_GET_MYADDRESS
937   get_myaddress (&addr);
938 #else
939   addr.sin_family = AF_INET;
940   addr.sin_port = htons (PMAPPORT);
941   addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
942 #endif
943   if (BOUNDP (address))
944     {
945       ASSERT_STRING (1, address);
946       GI_GET_XREP (str, address);
947       if (svz_inet_aton (str, &raddr) == -1)
948         {
949           guile_error ("%s: IP in dotted decimals expected", FUNC_NAME);
950           return SCM_EOL;
951         }
952       addr.sin_addr.s_addr = raddr.sin_addr.s_addr;
953     }
954 
955   if ((map = pmap_getmaps (&addr)) == NULL)
956     return SCM_EOL;
957   do
958     {
959       mapping = gi_list_3 (gi_integer2scm (map->pml_map.pm_vers),
960                            gi_integer2scm (map->pml_map.pm_prot),
961                            gi_integer2scm (map->pml_map.pm_port));
962       mapping = scm_cons (gi_integer2scm (map->pml_map.pm_prog),
963                           mapping);
964       mapping = scm_vector (mapping);
965       list = scm_cons (mapping ,list);
966     }
967   while ((map = map->pml_next) != NULL);
968   return scm_reverse (list);
969 #undef FUNC_NAME
970 }
971 #endif /* HAVE_PMAP_GETMAPS */
972 
973 static SCM
errnostring(void)974 errnostring (void)
975 {
976   return scm_strerror (gi_integer2scm (errno));
977 }
978 
979 #if HAVE_PMAP_SET && HAVE_PMAP_UNSET
980 SCM_DEFINE
981 (scm_portmap,
982  "portmap", 2, 2, 0,
983  (SCM prognum, SCM versnum, SCM protocol, SCM port),
984  doc: /***********
985 Establish a (portmap service) mapping
986 between the triple [@var{prognum},@var{versnum},@var{protocol}] and
987 @var{port} on the machine's portmap service.  The value of @var{protocol}
988 is most likely @code{IPPROTO_UDP} or @code{IPPROTO_TCP}.
989 If instead @var{protocol} and @var{port} are omitted, destroy
990 all mapping between the triple [@var{prognum},@var{versnum},*] and ports
991 on the machine's portmap service.  */)
992 {
993 #define FUNC_NAME s_scm_portmap
994   ASSERT_EXACT (1, prognum);
995   ASSERT_EXACT (2, prognum);
996 
997   if (!BOUNDP (protocol) && !BOUNDP (port))
998     {
999       if (!pmap_unset (gi_scm2int (prognum), gi_scm2int (versnum)))
1000         scm_syserror_msg (FUNC_NAME, "~A: pmap_unset ~A ~A",
1001                           gi_list_3 (errnostring (), prognum, versnum),
1002                           errno);
1003     }
1004   else
1005     {
1006       ASSERT_EXACT (3, protocol);
1007       ASSERT_EXACT (4, port);
1008 
1009       if (!pmap_set (gi_scm2int (prognum), gi_scm2int (versnum),
1010                      gi_scm2int (protocol), gi_scm2int (port)))
1011         scm_syserror_msg (FUNC_NAME, "~A: pmap_set ~A ~A ~A ~A",
1012                           gi_list_5 (errnostring (), prognum,
1013                                      versnum, protocol, port),
1014                           errno);
1015     }
1016   return SCM_UNSPECIFIED;
1017 #undef FUNC_NAME
1018 }
1019 #endif /* HAVE_PMAP_SET && HAVE_PMAP_UNSET */
1020 
1021 /* Validate @var{callback}; protect it from gc.  */
1022 static void
validate_callback(SCM callback,const char * who)1023 validate_callback (SCM callback, const char *who)
1024 {
1025   SCM_ASSERT_TYPE (SCM_PROCEDUREP (callback), callback,
1026                    SCM_ARG2, who, "procedure");
1027   /* TODO: Check arity.  */
1028 
1029   /* Protect callback from garbage collection meanwhile.  */
1030   gi_gc_protect (callback);
1031 }
1032 
1033 #define VALIDATE_CALLBACK(x)  validate_callback (x, FUNC_NAME)
1034 
1035 /* Callback wrapper for coserver responses.  */
1036 static int
guile_coserver_callback(char * res,void * closure)1037 guile_coserver_callback (char *res, void *closure)
1038 {
1039   SCM callback = (SCM) closure;
1040   int ret = -1;
1041 
1042   /* If successfully done, run the given Guile procedure.  */
1043   if (res != NULL)
1044     {
1045       guile_call (callback, 1, gi_string2scm (res));
1046       ret = 0;
1047     }
1048 
1049   /* Pass the value to garbage collection again.  */
1050   gi_gc_unprotect (callback);
1051   return ret;
1052 }
1053 
1054 #define ENQ_COSERVER_REQUEST(req,coserver)      \
1055   svz_coserver_ ## coserver ## _invoke          \
1056   (req, guile_coserver_callback,                \
1057    (void *) callback)
1058 
1059 SCM_DEFINE
1060 (guile_coserver_dns,
1061  "svz:coserver:dns", 2, 0, 0,
1062  (SCM host, SCM callback),
1063  doc: /***********
1064 Enqueue the @var{host} string argument into the internal
1065 DNS coserver queue.  When the coserver responds, the procedure
1066 @var{callback} is run as @code{(callback addr)}.  The @var{addr}
1067 argument passed to the callback is a string representing the appropriate
1068 IP address for the given hostname @var{host}.  */)
1069 {
1070 #define FUNC_NAME s_guile_coserver_dns
1071   char request[128];
1072 
1073   /* Check argument list first.  */
1074   ASSERT_STRING (1, host);
1075   VALIDATE_CALLBACK (callback);
1076 
1077   /* Convert hostname into C string.  */
1078   GI_GET_XREP (request, host);
1079 
1080   ENQ_COSERVER_REQUEST (request, dns);
1081   return SCM_UNSPECIFIED;
1082 #undef FUNC_NAME
1083 }
1084 
1085 SCM_DEFINE
1086 (guile_coserver_rdns,
1087  "svz:coserver:reverse-dns", 2, 0, 0,
1088  (SCM addr, SCM callback),
1089  doc: /***********
1090 Enqueue the given @var{addr} argument, which must be
1091 an IP address in network byte order, into the internal reverse DNS coserver
1092 queue.  When the coserver responds, the procedure @var{callback} is
1093 run as @code{(callback host)} where @var{host} is the hostname of the
1094 requested IP address @var{addr}.  */)
1095 {
1096 #define FUNC_NAME s_guile_coserver_rdns
1097   in_addr_t ip;
1098   svz_address_t *a;
1099 
1100   /* Check argument list first.  */
1101   ASSERT_EXACT (1, addr);
1102   VALIDATE_CALLBACK (callback);
1103 
1104   /* Convert IP address into C long value.  */
1105   ip = gi_scm2ulong (addr);
1106   a = svz_address_make (AF_INET, &ip);
1107 
1108   ENQ_COSERVER_REQUEST (a, rdns);
1109   svz_free (a);
1110   return SCM_UNSPECIFIED;
1111 #undef FUNC_NAME
1112 }
1113 
1114 SCM_DEFINE
1115 (guile_coserver_ident,
1116  "svz:coserver:ident", 2, 0, 0,
1117  (SCM sock, SCM callback),
1118  doc: /***********
1119 Enqueue the given @code{#<svz-socket>} @var{sock} into the
1120 internal ident coserver queue.  When the coserver responds, it
1121 runs the procedure @var{callback} as @code{(callback user)}, where
1122 @var{user} is the corresponding username for the client connection
1123 @var{sock}.  */)
1124 {
1125 #define FUNC_NAME s_guile_coserver_ident
1126   svz_socket_t *xsock;
1127 
1128   /* Check argument list first.  */
1129   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
1130   VALIDATE_CALLBACK (callback);
1131 
1132   ENQ_COSERVER_REQUEST (xsock, ident);
1133   return SCM_UNSPECIFIED;
1134 #undef FUNC_NAME
1135 }
1136 
1137 SCM_DEFINE
1138 (guile_sock_find,
1139  "svz:sock:find", 1, 0, 0,
1140  (SCM ident),
1141  doc: /***********
1142 Return the @code{#<svz-socket>} specified by @var{ident},
1143 a pair of integers in the form @code{(identification . version)}.
1144 If that socket no longer exists, return @code{#f}.  */)
1145 {
1146 #define FUNC_NAME s_guile_sock_find
1147   int version, id;
1148   svz_socket_t *sock;
1149 
1150   SCM_ASSERT_TYPE (SCM_PAIRP (ident) && gi_exactp (SCM_CAR (ident)) &&
1151                    gi_exactp (SCM_CDR (ident)), ident, SCM_ARG1,
1152                    FUNC_NAME, "pair of exact");
1153   id = gi_scm2int (SCM_CAR (ident));
1154   version = gi_scm2int (SCM_CDR (ident));
1155   if ((sock = svz_sock_find (id, version)) != NULL)
1156     return socket_smob (sock);
1157   return SCM_BOOL_F;
1158 #undef FUNC_NAME
1159 }
1160 
1161 SCM_DEFINE
1162 (guile_sock_ident,
1163  "svz:sock:ident", 1, 0, 0,
1164  (SCM sock),
1165  doc: /***********
1166 Return a pair of numbers identifying the given
1167 @code{#<svz-socket>} @var{sock}, which can be passed to
1168 @code{svz:sock:find}.  This may be necessary when you are passing
1169 a @code{#<svz-socket>} through coserver callback arguments in order to
1170 verify that the passed @code{#<svz-socket>} is still valid when the
1171 coserver callback runs.  */)
1172 {
1173 #define FUNC_NAME s_guile_sock_ident
1174   svz_socket_t *xsock;
1175   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
1176   return scm_cons (gi_integer2scm (xsock->id), gi_integer2scm (xsock->version));
1177 #undef FUNC_NAME
1178 }
1179 
1180 SCM_DEFINE
1181 (guile_read_file,
1182  "svz:read-file", 2, 0, 0,
1183  (SCM port, SCM size),
1184  doc: /***********
1185 Return either a binary smob containing a data block read
1186 from the open input port @var{port} with a maximum number of @var{size}
1187 bytes, or the end-of-file object if the underlying ports end has been
1188 reached.  The size of the returned binary smob may be less than the
1189 requested size @var{size} if it exceed the current size of the given port
1190 @var{port}.  Throw an exception if an error occurred while
1191 reading from the port.  */)
1192 {
1193 #define FUNC_NAME s_guile_read_file
1194   int fdes, len, ret;
1195   uint8_t *data;
1196 
1197   /* Check argument list.  */
1198   SCM_ASSERT_TYPE (SCM_NIMP (port) && SCM_FPORTP (port) &&
1199                    SCM_OPINFPORTP (port),
1200                    port, SCM_ARG1, FUNC_NAME, "open input port");
1201   ASSERT_EXACT (2, size);
1202 
1203   /* Get underlying file descriptor.  */
1204   fdes = gi_scm2int (scm_fileno (port));
1205 
1206   if ((len = gi_scm2int (size)) <= 0)
1207     SCM_OUT_OF_RANGE (SCM_ARG2, size);
1208 
1209   /* Allocate necessary data.  */
1210   data = gi_malloc (len, BDATA_WHAT);
1211 
1212   /* Read from file descriptor and evaluate return value.  */
1213   if ((ret = read (fdes, data, len)) < 0)
1214     {
1215       BFREE (DATA, data, len);
1216       scm_syserror_msg (FUNC_NAME, "~A: read ~A ~A",
1217                         gi_list_3 (errnostring (),
1218                                    gi_integer2scm (fdes),
1219                                    size),
1220                         errno);
1221     }
1222   else if (ret == 0)
1223     {
1224       BFREE (DATA, data, len);
1225       return SCM_EOF_VAL;
1226     }
1227   else if (ret != len)
1228     {
1229       data = gi_realloc (data, len, ret, BDATA_WHAT);
1230     }
1231 
1232   /* Finally return binary smob.  */
1233   return guile_garbage_to_bin (data, ret);
1234 #undef FUNC_NAME
1235 }
1236 
1237 SCM_DEFINE
1238 (guile_sock_send_oob,
1239  "svz:sock:send-oob", 2, 0, 0,
1240  (SCM sock, SCM oob),
1241  doc: /***********
1242 Send byte @var{oob} as urgent (out-of-band) data through the
1243 underlying TCP stream of TCP @var{sock}.
1244 Return @code{#t} on successful completion and otherwise
1245 (either it failed to send the byte or the passed socket is not a TCP
1246 socket) @code{#f}.  */)
1247 {
1248 #define FUNC_NAME s_guile_sock_send_oob
1249   svz_socket_t *xsock;
1250   int ret = -1;
1251 
1252   /* Check the arguments.  */
1253   CHECK_SMOB_ARG (socket, sock, SCM_ARG1, "svz-socket", xsock);
1254   SCM_ASSERT_TYPE (gi_exactp (oob) || SCM_CHARP (oob),
1255                    oob, SCM_ARG2, FUNC_NAME, "char or exact");
1256 
1257   /* Send the oob byte through TCP sockets only.  */
1258   if (xsock->proto & SVZ_PROTO_TCP)
1259     {
1260       xsock->oob = (uint8_t)
1261         (SCM_CHARP (oob) ? SCM_CHAR (oob) :
1262          (uint8_t) gi_scm2int (oob));
1263       ret = svz_tcp_send_oob (xsock);
1264     }
1265   return ((ret < 0) ? SCM_BOOL_F : SCM_BOOL_T);
1266 #undef FUNC_NAME
1267 }
1268 
1269 /* Initialize the API procedures supported by Guile.  */
1270 void
guile_api_init(void)1271 guile_api_init (void)
1272 {
1273 #if HAVE_PMAP_SET && HAVE_PMAP_UNSET
1274   gi_define ("IPPROTO_UDP", gi_integer2scm (IPPROTO_UDP));
1275   gi_define ("IPPROTO_TCP", gi_integer2scm (IPPROTO_TCP));
1276 #endif
1277 
1278   gi_define ("PROTO_TCP", gi_integer2scm (SVZ_PROTO_TCP));
1279   gi_define ("PROTO_UDP", gi_integer2scm (SVZ_PROTO_UDP));
1280   gi_define ("PROTO_ICMP", gi_integer2scm (SVZ_PROTO_ICMP));
1281   gi_define ("PROTO_RAW", gi_integer2scm (SVZ_PROTO_RAW));
1282   gi_define ("PROTO_PIPE", gi_integer2scm (SVZ_PROTO_PIPE));
1283   gi_define ("KICK_FLOOD", gi_integer2scm (0));
1284   gi_define ("KICK_QUEUE", gi_integer2scm (1));
1285 }
1286 
1287 /* Finalize the API procedures.  */
1288 void
guile_api_finalize(void)1289 guile_api_finalize (void)
1290 {
1291 }
1292 
1293 #endif /* ENABLE_GUILE_SERVER */
1294