From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: ludovic.courtes@laas.fr (Ludovic =?iso-8859-1?Q?Court=E8s?=) Newsgroups: gmane.lisp.guile.user Subject: Re: Exposing common type wrapping/unwrapping methods Date: Wed, 07 Sep 2005 11:49:25 +0200 Organization: LAAS-CNRS Message-ID: <87mzmpmcm2.fsf@laas.fr> References: <87oecutxox.fsf@laas.fr> <87vf58cxxq.fsf@zagadka.de> <87k6kwopv5.fsf@laas.fr> <87fysk7ady.fsf@zagadka.de> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1126087416 27561 80.91.229.2 (7 Sep 2005 10:03:36 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Wed, 7 Sep 2005 10:03:36 +0000 (UTC) Cc: guile-user@gnu.org Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Wed Sep 07 12:03:27 2005 Return-path: Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1ECwk7-0000c2-If for guile-user@m.gmane.org; Wed, 07 Sep 2005 12:01:24 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ECwdt-0006vP-DQ for guile-user@m.gmane.org; Wed, 07 Sep 2005 05:54:57 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1ECwdN-0006qE-2O for guile-user@gnu.org; Wed, 07 Sep 2005 05:54:25 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1ECwdH-0006nu-Bl for guile-user@gnu.org; Wed, 07 Sep 2005 05:54:20 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ECwdH-0006nV-53 for guile-user@gnu.org; Wed, 07 Sep 2005 05:54:19 -0400 Original-Received: from [140.93.0.15] (helo=laas.laas.fr) by monty-python.gnu.org with esmtp (TLS-1.0:DHE_RSA_3DES_EDE_CBC_SHA:24) (Exim 4.34) id 1ECwcW-0003bj-I2 for guile-user@gnu.org; Wed, 07 Sep 2005 05:53:32 -0400 Original-Received: by laas.laas.fr (8.13.1/8.13.1) with SMTP id j879n2xH010010; Wed, 7 Sep 2005 11:49:05 +0200 (CEST) Original-To: Marius Vollmer X-URL: http://www.laas.fr/~lcourtes/ X-Revolutionary-Date: 21 Fructidor an 213 de la =?iso-8859-1?Q?R=E9volutio?= =?iso-8859-1?Q?n?= X-PGP-Key-ID: 0xEB1F5364 X-PGP-Key: http://www.laas.fr/~lcourtes/ludovic.asc X-PGP-Fingerprint: 821D 815D 902A 7EAB 5CEE D120 7FBA 3D4F EB1F 5364 X-OS: powerpc-unknown-linux-gnu In-Reply-To: <87fysk7ady.fsf@zagadka.de> (Marius Vollmer's message of "Mon, 05 Sep 2005 01:09:45 +0300") User-Agent: Gnus/5.110004 (No Gnus v0.4) Emacs/21.4 (gnu/linux) X-Spam-Score: 0 () X-Scanned-By: MIMEDefang at CNRS-LAAS X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-user-bounces+guile-user=m.gmane.org@gnu.org Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.user:4722 Archived-At: Hi Marius, Marius Vollmer writes: > Hmm, I think your patch mixes the two ways we have to express a socket > address: one way is an argument convention used by connect, bind, and > sendto; the other way is a vector with the relevant data inside, as > returned by accept, getsockname, getpeername, and recvfrom!. Right. I followed your suggestion (with slight modifications, namely have an ADDRESS_SIZE output parameter for functions that return a pointer to `struct sockaddr') and updated my patch. However, the only thing I tested is `scm_from_sockaddr ()' on AF_INET addresses. If this looks good to you, then I guess I can update the doc, see what we can do with `scm_connect ()' and the likes, and submit a new patch. Thanks, Ludovic. Index: socket.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/socket.c,v retrieving revision 1.115 diff -u -B -b -p -r1.115 socket.c --- socket.c 10 Jul 2005 01:56:07 -0000 1.115 +++ socket.c 7 Sep 2005 09:41:40 -0000 @@ -664,7 +664,7 @@ SCM_DEFINE (scm_shutdown, "shutdown", 2, proc is the name of the original procedure. size returns the size of the structure allocated. */ -static struct sockaddr * +static SCM_C_INLINE_KEYWORD struct sockaddr * scm_fill_sockaddr (int fam, SCM address, SCM *args, int which_arg, const char *proc, int *size) #define FUNC_NAME proc @@ -893,8 +894,8 @@ SCM_DEFINE (scm_listen, "listen", 2, 0, #undef FUNC_NAME /* Put the components of a sockaddr into a new SCM vector. */ -static SCM -scm_addr_vector (const struct sockaddr *address, int addr_size, +static SCM_C_INLINE_KEYWORD SCM +_scm_from_sockaddr (const struct sockaddr *address, unsigned addr_size, const char *proc) { short int fam = address->sa_family; @@ -953,8 +954,10 @@ scm_addr_vector (const struct sockaddr * break; #endif default: - scm_misc_error (proc, "Unrecognised address family: ~A", + result = SCM_UNSPECIFIED; + scm_misc_error (proc, "unrecognised address family: ~A", scm_list_1 (scm_from_int (fam))); + } return result; } @@ -959,6 +962,182 @@ scm_addr_vector (const struct sockaddr * return result; } +/* The publicly-visible function. Return a Scheme object representing + ADDRESS, an address of ADDR_SIZE bytes. */ +SCM +scm_from_sockaddr (const struct sockaddr *address, unsigned addr_size) +{ + return (_scm_from_sockaddr (address, addr_size, "scm_from_sockaddr")); +} + +/* Convert ADDRESS, an address object returned by either + `scm_from_sockaddr ()' or `scm_make_socket_address ()', into its C + representation. On success, a non-NULL pointer is returned and + ADDRESS_SIZE is updated to the actual size (in bytes) of the returned + address. The result must eventually be freed using `free ()'. */ +struct sockaddr * +scm_to_sockaddr (SCM address, size_t *address_size) +#define FUNC_NAME "scm_to_sockaddr" +{ + short int family; + struct sockaddr *c_address = NULL; + + SCM_VALIDATE_VECTOR (1, address); + + *address_size = 0; + family = scm_to_short (SCM_SIMPLE_VECTOR_REF (address, 0)); + + switch (family) + { + case AF_INET: + { + struct sockaddr_in *c_inet; + + if (SCM_SIMPLE_VECTOR_LENGTH (address) != 3) + scm_misc_error (FUNC_NAME, "invalid inet address representation: ~A", + scm_list_1 (address)); + else + { + c_address = scm_malloc (sizeof (struct sockaddr_in)); + c_inet = (struct sockaddr_in *)c_address; + c_inet->sin_addr.s_addr = + htonl (scm_to_long (SCM_SIMPLE_VECTOR_REF (address, 1))); + c_inet->sin_port = + htons (scm_to_ushort (SCM_SIMPLE_VECTOR_REF (address, 2))); + + *address_size = sizeof (*c_inet); + } + + break; + } + +#ifdef HAVE_IPV6 + case AF_INET6: + { + struct sockaddr_in6 *c_inet6; + + if (SCM_SIMPLE_VECTOR_LENGTH (address) != 5) + scm_misc_error (FUNC_NAME, "invalid inet6 address representation: ~A", + scm_list_1 (address)); + else + { + c_address = scm_malloc (sizeof (struct sockaddr_in6)); + c_inet6 = (struct sockaddr_in6 *)c_address; + scm_to_ipv6 (c_inet6->sin6_addr.s6_addr, address); + c_inet6->sin6_port = + htons (scm_to_ushort (SCM_SIMPLE_VECTOR_REF (address, 2))); + c_inet6->sin6_flowinfo = + scm_to_uint32 (SCM_SIMPLE_VECTOR_REF (address, 3)); +#ifdef HAVE_SIN6_SCOPE_ID + c_inet6->sin6_scope_id = + scm_to_ulong (SCM_SIMPLE_VECTOR_REF (address, 4)); +#endif + + *address_size = sizeof (*c_inet6); + } + + break; + } +#endif + +#ifdef HAVE_UNIX_DOMAIN_SOCKETS + case AF_UNIX: + { + struct sockaddr_un *c_unix; + + if (SCM_SIMPLE_VECTOR_LENGTH (address) != 2) + scm_misc_error (FUNC_NAME, "invalid unix address representation: ~A", + scm_list_1 (address)); + else + { + SCM path; + size_t path_len = 0; + + path = SCM_SIMPLE_VECTOR_REF (address, 1); + if ((!scm_is_string (path)) && (path != SCM_BOOL_F)) + scm_misc_error (FUNC_NAME, "invalid unix address " + "path: ~A", scm_list_1 (path)); + else + { + if (path == SCM_BOOL_F) + path_len = 0; + else + path_len = scm_c_string_length (path); + +#ifndef UNIX_PATH_MAX +/* We can hope that this limit will eventually vanish, at least in GNU. + However, currently, while glibc doesn't define `UNIX_PATH_MAX', it + documents it has being limited to 108 bytes. */ +# define UNIX_PATH_MAX 108 +#endif + if (path_len >= UNIX_PATH_MAX) + scm_misc_error (FUNC_NAME, "unix address path " + "too long: ~A", scm_list_1 (path)); + else + { + if (path_len) + { + scm_to_locale_stringbuf (path, c_unix->sun_path, + UNIX_PATH_MAX); + c_unix->sun_path[path_len - 1] = '\0'; + } + else + c_unix->sun_path[0] = '\0'; + + *address_size = SUN_LEN (c_unix); + } + } + } + + break; + } +#endif + + default: + scm_misc_error (FUNC_NAME, "unrecognised address family: ~A", + scm_list_1 (scm_from_ushort (family))); + } + + return c_address; +} +#undef FUNC_NAME + + +/* Return a newly-allocated `sockaddr' structure that reflects ADDRESS, being + an address of family FAMILY, with the family-specific parameters ARGS (see + the description of `connect' for details). The returned structure may be + freed using `free ()'. */ +struct sockaddr * +scm_c_make_socket_address (SCM family, SCM address, SCM args, + size_t *address_size) +{ + size_t size; + struct sockaddr *soka; + + soka = scm_fill_sockaddr (scm_to_ushort (family), address, &args, 1, + "scm_c_make_socket_address", &size); + + return soka; +} + +/* Return a Scheme address object that reflects ADDRESS, being an address of + family FAMILY, with the family-specific parameters ARGS (see the + description of `connect' for details). */ +SCM +scm_make_socket_address (SCM family, SCM address, SCM args) +{ + 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; + + return (scm_from_sockaddr (c_address, c_address_size)); +} + + /* 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. */ @@ -1009,7 +1188,7 @@ SCM_DEFINE (scm_accept, "accept", 1, 0, if (newfd == -1) SCM_SYSERROR; newsock = SCM_SOCK_FD_TO_PORT (newfd); - address = scm_addr_vector (addr, addr_size, FUNC_NAME); + address = _scm_from_sockaddr (addr, addr_size, FUNC_NAME); return scm_cons (newsock, address); } #undef FUNC_NAME @@ -1031,7 +1210,7 @@ SCM_DEFINE (scm_getsockname, "getsocknam fd = SCM_FPORT_FDES (sock); if (getsockname (fd, addr, &addr_size) == -1) SCM_SYSERROR; - return scm_addr_vector (addr, addr_size, FUNC_NAME); + return _scm_from_sockaddr (addr, addr_size, FUNC_NAME); } #undef FUNC_NAME @@ -1053,7 +1232,7 @@ SCM_DEFINE (scm_getpeername, "getpeernam fd = SCM_FPORT_FDES (sock); if (getpeername (fd, addr, &addr_size) == -1) SCM_SYSERROR; - return scm_addr_vector (addr, addr_size, FUNC_NAME); + return _scm_from_sockaddr (addr, addr_size, FUNC_NAME); } #undef FUNC_NAME @@ -1207,7 +1386,7 @@ SCM_DEFINE (scm_recvfrom, "recvfrom!", 2 if (rv == -1) SCM_SYSERROR; if (addr->sa_family != AF_UNSPEC) - address = scm_addr_vector (addr, addr_size, FUNC_NAME); + address = _scm_from_sockaddr (addr, addr_size, FUNC_NAME); else address = SCM_BOOL_F; Index: socket.h =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/socket.h,v retrieving revision 1.17 diff -u -B -b -p -r1.17 socket.h --- socket.h 23 May 2005 19:57:21 -0000 1.17 +++ socket.h 7 Sep 2005 09:41:40 -0000 @@ -54,6 +54,16 @@ SCM_API SCM scm_recvfrom (SCM sockfd, SC SCM_API SCM scm_sendto (SCM sockfd, SCM message, SCM fam, SCM address, SCM args_and_flags); SCM_API void scm_init_socket (void); +/* Wrapping/unwrapping address objects. */ +struct sockaddr; +SCM_API SCM scm_from_sockaddr (const struct sockaddr *address, + unsigned addr_size); +SCM_API struct sockaddr *scm_to_sockaddr (SCM address, size_t *adress_size); +SCM_API struct sockaddr *scm_c_make_socket_address (SCM family, SCM address, + SCM args, + size_t *address_size); +SCM_API SCM scm_make_socket_address (SCM family, SCM address, SCM args); + #endif /* SCM_SOCKET_H */ /* _______________________________________________ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user