-/* Copyright (C) 1996,1997,1998,2000,2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 1996,1997,1998,2000,2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
*/
\f
-#if HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gmp.h>
#include "libguile/_scm.h"
-#include "libguile/unif.h"
+#include "libguile/arrays.h"
#include "libguile/feature.h"
#include "libguile/fports.h"
#include "libguile/strings.h"
#include "libguile/vectors.h"
#include "libguile/dynwind.h"
+#include "libguile/srfi-13.h"
#include "libguile/validate.h"
#include "libguile/socket.h"
+#include "libguile/iselect.h"
+
#ifdef __MINGW32__
#include "win32-socket.h"
#endif
+ strlen ((ptr)->sun_path))
#endif
+/* The largest possible socket address. Wrapping it in a union guarantees
+ that the compiler will make it suitably aligned. */
+typedef union
+{
+ struct sockaddr sockaddr;
+ struct sockaddr_in sockaddr_in;
+
+#ifdef HAVE_UNIX_DOMAIN_SOCKETS
+ struct sockaddr_un sockaddr_un;
+#endif
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 sockaddr_in6;
+#endif
+} scm_t_max_sockaddr;
+
+
+/* Maximum size of a socket address. */
+#define MAX_ADDR_SIZE (sizeof (scm_t_max_sockaddr))
+
+
\f
SCM_DEFINE (scm_htons, "htons", 1, 0, 0,
}
#undef FUNC_NAME
-#ifndef HAVE_INET_ATON
-/* for our definition in inet_aton.c, not usually needed. */
-extern int inet_aton ();
-#endif
-
-SCM_DEFINE (scm_inet_aton, "inet-aton", 1, 0, 0,
- (SCM address),
- "Convert an IPv4 Internet address from printable string\n"
- "(dotted decimal notation) to an integer. E.g.,\n\n"
- "@lisp\n"
- "(inet-aton \"127.0.0.1\") @result{} 2130706433\n"
- "@end lisp")
-#define FUNC_NAME s_scm_inet_aton
-{
- struct in_addr soka;
- char *c_address;
- int rv;
-
- c_address = scm_to_locale_string (address);
- rv = inet_aton (c_address, &soka);
- free (c_address);
- if (rv == 0)
- SCM_MISC_ERROR ("bad address", SCM_EOL);
- return scm_from_ulong (ntohl (soka.s_addr));
-}
-#undef FUNC_NAME
-
-
-SCM_DEFINE (scm_inet_ntoa, "inet-ntoa", 1, 0, 0,
- (SCM inetid),
- "Convert an IPv4 Internet address to a printable\n"
- "(dotted decimal notation) string. E.g.,\n\n"
- "@lisp\n"
- "(inet-ntoa 2130706433) @result{} \"127.0.0.1\"\n"
- "@end lisp")
-#define FUNC_NAME s_scm_inet_ntoa
-{
- struct in_addr addr;
- char *s;
- SCM answer;
- addr.s_addr = htonl (SCM_NUM2ULONG (1, inetid));
- s = inet_ntoa (addr);
- answer = scm_from_locale_string (s);
- return answer;
-}
-#undef FUNC_NAME
-
#ifdef HAVE_INET_NETOF
SCM_DEFINE (scm_inet_netof, "inet-netof", 1, 0, 0,
(SCM address),
scm_remember_upto_here_1 (src);
}
else
- scm_wrong_type_arg (NULL, 0, src);
+ scm_wrong_type_arg_msg ("scm_to_ipv6", 0, src, "integer");
}
-#ifdef HAVE_INET_PTON
SCM_DEFINE (scm_inet_pton, "inet-pton", 2, 0, 0,
(SCM family, SCM address),
"Convert a string containing a printable network address to\n"
{
int af;
char *src;
- char dst[16];
+ scm_t_uint32 dst[4];
int rv, eno;
af = scm_to_int (family);
else if (rv == 0)
SCM_MISC_ERROR ("Bad address", SCM_EOL);
if (af == AF_INET)
- return scm_from_ulong (ntohl (*(scm_t_uint32 *) dst));
+ return scm_from_ulong (ntohl (*dst));
else
return scm_from_ipv6 ((scm_t_uint8 *) dst);
}
#undef FUNC_NAME
-#endif
-#ifdef HAVE_INET_NTOP
SCM_DEFINE (scm_inet_ntop, "inet-ntop", 2, 0, 0,
(SCM family, SCM address),
"Convert a network address into a printable string.\n"
"@var{family} can be @code{AF_INET} or @code{AF_INET6}. E.g.,\n\n"
"@lisp\n"
"(inet-ntop AF_INET 2130706433) @result{} \"127.0.0.1\"\n"
- "(inet-ntop AF_INET6 (- (expt 2 128) 1)) @result{}\n"
- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\n"
+ "(inet-ntop AF_INET6 (- (expt 2 128) 1))\n"
+ " @result{} \"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\"\n"
"@end lisp")
#define FUNC_NAME s_scm_inet_ntop
{
return scm_from_locale_string (dst);
}
#undef FUNC_NAME
-#endif
#endif /* HAVE_IPV6 */
#undef FUNC_NAME
#endif
+/* Possible results for `getsockopt ()'. Wrapping it into a union guarantees
+ suitable alignment. */
+typedef union
+{
+#ifdef HAVE_STRUCT_LINGER
+ struct linger linger;
+#endif
+ size_t size;
+ int integer;
+} scm_t_getsockopt_result;
+
SCM_DEFINE (scm_getsockopt, "getsockopt", 3, 0, 0,
(SCM sock, SCM level, SCM optname),
"Return an option value from socket port @var{sock}.\n"
{
int fd;
/* size of optval is the largest supported option. */
-#ifdef HAVE_STRUCT_LINGER
- char optval[sizeof (struct linger)];
- socklen_t optlen = sizeof (struct linger);
-#else
- char optval[sizeof (size_t)];
- socklen_t optlen = sizeof (size_t);
-#endif
+ scm_t_getsockopt_result optval;
+ socklen_t optlen = sizeof (optval);
int ilevel;
int ioptname;
ioptname = scm_to_int (optname);
fd = SCM_FPORT_FDES (sock);
- if (getsockopt (fd, ilevel, ioptname, (void *) optval, &optlen) == -1)
+ if (getsockopt (fd, ilevel, ioptname, (void *) &optval, &optlen) == -1)
SCM_SYSERROR;
if (ilevel == SOL_SOCKET)
if (ioptname == SO_LINGER)
{
#ifdef HAVE_STRUCT_LINGER
- struct linger *ling = (struct linger *) optval;
+ struct linger *ling = (struct linger *) &optval;
return scm_cons (scm_from_long (ling->l_onoff),
scm_from_long (ling->l_linger));
#else
- return scm_cons (scm_from_long (*(int *) optval),
+ return scm_cons (scm_from_long (*(int *) &optval),
scm_from_int (0));
#endif
}
#endif
)
{
- return scm_from_size_t (*(size_t *) optval);
+ return scm_from_size_t (*(size_t *) &optval);
}
}
- return scm_from_int (*(int *) optval);
+ return scm_from_int (*(int *) &optval);
}
#undef FUNC_NAME
/* Put the components of a sockaddr into a new SCM vector. */
static SCM_C_INLINE_KEYWORD SCM
-_scm_from_sockaddr (const struct sockaddr *address, unsigned addr_size,
- const char *proc)
+_scm_from_sockaddr (const scm_t_max_sockaddr *address, unsigned addr_size,
+ const char *proc)
{
- short int fam = address->sa_family;
- SCM result =SCM_EOL;
-
+ SCM result = SCM_EOL;
+ short int fam = ((struct sockaddr *) address)->sa_family;
switch (fam)
{
SCM
scm_from_sockaddr (const struct sockaddr *address, unsigned addr_size)
{
- return (_scm_from_sockaddr (address, addr_size, "scm_from_sockaddr"));
+ return (_scm_from_sockaddr ((scm_t_max_sockaddr *) address,
+ addr_size, "scm_from_sockaddr"));
}
/* Convert ADDRESS, an address object returned by either
{
struct sockaddr_in6 c_inet6;
- scm_to_ipv6 (c_inet6.sin6_addr.s6_addr, address);
+ scm_to_ipv6 (c_inet6.sin6_addr.s6_addr,
+ SCM_SIMPLE_VECTOR_REF (address, 1));
c_inet6.sin6_port =
htons (scm_to_ushort (SCM_SIMPLE_VECTOR_REF (address, 2)));
c_inet6.sin6_flowinfo =
"@code{connect} for details).")
#define FUNC_NAME s_scm_make_socket_address
{
+ SCM result = SCM_BOOL_F;
struct sockaddr *c_address;
size_t c_address_size;
c_address = scm_c_make_socket_address (family, address, args,
&c_address_size);
- if (!c_address)
- return SCM_BOOL_F;
+ if (c_address != NULL)
+ {
+ result = scm_from_sockaddr (c_address, c_address_size);
+ free (c_address);
+ }
- return (scm_from_sockaddr (c_address, c_address_size));
+ return result;
}
#undef FUNC_NAME
\f
-/* calculate the size of a buffer large enough to hold any supported
- sockaddr type. if the buffer isn't large enough, certain system
- calls will return a truncated address. */
-
-#if defined (HAVE_UNIX_DOMAIN_SOCKETS)
-#define MAX_SIZE_UN sizeof (struct sockaddr_un)
-#else
-#define MAX_SIZE_UN 0
-#endif
-
-#if defined (HAVE_IPV6)
-#define MAX_SIZE_IN6 sizeof (struct sockaddr_in6)
-#else
-#define MAX_SIZE_IN6 0
-#endif
-
-#define MAX_ADDR_SIZE max (max (sizeof (struct sockaddr_in), MAX_SIZE_IN6),\
- MAX_SIZE_UN)
-
SCM_DEFINE (scm_accept, "accept", 1, 0, 0,
(SCM sock),
"Accept a connection on a bound, listening socket.\n"
"connection and will continue to accept new requests.")
#define FUNC_NAME s_scm_accept
{
- int fd;
+ int fd, selected;
int newfd;
SCM address;
SCM newsock;
+ SELECT_TYPE readfds, exceptfds;
socklen_t addr_size = MAX_ADDR_SIZE;
- char max_addr[MAX_ADDR_SIZE];
- struct sockaddr *addr = (struct sockaddr *) max_addr;
+ scm_t_max_sockaddr addr;
sock = SCM_COERCE_OUTPORT (sock);
SCM_VALIDATE_OPFPORT (1, sock);
fd = SCM_FPORT_FDES (sock);
- newfd = accept (fd, addr, &addr_size);
+
+ FD_ZERO (&readfds);
+ FD_ZERO (&exceptfds);
+ FD_SET (fd, &readfds);
+ FD_SET (fd, &exceptfds);
+
+ /* Block until something happens on FD, leaving guile mode while
+ waiting. */
+ selected = scm_std_select (fd + 1, &readfds, NULL, &exceptfds,
+ NULL);
+ if (selected < 0)
+ SCM_SYSERROR;
+
+ newfd = accept (fd, (struct sockaddr *) &addr, &addr_size);
if (newfd == -1)
SCM_SYSERROR;
newsock = SCM_SOCK_FD_TO_PORT (newfd);
- address = _scm_from_sockaddr (addr, addr_size, FUNC_NAME);
+ address = _scm_from_sockaddr (&addr, addr_size,
+ FUNC_NAME);
+
return scm_cons (newsock, address);
}
#undef FUNC_NAME
{
int fd;
socklen_t addr_size = MAX_ADDR_SIZE;
- char max_addr[MAX_ADDR_SIZE];
- struct sockaddr *addr = (struct sockaddr *) max_addr;
+ scm_t_max_sockaddr addr;
sock = SCM_COERCE_OUTPORT (sock);
SCM_VALIDATE_OPFPORT (1, sock);
fd = SCM_FPORT_FDES (sock);
- if (getsockname (fd, addr, &addr_size) == -1)
+ if (getsockname (fd, (struct sockaddr *) &addr, &addr_size) == -1)
SCM_SYSERROR;
- return _scm_from_sockaddr (addr, addr_size, FUNC_NAME);
+
+ return _scm_from_sockaddr (&addr, addr_size, FUNC_NAME);
}
#undef FUNC_NAME
{
int fd;
socklen_t addr_size = MAX_ADDR_SIZE;
- char max_addr[MAX_ADDR_SIZE];
- struct sockaddr *addr = (struct sockaddr *) max_addr;
+ scm_t_max_sockaddr addr;
sock = SCM_COERCE_OUTPORT (sock);
SCM_VALIDATE_OPFPORT (1, sock);
fd = SCM_FPORT_FDES (sock);
- if (getpeername (fd, addr, &addr_size) == -1)
+ if (getpeername (fd, (struct sockaddr *) &addr, &addr_size) == -1)
SCM_SYSERROR;
- return _scm_from_sockaddr (addr, addr_size, FUNC_NAME);
+
+ return _scm_from_sockaddr (&addr, addr_size, FUNC_NAME);
}
#undef FUNC_NAME
"protocols, if a packet larger than this limit is encountered\n"
"then some data\n"
"will be irrevocably lost.\n\n"
+ "The data is assumed to be binary, and there is no decoding of\n"
+ "of locale-encoded strings.\n\n"
"The optional @var{flags} argument is a value or\n"
"bitwise OR of MSG_OOB, MSG_PEEK, MSG_DONTROUTE etc.\n\n"
"The value returned is the number of bytes read from the\n"
int flg;
char *dest;
size_t len;
+ SCM msg;
SCM_VALIDATE_OPFPORT (1, sock);
SCM_VALIDATE_STRING (2, buf);
flg = scm_to_int (flags);
fd = SCM_FPORT_FDES (sock);
- len = scm_i_string_length (buf);
- dest = scm_i_string_writable_chars (buf);
+ len = scm_i_string_length (buf);
+ msg = scm_i_make_string (len, &dest);
SCM_SYSCALL (rv = recv (fd, dest, len, flg));
- scm_i_string_stop_writing ();
+ scm_string_copy_x (buf, scm_from_int (0),
+ msg, scm_from_int (0), scm_from_size_t (len));
if (rv == -1)
SCM_SYSERROR;
- scm_remember_upto_here_1 (buf);
+ scm_remember_upto_here_2 (buf, msg);
return scm_from_int (rv);
}
#undef FUNC_NAME
"bitwise OR of MSG_OOB, MSG_PEEK, MSG_DONTROUTE etc.\n\n"
"Note that the data is written directly to the socket\n"
"file descriptor:\n"
- "any unflushed buffered port data is ignored.")
+ "any unflushed buffered port data is ignored.\n\n"
+ "This operation is defined only for strings containing codepoints\n"
+ "zero to 255.")
#define FUNC_NAME s_scm_send
{
int rv;
int fd;
int flg;
- const char *src;
+ char *src;
size_t len;
sock = SCM_COERCE_OUTPORT (sock);
SCM_VALIDATE_OPFPORT (1, sock);
SCM_VALIDATE_STRING (2, message);
+
+ /* If the string is wide, see if it can be coerced into
+ a narrow string. */
+ if (!scm_i_is_narrow_string (message)
+ || scm_i_try_narrow_string (message))
+ SCM_MISC_ERROR ("the message string is not 8-bit: ~s",
+ scm_list_1 (message));
+
if (SCM_UNBNDP (flags))
flg = 0;
else
fd = SCM_FPORT_FDES (sock);
len = scm_i_string_length (message);
+ message = scm_i_string_start_writing (message);
src = scm_i_string_writable_chars (message);
SCM_SYSCALL (rv = send (fd, src, len, flg));
scm_i_string_stop_writing ();
size_t cend;
SCM address;
socklen_t addr_size = MAX_ADDR_SIZE;
- char max_addr[MAX_ADDR_SIZE];
- struct sockaddr *addr = (struct sockaddr *) max_addr;
+ scm_t_max_sockaddr addr;
SCM_VALIDATE_OPFPORT (1, sock);
fd = SCM_FPORT_FDES (sock);
/* recvfrom will not necessarily return an address. usually nothing
is returned for stream sockets. */
+ str = scm_i_string_start_writing (str);
buf = scm_i_string_writable_chars (str);
- addr->sa_family = AF_UNSPEC;
+ ((struct sockaddr *) &addr)->sa_family = AF_UNSPEC;
SCM_SYSCALL (rv = recvfrom (fd, buf + offset,
cend - offset, flg,
- addr, &addr_size));
+ (struct sockaddr *) &addr, &addr_size));
scm_i_string_stop_writing ();
if (rv == -1)
SCM_SYSERROR;
- if (addr->sa_family != AF_UNSPEC)
- address = _scm_from_sockaddr (addr, addr_size, FUNC_NAME);
+ if (((struct sockaddr *) &addr)->sa_family != AF_UNSPEC)
+ address = _scm_from_sockaddr (&addr, addr_size, FUNC_NAME);
else
address = SCM_BOOL_F;
scm_remember_upto_here_1 (str);
+
return scm_cons (scm_from_int (rv), address);
}
#undef FUNC_NAME
"set to be non-blocking.\n"
"Note that the data is written directly to the socket\n"
"file descriptor:\n"
- "any unflushed buffered port data is ignored.")
+ "any unflushed buffered port data is ignored.\n"
+ "This operation is defined only for strings containing codepoints\n"
+ "zero to 255.")
#define FUNC_NAME s_scm_sendto
{
int rv;