-/* Copyright (C) 1996,1997,1998,2000,2001 Free Software Foundation, Inc.
+/* Copyright (C) 1996,1997,1998,2000,2001, 2002 Free Software Foundation, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
- *
- * As a special exception, the Free Software Foundation gives permission
- * for additional uses of the text contained in its release of GUILE.
- *
- * The exception is that, if you link the GUILE library with other files
- * to produce an executable, this does not by itself cause the
- * resulting executable to be covered by the GNU General Public License.
- * Your use of that executable is in no way restricted on account of
- * linking the GUILE library code into it.
+ * 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.
*
- * This exception does not however invalidate any other reasons why
- * the executable file might be covered by the GNU General Public License.
- *
- * This exception applies only to the code released by the
- * Free Software Foundation under the name GUILE. If you copy
- * code from other Free Software Foundation releases into a copy of
- * GUILE, as the General Public License permits, the exception does
- * not apply to the code that you add in this way. To avoid misleading
- * anyone as to the status of such modified files, you must delete
- * this exception notice from them.
+ * 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.
*
- * If you write modifications of your own for GUILE, it is your choice
- * whether to permit this exception to apply to your modifications.
- * If you do not wish that, delete this exception notice. */
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
\f
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include <errno.h>
+#include <gmp.h>
#include "libguile/_scm.h"
#include "libguile/unif.h"
+ strlen ((ptr)->sun_path))
#endif
-#if !defined (HAVE_UINT32_T)
-#if SIZEOF_INT == 4
-typedef unsigned int uint32_t;
-#elif SIZEOF_LONG == 4
-typedef unsigned long uint32_t;
-#else
-#error can not define uint32_t
-#endif
-#endif
-
/* we are not currently using socklen_t. it's not defined on all systems,
so would need to be checked by configure. in the meantime, plain
int is the best alternative. */
"and returned as a new integer.")
#define FUNC_NAME s_scm_htonl
{
- uint32_t c_in = SCM_NUM2ULONG (1, value);
+ scm_t_uint32 c_in = SCM_NUM2ULONG (1, value);
return scm_ulong2num (htonl (c_in));
}
"and returned as a new integer.")
#define FUNC_NAME s_scm_ntohl
{
- uint32_t c_in = SCM_NUM2ULONG (1, value);
+ scm_t_uint32 c_in = SCM_NUM2ULONG (1, value);
return scm_ulong2num (ntohl (c_in));
}
\
for (i = 0; i < 8; i++)\
{\
- char c = (addr)[i];\
+ scm_t_uint8 c = (addr)[i];\
\
(addr)[i] = (addr)[15 - i];\
(addr)[15 - i] = c;\
}
#endif
+#ifdef WORDS_BIGENDIAN
+#define FLIPCPY_NET_HOST_128(dest, src) memcpy (dest, src, 16)
+#else
+#define FLIPCPY_NET_HOST_128(dest, src) \
+{ \
+ const scm_t_uint8 *tmp_srcp = (src) + 15; \
+ scm_t_uint8 *tmp_destp = (dest); \
+ \
+ do { \
+ *tmp_destp++ = *tmp_srcp--; \
+ } while (tmp_srcp != (src)); \
+}
+#endif
+
+
+#if (SIZEOF_SCM_T_BITS * SCM_CHAR_BIT) > 128
+#error "Assumption that scm_t_bits <= 128 bits has been violated."
+#endif
+
+#if (SIZEOF_UNSIGNED_LONG * SCM_CHAR_BIT) > 128
+#error "Assumption that unsigned long <= 128 bits has been violated."
+#endif
+
+#if (SIZEOF_UNSIGNED_LONG_LONG * SCM_CHAR_BIT) > 128
+#error "Assumption that unsigned long long <= 128 bits has been violated."
+#endif
+
/* convert a 128 bit IPv6 address in network order to a host ordered
SCM integer. */
-static SCM ipv6_net_to_num (const char *src)
+static SCM ipv6_net_to_num (const scm_t_uint8 *src)
{
- int big_digits = 128 / SCM_BITSPERDIG;
- const int bytes_per_dig = SCM_BITSPERDIG / 8;
- char addr[16];
- char *ptr = addr;
- SCM result;
-
- memcpy (addr, src, 16);
- /* get rid of leading zeros. */
- while (big_digits > 0)
- {
- long test = 0;
+ int i = 0;
+ const scm_t_uint8 *ptr = src;
+ int num_zero_bytes = 0;
+ scm_t_uint8 addr[16];
- memcpy (&test, ptr, bytes_per_dig);
- if (test != 0)
- break;
- ptr += bytes_per_dig;
- big_digits--;
- }
- FLIP_NET_HOST_128 (addr);
- if (big_digits * bytes_per_dig <= sizeof (unsigned long))
+ /* count leading zeros (since we know it's bigendian, they'll be first) */
+ while (i < 16)
{
- /* this is just so that we use INUM where possible. */
- unsigned long l_addr;
+ if (*ptr) break;
+ num_zero_bytes++;
+ i++;
+ }
- memcpy (&l_addr, addr, sizeof (unsigned long));
- result = scm_ulong2num (l_addr);
+ if (SCM_SIZEOF_UNSIGNED_LONG_LONG != 0) /* compiler should optimize this */
+ {
+ if ((16 - num_zero_bytes) <= sizeof (unsigned long long))
+ {
+ /* it fits */
+ unsigned long long x;
+
+ FLIPCPY_NET_HOST_128(addr, src);
+#ifdef WORDS_BIGENDIAN
+ memcpy (&x, addr + (16 - sizeof (x)), sizeof (x));
+#else
+ memcpy (&x, addr, sizeof (x));
+#endif
+ return scm_ulong_long2num (x);
+ }
}
else
{
- result = scm_i_mkbig (big_digits, 0);
- memcpy (SCM_BDIGITS (result), addr, big_digits * bytes_per_dig);
+ if ((16 - num_zero_bytes) <= sizeof (unsigned long))
+ {
+ /* this is just so that we use INUM where possible. */
+ unsigned long x;
+
+ FLIPCPY_NET_HOST_128(addr, src);
+#ifdef WORDS_BIGENDIAN
+ memcpy (&x, addr + (16 - sizeof (x)), sizeof (x));
+#else
+ memcpy (&x, addr, sizeof (x));
+#endif
+ return scm_ulong2num (x);
+ }
}
- return result;
+ /* otherwise get the big hammer */
+ {
+ SCM result = scm_i_mkbig ();
+
+ mpz_import (SCM_I_BIG_MPZ (result),
+ 1, /* chunk */
+ 1, /* big-endian chunk ordering */
+ 16, /* chunks are 16 bytes long */
+ 1, /* big-endian byte ordering */
+ 0, /* "nails" -- leading unused bits per chunk */
+ src);
+ return scm_i_normbig (result);
+ }
}
/* convert a host ordered SCM integer to a 128 bit IPv6 address in
network order. */
-static void ipv6_num_to_net (SCM src, char *dst)
+static void ipv6_num_to_net (SCM src, scm_t_uint8 *dst)
{
+ /* This code presumes that src has already been checked for range. */
if (SCM_INUMP (src))
{
- uint32_t addr = htonl (SCM_INUM (src));
-
- memset (dst, 0, 12);
- memcpy (dst + 12, &addr, 4);
+ scm_t_signed_bits n = SCM_INUM (src);
+#ifdef WORDS_BIGENDIAN
+ memset (dst, 0, 16 - sizeof (scm_t_signed_bits));
+ memcpy (dst + (16 - sizeof (scm_t_signed_bits)),
+ &n,
+ sizeof (scm_t_signed_bits));
+#else
+ memset (dst + sizeof (scm_t_signed_bits),
+ 0,
+ 16 - sizeof (scm_t_signed_bits));
+ /* FIXME: this pair of ops is kinda wasteful -- should rewrite as
+ a single loop perhaps, similar to the handling of bignums. */
+ memcpy (dst, &n, sizeof (scm_t_signed_bits));
+ FLIP_NET_HOST_128 (dst);
+#endif
}
else
{
+ /* Presumes src has already been checked for fit -- see above. */
+ size_t count;
memset (dst, 0, 16);
- memcpy (dst, SCM_BDIGITS (src),
- SCM_NUMDIGS (src) * (SCM_BITSPERDIG / 8));
- FLIP_NET_HOST_128 (dst);
+ mpz_export (dst,
+ &count,
+ 1, /* big-endian chunk ordering */
+ 16, /* chunks are 16 bytes long */
+ 1, /* big-endian byte ordering */
+ 0, /* "nails" -- leading unused bits per chunk */
+ SCM_I_BIG_MPZ (src));
+ scm_remember_upto_here_1 (src);
+ }
+}
+
+static int
+bignum_in_ipv6_range_p (SCM address)
+{
+ int result;
+ int sgn = mpz_sgn (SCM_I_BIG_MPZ (address));
+
+ if (sgn < 0)
+ result = 0;
+ else
+ {
+ int size = mpz_sizeinbase (SCM_I_BIG_MPZ (address), 2);
+ if (size > 128) result = 0;
+ else result = 1;
}
+ scm_remember_upto_here_1 (address);
+ return result;
}
/* check that an SCM variable contains an IPv6 integer address. */
else\
{\
SCM_VALIDATE_BIGINT (which_arg, address);\
- SCM_ASSERT_RANGE (which_arg, address,\
- !SCM_BIGSIGN (address)\
- && (SCM_BITSPERDIG\
- * SCM_NUMDIGS (address) <= 128));\
+ SCM_ASSERT_RANGE (which_arg, address, bignum_in_ipv6_range_p);\
}
#ifdef HAVE_INET_PTON
else if (rv == 0)
SCM_MISC_ERROR ("Bad address", SCM_EOL);
if (af == AF_INET)
- return scm_ulong2num (ntohl (*(uint32_t *) dst));
+ return scm_ulong2num (ntohl (*(scm_t_uint32 *) dst));
else
return ipv6_net_to_num ((char *) dst);
}
SCM_VALIDATE_INUM_COPY (1, family, af);
SCM_ASSERT_RANGE (1, family, af == AF_INET || af == AF_INET6);
if (af == AF_INET)
- *(uint32_t *) addr6 = htonl (SCM_NUM2ULONG (2, address));
+ *(scm_t_uint32 *) addr6 = htonl (SCM_NUM2ULONG (2, address));
else
{
VALIDATE_INET6 (2, address);
int fam;
int fd[2];
- SCM_VALIDATE_INUM (1,family);
- SCM_VALIDATE_INUM (2,style);
- SCM_VALIDATE_INUM (3,proto);
+ SCM_VALIDATE_INUM (1, family);
+ SCM_VALIDATE_INUM (2, style);
+ SCM_VALIDATE_INUM (3, proto);
fam = SCM_INUM (family);
{
int fd;
sock = SCM_COERCE_OUTPORT (sock);
- SCM_VALIDATE_OPFPORT (1,sock);
- SCM_VALIDATE_INUM (2,how);
- SCM_ASSERT_RANGE(2,how,0 <= SCM_INUM (how) && 2 >= SCM_INUM (how));
+ SCM_VALIDATE_OPFPORT (1, sock);
+ SCM_VALIDATE_INUM (2, how);
+ SCM_ASSERT_RANGE(2, how,0 <= SCM_INUM (how) && 2 >= SCM_INUM (how));
fd = SCM_FPORT_FDES (sock);
if (shutdown (fd, SCM_INUM (how)) == -1)
SCM_SYSERROR;
SCM_VALIDATE_CONS (which_arg + 1, *args);
SCM_VALIDATE_INUM_COPY (which_arg + 1, SCM_CAR (*args), port);
*args = SCM_CDR (*args);
- soka = (struct sockaddr_in *) malloc (sizeof (struct sockaddr_in));
+ soka = (struct sockaddr_in *) scm_malloc (sizeof (struct sockaddr_in));
if (!soka)
scm_memory_error (proc);
/* 4.4BSD-style interface includes sin_len member and defines SIN_LEN,
*args = SCM_CDR (*args);
}
}
- soka = (struct sockaddr_in6 *) malloc (sizeof (struct sockaddr_in6));
+ soka = (struct sockaddr_in6 *) scm_malloc (sizeof (struct sockaddr_in6));
if (!soka)
scm_memory_error (proc);
#ifdef SIN_LEN6
member of the structure. */
addr_size = sizeof (struct sockaddr_un)
+ max (0, SCM_STRING_LENGTH (address) + 1 - (sizeof soka->sun_path));
- soka = (struct sockaddr_un *) malloc (addr_size);
+ soka = (struct sockaddr_un *) scm_malloc (addr_size);
if (!soka)
scm_memory_error (proc);
memset (soka, 0, addr_size); /* for sun_len: see sin_len above. */
int size;
sock = SCM_COERCE_OUTPORT (sock);
- SCM_VALIDATE_OPFPORT (1,sock);
- SCM_VALIDATE_INUM (2,fam);
+ SCM_VALIDATE_OPFPORT (1, sock);
+ SCM_VALIDATE_INUM (2, fam);
fd = SCM_FPORT_FDES (sock);
soka = scm_fill_sockaddr (SCM_INUM (fam), address, &args, 3, FUNC_NAME,
&size);
{
int fd;
sock = SCM_COERCE_OUTPORT (sock);
- SCM_VALIDATE_OPFPORT (1,sock);
- SCM_VALIDATE_INUM (2,backlog);
+ SCM_VALIDATE_OPFPORT (1, sock);
+ SCM_VALIDATE_INUM (2, backlog);
fd = SCM_FPORT_FDES (sock);
if (listen (fd, SCM_INUM (backlog)) == -1)
SCM_SYSERROR;
/* Put the components of a sockaddr into a new SCM vector. */
static SCM
-scm_addr_vector (const struct sockaddr *address, const char *proc)
+scm_addr_vector (const struct sockaddr *address, int addr_size,
+ const char *proc)
{
short int fam = address->sa_family;
- SCM result;
- SCM *ve;
+ SCM result =SCM_EOL;
+
switch (fam)
{
const struct sockaddr_in *nad = (struct sockaddr_in *) address;
result = scm_c_make_vector (3, SCM_UNSPECIFIED);
- ve = SCM_VELTS (result);
- ve[0] = scm_ulong2num ((unsigned long) fam);
- ve[1] = scm_ulong2num (ntohl (nad->sin_addr.s_addr));
- ve[2] = scm_ulong2num ((unsigned long) ntohs (nad->sin_port));
+
+ SCM_VECTOR_SET(result, 0, scm_ulong2num ((unsigned long) fam));
+ SCM_VECTOR_SET(result, 1, scm_ulong2num (ntohl (nad->sin_addr.s_addr)));
+ SCM_VECTOR_SET(result, 2, scm_ulong2num ((unsigned long) ntohs (nad->sin_port)));
}
break;
#ifdef HAVE_IPV6
const struct sockaddr_in6 *nad = (struct sockaddr_in6 *) address;
result = scm_c_make_vector (5, SCM_UNSPECIFIED);
- ve = SCM_VELTS (result);
- ve[0] = scm_ulong2num ((unsigned long) fam);
- ve[1] = ipv6_net_to_num (nad->sin6_addr.s6_addr);
- ve[2] = scm_ulong2num ((unsigned long) ntohs (nad->sin6_port));
- ve[3] = scm_ulong2num ((unsigned long) nad->sin6_flowinfo);
+ SCM_VECTOR_SET(result, 0, scm_ulong2num ((unsigned long) fam));
+ SCM_VECTOR_SET(result, 1, ipv6_net_to_num (nad->sin6_addr.s6_addr));
+ SCM_VECTOR_SET(result, 2, scm_ulong2num ((unsigned long) ntohs (nad->sin6_port)));
+ SCM_VECTOR_SET(result, 3, scm_ulong2num ((unsigned long) nad->sin6_flowinfo));
#ifdef HAVE_SIN6_SCOPE_ID
- ve[4] = scm_ulong2num ((unsigned long) nad->sin6_scope_id);
+ SCM_VECTOR_SET(result, 4, scm_ulong2num ((unsigned long) nad->sin6_scope_id));
#else
- ve[4] = SCM_INUM0;
+ SCM_VECTOR_SET(result, 4, SCM_INUM0);
#endif
}
break;
const struct sockaddr_un *nad = (struct sockaddr_un *) address;
result = scm_c_make_vector (2, SCM_UNSPECIFIED);
- ve = SCM_VELTS (result);
- ve[0] = scm_ulong2num ((unsigned long) fam);
- ve[1] = scm_mem2string (nad->sun_path, strlen (nad->sun_path));
+
+ SCM_VECTOR_SET(result, 0, scm_ulong2num ((unsigned long) fam));
+ /* When addr_size is not enough to cover sun_path, do not try
+ to access it. */
+ if (addr_size <= offsetof (struct sockaddr_un, sun_path))
+ SCM_VECTOR_SET(result, 1, SCM_BOOL_F);
+ else
+ SCM_VECTOR_SET(result, 1, scm_mem2string (nad->sun_path,
+ strlen (nad->sun_path)));
}
break;
#endif
if (newfd == -1)
SCM_SYSERROR;
newsock = SCM_SOCK_FD_TO_PORT (newfd);
- address = scm_addr_vector (addr, FUNC_NAME);
+ address = scm_addr_vector (addr, addr_size, FUNC_NAME);
return scm_cons (newsock, address);
}
#undef FUNC_NAME
struct sockaddr *addr = (struct sockaddr *) max_addr;
sock = SCM_COERCE_OUTPORT (sock);
- SCM_VALIDATE_OPFPORT (1,sock);
+ SCM_VALIDATE_OPFPORT (1, sock);
fd = SCM_FPORT_FDES (sock);
if (getsockname (fd, addr, &addr_size) == -1)
SCM_SYSERROR;
- return scm_addr_vector (addr, FUNC_NAME);
+ return scm_addr_vector (addr, addr_size, FUNC_NAME);
}
#undef FUNC_NAME
struct sockaddr *addr = (struct sockaddr *) max_addr;
sock = SCM_COERCE_OUTPORT (sock);
- SCM_VALIDATE_OPFPORT (1,sock);
+ SCM_VALIDATE_OPFPORT (1, sock);
fd = SCM_FPORT_FDES (sock);
if (getpeername (fd, addr, &addr_size) == -1)
SCM_SYSERROR;
- return scm_addr_vector (addr, FUNC_NAME);
+ return scm_addr_vector (addr, addr_size, FUNC_NAME);
}
#undef FUNC_NAME
int fd;
int flg;
- SCM_VALIDATE_OPFPORT (1,sock);
- SCM_VALIDATE_STRING (2,buf);
- SCM_VALIDATE_INUM_DEF_COPY (3,flags,0,flg);
+ SCM_VALIDATE_OPFPORT (1, sock);
+ SCM_VALIDATE_STRING (2, buf);
+ SCM_VALIDATE_INUM_DEF_COPY (3, flags,0, flg);
fd = SCM_FPORT_FDES (sock);
SCM_SYSCALL (rv = recv (fd, SCM_STRING_CHARS (buf), SCM_STRING_LENGTH (buf), flg));
int flg;
sock = SCM_COERCE_OUTPORT (sock);
- SCM_VALIDATE_OPFPORT (1,sock);
+ SCM_VALIDATE_OPFPORT (1, sock);
SCM_VALIDATE_STRING (2, message);
- SCM_VALIDATE_INUM_DEF_COPY (3,flags,0,flg);
+ SCM_VALIDATE_INUM_DEF_COPY (3, flags,0, flg);
fd = SCM_FPORT_FDES (sock);
SCM_SYSCALL (rv = send (fd, SCM_STRING_CHARS (message), SCM_STRING_LENGTH (message), flg));
char max_addr[MAX_ADDR_SIZE];
struct sockaddr *addr = (struct sockaddr *) max_addr;
- SCM_VALIDATE_OPFPORT (1,sock);
+ SCM_VALIDATE_OPFPORT (1, sock);
fd = SCM_FPORT_FDES (sock);
SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, str, buf, 4, start, offset,
5, end, cend);
if (rv == -1)
SCM_SYSERROR;
if (addr->sa_family != AF_UNSPEC)
- address = scm_addr_vector (addr, FUNC_NAME);
+ address = scm_addr_vector (addr, addr_size, FUNC_NAME);
else
address = SCM_BOOL_F;
int size;
sock = SCM_COERCE_OUTPORT (sock);
- SCM_VALIDATE_FPORT (1,sock);
+ SCM_VALIDATE_FPORT (1, sock);
SCM_VALIDATE_STRING (2, message);
- SCM_VALIDATE_INUM (3,fam);
+ SCM_VALIDATE_INUM (3, fam);
fd = SCM_FPORT_FDES (sock);
soka = scm_fill_sockaddr (SCM_INUM (fam), address, &args_and_flags, 4,
FUNC_NAME, &size);
flg = 0;
else
{
- SCM_VALIDATE_CONS (5,args_and_flags);
+ SCM_VALIDATE_CONS (5, args_and_flags);
flg = SCM_NUM2ULONG (5, SCM_CAR (args_and_flags));
}
SCM_SYSCALL (rv = sendto (fd, SCM_STRING_CHARS (message),