unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Exposing common type wrapping/unwrapping methods
@ 2005-04-04 14:37 Ludovic Courtès
  2005-05-24 17:53 ` Marius Vollmer
  0 siblings, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-04-04 14:37 UTC (permalink / raw)


Hi,

Most type wrapping/unwrapping methods that are used within Guile are not
exposed to the user, which is a pity.  For example, `scm_addr_vector'
(in socket.c) which converts a `sockaddr' structure to its Scheme
representation (a vector) is defined as `static'.  This leaves the C
programmer with the following alternative:

* use, e.g., `scm_connect ()' instead of `connect ()' in its C code;

* define a new SMOB (or other representation) for `sockaddr' that may be
  incompatible with Guile's representation of this C type;

* copy/paste Guile's conversion methods, hoping that they're going to
  remain valid.


Obviously, the best solution would be to expose the relevant functions
to the user.  :-)

What do you think?

Thanks,
Ludovic.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-04-04 14:37 Exposing common type wrapping/unwrapping methods Ludovic Courtès
@ 2005-05-24 17:53 ` Marius Vollmer
  2005-06-14 16:38   ` Ludovic Courtès
  0 siblings, 1 reply; 29+ messages in thread
From: Marius Vollmer @ 2005-05-24 17:53 UTC (permalink / raw)
  Cc: guile-user

ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Obviously, the best solution would be to expose the relevant functions
> to the user.  :-)

Yes, we should do that, following the scm_to and scm_from naming scheme.

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-05-24 17:53 ` Marius Vollmer
@ 2005-06-14 16:38   ` Ludovic Courtès
  2005-08-19  7:57     ` Ludovic Courtès
  2005-09-04 22:09     ` Marius Vollmer
  0 siblings, 2 replies; 29+ messages in thread
From: Ludovic Courtès @ 2005-06-14 16:38 UTC (permalink / raw)
  Cc: guile-user

Hi,

Marius Vollmer <mvo@zagadka.de> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
>> Obviously, the best solution would be to expose the relevant functions
>> to the user.  :-)
>
> Yes, we should do that, following the scm_to and scm_from naming scheme.

Following this discussion, I propose the following addition which
exposes the wrapping/unwrapping functions of `sockaddr' objects.

Thanks,
Ludovic.


2005-06-14  Ludovic Courtès  <ludovic.courtes@laas.fr>

	* socket.c (scm_addr_vector):  Renamed to `_scm_from_sockaddr'
	and made inline.
	(scm_from_sockaddr):  New function.
	(scm_to_sockaddr):  New function.
	(scm_fill_sockaddr):  Made inline.

	* socket.h (scm_from_sockaddr):  New declaration.
	(scm_to_sockaddr):  New declaration.


Index: socket.c
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/socket.c,v
retrieving revision 1.114
diff -u -B -b -r1.114 socket.c
--- socket.c	5 Jun 2005 18:27:53 -0000	1.114
+++ socket.c	14 Jun 2005 16:26:51 -0000
@@ -664,7 +664,7 @@
    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
@@ -769,6 +769,22 @@
 }
 #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_to_sockaddr (int family, SCM address, SCM args)
+{
+  size_t size;
+  struct sockaddr *soka;
+
+  soka = scm_fill_sockaddr (family, address, &args, 1,
+			    "scm_to_sockaddr", &size);
+
+  return soka;
+}
+
 SCM_DEFINE (scm_connect, "connect", 3, 0, 1,
             (SCM sock, SCM fam, SCM address, SCM args),
 	    "Initiate a connection from a socket using a specified address\n"
@@ -893,8 +909,8 @@
 #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 +969,10 @@
       break;
 #endif
     default:
+      result = SCM_UNSPECIFIED;
       scm_misc_error (proc, "Unrecognised address family: ~A",
 		      scm_list_1 (scm_from_int (fam)));
+
     }
   return result;
 }
@@ -959,6 +977,14 @@
   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"));
+}
+
 /* 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 +1035,7 @@
   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 +1057,7 @@
   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 +1079,7 @@
   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 +1233,7 @@
   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 -r1.17 socket.h
--- socket.h	23 May 2005 19:57:21 -0000	1.17
+++ socket.h	14 Jun 2005 16:26:51 -0000
@@ -54,6 +54,11 @@
 SCM_API SCM scm_sendto (SCM sockfd, SCM message, SCM fam, SCM address, SCM args_and_flags);
 SCM_API void scm_init_socket (void);
 
+struct sockaddr;
+SCM_API SCM scm_from_sockaddr (const struct sockaddr *address,
+			       unsigned addr_size);
+SCM_API struct sockaddr *scm_to_sockaddr (int 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


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-06-14 16:38   ` Ludovic Courtès
@ 2005-08-19  7:57     ` Ludovic Courtès
  2005-08-20  6:01       ` Ken Raeburn
  2005-09-04 22:09     ` Marius Vollmer
  1 sibling, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-08-19  7:57 UTC (permalink / raw)
  Cc: Marius Vollmer

Hello,

It seems that the email below (<87k6kwopv5.fsf@laas.fr>) got lost.  Can
someone comment on this?

Thanks,
Ludovic.

ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Hi,
>
> Marius Vollmer <mvo@zagadka.de> writes:
>
>> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>>
>>> Obviously, the best solution would be to expose the relevant functions
>>> to the user.  :-)
>>
>> Yes, we should do that, following the scm_to and scm_from naming scheme.
>
> Following this discussion, I propose the following addition which
> exposes the wrapping/unwrapping functions of `sockaddr' objects.
>
> Thanks,
> Ludovic.
>
>
> 2005-06-14  Ludovic Courtès  <ludovic.courtes@laas.fr>
>
> 	* socket.c (scm_addr_vector):  Renamed to `_scm_from_sockaddr'
> 	and made inline.
> 	(scm_from_sockaddr):  New function.
> 	(scm_to_sockaddr):  New function.
> 	(scm_fill_sockaddr):  Made inline.
>
> 	* socket.h (scm_from_sockaddr):  New declaration.
> 	(scm_to_sockaddr):  New declaration.
>
>
> Index: socket.c
> ===================================================================
> RCS file: /cvsroot/guile/guile/guile-core/libguile/socket.c,v
> retrieving revision 1.114
> diff -u -B -b -r1.114 socket.c
> --- socket.c	5 Jun 2005 18:27:53 -0000	1.114
> +++ socket.c	14 Jun 2005 16:26:51 -0000
> @@ -664,7 +664,7 @@
>     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
> @@ -769,6 +769,22 @@
>  }
>  #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_to_sockaddr (int family, SCM address, SCM args)
> +{
> +  size_t size;
> +  struct sockaddr *soka;
> +
> +  soka = scm_fill_sockaddr (family, address, &args, 1,
> +			    "scm_to_sockaddr", &size);
> +
> +  return soka;
> +}
> +
>  SCM_DEFINE (scm_connect, "connect", 3, 0, 1,
>              (SCM sock, SCM fam, SCM address, SCM args),
>  	    "Initiate a connection from a socket using a specified address\n"
> @@ -893,8 +909,8 @@
>  #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 +969,10 @@
>        break;
>  #endif
>      default:
> +      result = SCM_UNSPECIFIED;
>        scm_misc_error (proc, "Unrecognised address family: ~A",
>  		      scm_list_1 (scm_from_int (fam)));
> +
>      }
>    return result;
>  }
> @@ -959,6 +977,14 @@
>    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"));
> +}
> +
>  /* 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 +1035,7 @@
>    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 +1057,7 @@
>    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 +1079,7 @@
>    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 +1233,7 @@
>    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 -r1.17 socket.h
> --- socket.h	23 May 2005 19:57:21 -0000	1.17
> +++ socket.h	14 Jun 2005 16:26:51 -0000
> @@ -54,6 +54,11 @@
>  SCM_API SCM scm_sendto (SCM sockfd, SCM message, SCM fam, SCM address, SCM args_and_flags);
>  SCM_API void scm_init_socket (void);
>  
> +struct sockaddr;
> +SCM_API SCM scm_from_sockaddr (const struct sockaddr *address,
> +			       unsigned addr_size);
> +SCM_API struct sockaddr *scm_to_sockaddr (int 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


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-08-19  7:57     ` Ludovic Courtès
@ 2005-08-20  6:01       ` Ken Raeburn
  2005-08-20 12:40         ` Marius Vollmer
  0 siblings, 1 reply; 29+ messages in thread
From: Ken Raeburn @ 2005-08-20  6:01 UTC (permalink / raw)


On Aug 19, 2005, at 03:57, Ludovic Courtès wrote:
>> +/* 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_to_sockaddr (int family, SCM address, SCM args)

This reminds me... was there ever a decision on the "call malloc and  
free from the same object on Windows" issue?  I found some old  
discussion in the guile-devel mail archive in late 2001, between  
stefan and Dirk mostly, but I don't see a resolution.

Basically, malloc and free referenced from a DLL, say libguile.dll,  
may be different instances of the functions than the application or  
other DLLs might see, and they should thus be assumed to have  
different allocation pools that can't be mixed.  If a chunk of  
storage is allocated by one DLL's notion of "malloc", then it must be  
freed by that same DLL's notion of "free".  (I worded it a little  
funny here, because function pointers could be passed around such  
that, for example, the library always uses the application's  
allocator, or the application can allocate storage from the library's  
pool; shim functions work too.)  Interfaces like this, where the DLL  
allocates and the main program frees, can cause corruption.

Or, you just don't build DLLs for some packages.

Ken

_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-08-20  6:01       ` Ken Raeburn
@ 2005-08-20 12:40         ` Marius Vollmer
  2005-08-20 13:53           ` Ken Raeburn
  0 siblings, 1 reply; 29+ messages in thread
From: Marius Vollmer @ 2005-08-20 12:40 UTC (permalink / raw)
  Cc: guile-user

Ken Raeburn <raeburn@raeburn.org> writes:

> This reminds me... was there ever a decision on the "call malloc and
> free from the same object on Windows" issue?

My decision at that time was that we assume that there is only one
malloc and one free.

> Basically, malloc and free referenced from a DLL, say libguile.dll,
> may be different instances of the functions than the application or
> other DLLs might see, and they should thus be assumed to have
> different allocation pools that can't be mixed.

Is this merely technically possible or are people actually using this
'feature'?  Is it considered a godd practice?  Why should we agree?

Can we require libguile.dll to use the systems libc malloc and free?
We could put this in the documentation then so that people know which
variant of malloc and free to use together with libguile.dll.

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-08-20 12:40         ` Marius Vollmer
@ 2005-08-20 13:53           ` Ken Raeburn
  2005-09-04 22:17             ` Marius Vollmer
  0 siblings, 1 reply; 29+ messages in thread
From: Ken Raeburn @ 2005-08-20 13:53 UTC (permalink / raw)
  Cc: guile-user

On Aug 20, 2005, at 08:40, Marius Vollmer wrote:
> My decision at that time was that we assume that there is only one
> malloc and one free.

Okay.

>> Basically, malloc and free referenced from a DLL, say libguile.dll,
>> may be different instances of the functions than the application or
>> other DLLs might see, and they should thus be assumed to have
>> different allocation pools that can't be mixed.
>
> Is this merely technically possible or are people actually using this
> 'feature'?  Is it considered a godd practice?  Why should we agree?
>
> Can we require libguile.dll to use the systems libc malloc and free?
> We could put this in the documentation then so that people know which
> variant of malloc and free to use together with libguile.dll.

I'm not an expert in this area, but my understanding is:
"The system's libc" is part of the problem here -- there's no special  
DLL which is *the* C runtime library.  You can use MSVCRT.DLL, or  
MSVCR71.DLL, or MSVCRTD.DLL, and perhaps others, depending on the  
compiler, compiler version, and compiler options you use for each  
component.  You can also link the C runtime into your executable, but  
its symbols may not be seen by the DLLs, I think.

It's all well and good if you can tell someone that they have to use  
the same compiler and options for building the executable as for  
building the library, but it gets messy if someone might be providing  
a pre-built DLL.

Ken


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-06-14 16:38   ` Ludovic Courtès
  2005-08-19  7:57     ` Ludovic Courtès
@ 2005-09-04 22:09     ` Marius Vollmer
  2005-09-07  9:49       ` Ludovic Courtès
  1 sibling, 1 reply; 29+ messages in thread
From: Marius Vollmer @ 2005-09-04 22:09 UTC (permalink / raw)
  Cc: guile-user

ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Following this discussion, I propose the following addition which
> exposes the wrapping/unwrapping functions of `sockaddr' objects.

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!.

The scm_from_ and scm_to_ functions are meant to convert between a C
representation and a Scheme representation of some value.  Thus, one
should be able to do things like

   scm_equal_p (OBJ, scm_from_sockaddr (scm_to_sockaddr (OBJ)))

for example, and ideally get #t.

Thus, I propose the following functions:

   - SCM scm_from_sockaddr (const struct sockaddr *addr, size_t addr_size);

   Return the SCM representation of ADDR, which is a vector ...

   - struct sockaddr *scm_to_sockaddr (SCM addr);

   Return a newly-allocated `sockaddr' structure that reflects ADDR,
   which is a SCM vector as returned by scm_from_sockaddr, scm_accept,
   etc.  The returned structure may be freed using `free ()'.

   - SCM scm_make_socket_address (SCM fam, SCM address, SCM args);

   Construct a socket address like connect would given the three
   arguments and return it.

   - struct sockaddr *scm_c_make_socket_address (SCM fam, SCM address,
                                                 SCM args);

   Equivalent to scm_to_sockaddr (scm_make_socket_address (...)).

Also, scm_connect, scm_bind, and scm_sendto should probably be changed
to accept a SCM representation of a socket address, so that you could
write, for example:

   (connect sock (make-socket-address ...))

That change should be backwards compatible, of course, which is a
little bit of pain because of the C API...

Ludovic, could you update your patch if you agree?

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-08-20 13:53           ` Ken Raeburn
@ 2005-09-04 22:17             ` Marius Vollmer
  2005-09-07  4:17               ` Rob Browning
  0 siblings, 1 reply; 29+ messages in thread
From: Marius Vollmer @ 2005-09-04 22:17 UTC (permalink / raw)
  Cc: guile-user

Ken Raeburn <raeburn@raeburn.org> writes:

> I'm not an expert in this area, but my understanding is: [...]

Thanks for the input...  */me scratches head* ... this is what the
heathens call their "DLL hell", right?

I would have to see a concrete patch to have a more concrete opinion.
Right now, I don't plan to do anything about this.

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-09-04 22:17             ` Marius Vollmer
@ 2005-09-07  4:17               ` Rob Browning
  0 siblings, 0 replies; 29+ messages in thread
From: Rob Browning @ 2005-09-07  4:17 UTC (permalink / raw)
  Cc: guile-user, Ken Raeburn

Marius Vollmer <mvo@zagadka.de> writes:

> Thanks for the input...  */me scratches head* ... this is what the
> heathens call their "DLL hell", right?

Perhaps.  In case it's relevant, I believe this may be why libtool
provides lt_dlmalloc, lt_dlrealloc, and lt_dlfree.  See the libtool
info pages:

 -- Variable: lt_ptr (*) (size_t SIZE) lt_dlmalloc
 -- Variable: lt_ptr (*) (lt_ptr PTR, size_t SIZE) lt_dlrealloc
 -- Variable: void (*) (lt_ptr PTR) lt_dlfree
     These variables are set to `malloc', `realloc' and `free' by
     default, but you can set them to any other functions that provide
     equivalent functionality.  If you change any of these function
     pointers, you will almost certainly need to change all three to
     point into the same malloc library.  Strange things will happen if
     you allocate memory from one library, and then pass it to an
     implementation of `free' that doesn't know what book keeping the
     allocator used.

     You must not modify any of their values after calling any libltdl
     function other than `lt_dlpreopen_default' or the macro
     `LTDL_SET_PRELOADED_SYMBOLS'.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-09-04 22:09     ` Marius Vollmer
@ 2005-09-07  9:49       ` Ludovic Courtès
  2005-09-21  9:16         ` Ludovic Courtès
  0 siblings, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-09-07  9:49 UTC (permalink / raw)
  Cc: guile-user

Hi Marius,

Marius Vollmer <mvo@zagadka.de> 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.


\f
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));
+}
+
+\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.  */
@@ -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


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-09-07  9:49       ` Ludovic Courtès
@ 2005-09-21  9:16         ` Ludovic Courtès
  2005-09-22  0:14           ` Kevin Ryde
  0 siblings, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-09-21  9:16 UTC (permalink / raw)
  Cc: guile-user

Hi,

ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> 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.

Below is an updated patch that fixes two bugs in `scm_to_sockaddr ()'
and modifies `scm_connect ()', `scm_bind ()', and `scm_sendto ()'
according to Marius' suggestion.  This means that there are now two ways
to use them from Scheme, but their C API remains unchanged.  Here is an
example:

  guile> (define s (socket AF_INET SOCK_STREAM 0))
  guile> (define host (gethostbyname "www.gnu.org"))
  guile> host
  #("gnu.org" ("www.gnu.org") 2 4 (3353880842))
  guile> (define sc (connect s AF_INET 3353880842 80))
  guile> (define sa (make-socket-address AF_INET 3353880842 80))
  guile> (define s2 (socket AF_INET SOCK_STREAM 0))
  guile> (define sc2 (connect s2 sa))

Again, I only tested AF_INET addresses and I didn't try `sendto' and
`bind'.  Is there any test case out there or a program that could serve
as a test case?  Unfortunately, the old Guile-WWW available in Debian
cannot be used with Guile 1.7 because of the unavailability of
`make-shared-substring'.

I also emailed `assign@gnu.org' so that they could send me the copyright
assignment forms if that is necessary.

Thanks,
Ludovic.


ChangeLog entry for libguile:

2005-09-21  Ludovic Courtès  <ludovic.courtes@laas.fr>

	* socket.c (scm_fill_sockaddr):  Added SCM_C_INLINE_KEYWORD.
	Changed the type of SIZE to `size_t'.
	(scm_connect):  Accept a socket address object as the second argument.
	(scm_bind):  Likewise.
	(scm_sendto):  Likewise.
	(scm_addr_vector):  Renamed to `_scm_from_sockaddr'.
	(scm_from_sockaddr):  New function.
	(scm_to_sockaddr):  New function.
	(scm_c_make_socket_address):  New function.
	(scm_make_socket_address):  New function.

	* socket.h:  Added declarations of the above new functions.

\f
--- orig/libguile/socket.c
+++ mod/libguile/socket.c
@@ -664,9 +664,9 @@
    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)
+		   const char *proc, size_t *size)
 #define FUNC_NAME proc
 {
   switch (fam)
@@ -768,9 +768,9 @@
     }
 }
 #undef FUNC_NAME
-  
-SCM_DEFINE (scm_connect, "connect", 3, 0, 1,
-            (SCM sock, SCM fam, SCM address, SCM args),
+
+SCM_DEFINE (scm_connect, "connect", 2, 1, 1,
+            (SCM sock, SCM fam_or_sockaddr, SCM address, SCM args),
 	    "Initiate a connection from a socket using a specified address\n"
 	    "family to the address\n"
 	    "specified by @var{address} and possibly @var{args}.\n"
@@ -787,22 +787,32 @@
 	    "@var{args} may be up to three integers:\n"
 	    "port [flowinfo] [scope_id],\n"
 	    "where flowinfo and scope_id default to zero.\n\n"
+	    "Alternatively, the second argument can be a socket address object "
+	    "as returned by @code{make-socket-address}, in which case the "
+	    "no additional arguments should be passed.\n\n"
 	    "The return value is unspecified.")
 #define FUNC_NAME s_scm_connect
 {
   int fd;
   struct sockaddr *soka;
-  int size;
+  size_t size;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_OPFPORT (1, sock);
   fd = SCM_FPORT_FDES (sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args, 3, FUNC_NAME,
-			    &size);
+
+  if (address == SCM_UNDEFINED)
+    /* No third argument was passed to FAM_OR_SOCKADDR must actually be a
+       `socket address' object.  */
+    soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args, 3, FUNC_NAME, &size);
+
   if (connect (fd, soka, size) == -1)
     {
       int save_errno = errno;
-      
+
       free (soka);
       errno = save_errno;
       SCM_SYSERROR;
@@ -812,8 +822,8 @@
 }
 #undef FUNC_NAME
 
-SCM_DEFINE (scm_bind, "bind", 3, 0, 1,
-            (SCM sock, SCM fam, SCM address, SCM args),
+SCM_DEFINE (scm_bind, "bind", 2, 1, 1,
+            (SCM sock, SCM fam_or_sockaddr, SCM address, SCM args),
 	    "Assign an address to the socket port @var{sock}.\n"
 	    "Generally this only needs to be done for server sockets,\n"
 	    "so they know where to look for incoming connections.  A socket\n"
@@ -846,22 +856,33 @@
 	    "may be up to three integers:\n"
 	    "port [flowinfo] [scope_id],\n"
 	    "where flowinfo and scope_id default to zero.\n\n"
+	    "Alternatively, the second argument can be a socket address object "
+	    "as returned by @code{make-socket-address}, in which case the "
+	    "no additional arguments should be passed.\n\n"
 	    "The return value is unspecified.")
 #define FUNC_NAME s_scm_bind
 {
   struct sockaddr *soka;
-  int size;
+  size_t size;
   int fd;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_OPFPORT (1, sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args, 3, FUNC_NAME,
-			    &size);
   fd = SCM_FPORT_FDES (sock);
+
+  if (address == SCM_UNDEFINED)
+    /* No third argument was passed to FAM_OR_SOCKADDR must actually be a
+       `socket address' object.  */
+    soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args, 3, FUNC_NAME, &size);
+
+
   if (bind (fd, soka, size) == -1)
   {
     int save_errno = errno;
-      
+
     free (soka);
     errno = save_errno;
     SCM_SYSERROR;
@@ -893,8 +914,8 @@
 #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,12 +974,198 @@
       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;
 }
 
+/* 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_ulong (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:
+      {
+	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
+	      {
+		struct sockaddr_un *c_unix;
+
+		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
+		  {
+		    c_address = scm_malloc (sizeof (struct sockaddr_un));
+		    c_unix = (struct sockaddr_un *)c_address;
+
+		    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;
+}
+
+SCM_DEFINE (scm_make_socket_address, "make-socket-address", 2, 0, 1,
+	    (SCM family, SCM address, SCM args),
+	    "Return a Scheme address object that reflects @var{address}, "
+	    "being an address of family @var{family}, with the "
+	    "family-specific parameters @var{args} (see the description of "
+	    "@code{connect} for details).")
+#define FUNC_NAME s_scm_make_socket_address
+{
+  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));
+}
+#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.  */
@@ -1009,7 +1216,7 @@
   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 +1238,7 @@
   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 +1260,7 @@
   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 +1414,7 @@
   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;
 
@@ -1216,13 +1423,14 @@
 }
 #undef FUNC_NAME
 
-SCM_DEFINE (scm_sendto, "sendto", 4, 0, 1,
-            (SCM sock, SCM message, SCM fam, SCM address, SCM args_and_flags),
+SCM_DEFINE (scm_sendto, "sendto", 3, 1, 1,
+            (SCM sock, SCM message, SCM fam_or_sockaddr, SCM address, SCM args_and_flags),
 	    "Transmit the string @var{message} on the socket port\n"
 	    "@var{sock}.  The\n"
 	    "destination address is specified using the @var{fam},\n"
 	    "@var{address} and\n"
-	    "@var{args_and_flags} arguments, in a similar way to the\n"
+	    "@var{args_and_flags} arguments, or just a socket address object "
+	    "returned by @code{make-socket-address}, in a similar way to the\n"
 	    "@code{connect} procedure.  @var{args_and_flags} contains\n"
 	    "the usual connection arguments optionally followed by\n"
 	    "a flags argument, which is a value or\n"
@@ -1241,14 +1449,26 @@
   int fd;
   int flg;
   struct sockaddr *soka;
-  int size;
+  size_t size;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_FPORT (1, sock);
   SCM_VALIDATE_STRING (2, message);
   fd = SCM_FPORT_FDES (sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args_and_flags, 4,
-			    FUNC_NAME, &size);
+
+  if (!scm_is_number (fam_or_sockaddr))
+    {
+      /* FAM_OR_SOCKADDR must actually be a `socket address' object.  This
+	 means that the following arguments, i.e. ADDRESS and those listed in
+	 ARGS_AND_FLAGS, are the `MSG_' flags.  */
+      soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+      if (address != SCM_UNDEFINED)
+	args_and_flags = scm_cons (address, args_and_flags);
+    }
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args_and_flags, 3, FUNC_NAME, &size);
+
   if (scm_is_null (args_and_flags))
     flg = 0;
   else


--- orig/libguile/socket.h
+++ mod/libguile/socket.h
@@ -54,6 +54,16 @@
 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


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-09-21  9:16         ` Ludovic Courtès
@ 2005-09-22  0:14           ` Kevin Ryde
  2005-09-22 13:46             ` Ludovic Courtès
  0 siblings, 1 reply; 29+ messages in thread
From: Kevin Ryde @ 2005-09-22  0:14 UTC (permalink / raw)
  Cc: guile-user

ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> Again, I only tested AF_INET addresses and I didn't try `sendto' and
> `bind'.

Untested code cannot be accepted.  AF_UNIX is easy, AF_INET6 might
depend on the system.  You'll need to make something for
test-suite/tests/socket.test exercising each case, eventually.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-09-22  0:14           ` Kevin Ryde
@ 2005-09-22 13:46             ` Ludovic Courtès
  2005-09-22 21:30               ` Kevin Ryde
  2005-09-28 21:30               ` Kevin Ryde
  0 siblings, 2 replies; 29+ messages in thread
From: Ludovic Courtès @ 2005-09-22 13:46 UTC (permalink / raw)
  Cc: guile-user

Hi Kevin,

Kevin Ryde <user42@zip.com.au> writes:

> Untested code cannot be accepted.  AF_UNIX is easy, AF_INET6 might
> depend on the system.  You'll need to make something for
> test-suite/tests/socket.test exercising each case, eventually.

I finally wrote test cases which actually helped me find bugs, of
course.  It actually tests a bit more than what I changed.  In
particular, I wrote a series of tests that uses Unix sockets (where
available) and will hopefully run correctly on most machines (in the
worst case, tests should be "unresolved").  Among other things, it tests
the two calling conventions of `connect' and `bind'.

Regarding `sendto', I tested it informally as follows:

  guile> (define host (gethostbyname "www.gnu.org"))
  guile> host
  #("gnu.org" ("www.gnu.org") 2 4 (3353880842))
  guile> (sendto (socket AF_INET SOCK_DGRAM 0) "msg" AF_INET 3353880842 80)
  3
  guile> (define sa (make-socket-address AF_INET 3353880842 80))
  guile> (sendto (socket AF_INET SOCK_DGRAM 0) "msg" sa)
  3
  guile> (sendto (socket AF_INET SOCK_DGRAM 0) "msg" AF_INET 3353880842 80 MSG_PEEK)
  3
  guile> (set! sa (make-socket-address AF_INET 3353880842 80))
  guile> (sendto (socket AF_INET SOCK_DGRAM 0) "msg" sa MSG_PEEK)
  3

The output of `strace' shows that the right arguments are being passed.

However, I didn't test IPv6 stuff due to my being completely
inexperienced with IPv6.  So I'd be nice if someone could help me with
this.

BTW, maybe `scm_fill_sockaddr ()' should also be changed to raise an
error when too many arguments for the given family are passed?

Thanks,
Ludovic.


Two more ChangeLog entries are necessary.

For `ice-9':

2005-09-22  Ludovic Courtès  <ludovic.courtes@laas.fr>

	* networking.scm (sockaddr:flowinfo):  New procedure.
	(sockaddr:scopeid):  New procedure.

For `test-suite':

2005-09-22  Ludovic Courtès  <ludovic.courtes@laas.fr>

	* tests/socket.test:  Added the tests prefixed by
	"make-socket-address" and "AF_UNIX".

\f
--- orig/ice-9/networking.scm
+++ mod/ice-9/networking.scm
@@ -80,3 +80,5 @@
 (define (sockaddr:path obj) (vector-ref obj 1))
 (define (sockaddr:addr obj) (vector-ref obj 1))
 (define (sockaddr:port obj) (vector-ref obj 2))
+(define (sockaddr:flowinfo obj) (vector-ref obj 3))
+(define (sockaddr:scopeid obj) (vector-ref obj 4))


--- orig/libguile/socket.c
+++ mod/libguile/socket.c
@@ -664,9 +664,9 @@
    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)
+		   const char *proc, size_t *size)
 #define FUNC_NAME proc
 {
   switch (fam)
@@ -768,9 +768,9 @@
     }
 }
 #undef FUNC_NAME
-  
-SCM_DEFINE (scm_connect, "connect", 3, 0, 1,
-            (SCM sock, SCM fam, SCM address, SCM args),
+
+SCM_DEFINE (scm_connect, "connect", 2, 1, 1,
+            (SCM sock, SCM fam_or_sockaddr, SCM address, SCM args),
 	    "Initiate a connection from a socket using a specified address\n"
 	    "family to the address\n"
 	    "specified by @var{address} and possibly @var{args}.\n"
@@ -787,22 +787,32 @@
 	    "@var{args} may be up to three integers:\n"
 	    "port [flowinfo] [scope_id],\n"
 	    "where flowinfo and scope_id default to zero.\n\n"
+	    "Alternatively, the second argument can be a socket address object "
+	    "as returned by @code{make-socket-address}, in which case the "
+	    "no additional arguments should be passed.\n\n"
 	    "The return value is unspecified.")
 #define FUNC_NAME s_scm_connect
 {
   int fd;
   struct sockaddr *soka;
-  int size;
+  size_t size;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_OPFPORT (1, sock);
   fd = SCM_FPORT_FDES (sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args, 3, FUNC_NAME,
-			    &size);
+
+  if (address == SCM_UNDEFINED)
+    /* No third argument was passed to FAM_OR_SOCKADDR must actually be a
+       `socket address' object.  */
+    soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args, 3, FUNC_NAME, &size);
+
   if (connect (fd, soka, size) == -1)
     {
       int save_errno = errno;
-      
+
       free (soka);
       errno = save_errno;
       SCM_SYSERROR;
@@ -812,8 +822,8 @@
 }
 #undef FUNC_NAME
 
-SCM_DEFINE (scm_bind, "bind", 3, 0, 1,
-            (SCM sock, SCM fam, SCM address, SCM args),
+SCM_DEFINE (scm_bind, "bind", 2, 1, 1,
+            (SCM sock, SCM fam_or_sockaddr, SCM address, SCM args),
 	    "Assign an address to the socket port @var{sock}.\n"
 	    "Generally this only needs to be done for server sockets,\n"
 	    "so they know where to look for incoming connections.  A socket\n"
@@ -846,22 +856,33 @@
 	    "may be up to three integers:\n"
 	    "port [flowinfo] [scope_id],\n"
 	    "where flowinfo and scope_id default to zero.\n\n"
+	    "Alternatively, the second argument can be a socket address object "
+	    "as returned by @code{make-socket-address}, in which case the "
+	    "no additional arguments should be passed.\n\n"
 	    "The return value is unspecified.")
 #define FUNC_NAME s_scm_bind
 {
   struct sockaddr *soka;
-  int size;
+  size_t size;
   int fd;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_OPFPORT (1, sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args, 3, FUNC_NAME,
-			    &size);
   fd = SCM_FPORT_FDES (sock);
+
+  if (address == SCM_UNDEFINED)
+    /* No third argument was passed to FAM_OR_SOCKADDR must actually be a
+       `socket address' object.  */
+    soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args, 3, FUNC_NAME, &size);
+
+
   if (bind (fd, soka, size) == -1)
   {
     int save_errno = errno;
-      
+
     free (soka);
     errno = save_errno;
     SCM_SYSERROR;
@@ -893,8 +914,8 @@
 #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,12 +974,201 @@
       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;
 }
 
+/* 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_ulong (SCM_SIMPLE_VECTOR_REF (address, 1)));
+	    c_inet->sin_port =
+	      htons (scm_to_ushort (SCM_SIMPLE_VECTOR_REF (address, 2)));
+
+	    c_inet->sin_family = AF_INET;
+	    *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
+
+	    c_inet6->sin6_family = AF_INET6;
+	    *address_size = sizeof (*c_inet6);
+	  }
+
+	break;
+      }
+#endif
+
+#ifdef HAVE_UNIX_DOMAIN_SOCKETS
+    case AF_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
+	      {
+		struct sockaddr_un *c_unix;
+
+		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
+		  {
+		    c_address = scm_malloc (sizeof (struct sockaddr_un));
+		    c_unix = (struct sockaddr_un *)c_address;
+
+		    if (path_len)
+		      {
+			scm_to_locale_stringbuf (path, c_unix->sun_path,
+						 UNIX_PATH_MAX);
+			c_unix->sun_path[path_len] = '\0';
+		      }
+		    else
+		      c_unix->sun_path[0] = '\0';
+
+		    c_unix->sun_family = AF_UNIX;
+		    *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;
+}
+
+SCM_DEFINE (scm_make_socket_address, "make-socket-address", 2, 0, 1,
+	    (SCM family, SCM address, SCM args),
+	    "Return a Scheme address object that reflects @var{address}, "
+	    "being an address of family @var{family}, with the "
+	    "family-specific parameters @var{args} (see the description of "
+	    "@code{connect} for details).")
+#define FUNC_NAME s_scm_make_socket_address
+{
+  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));
+}
+#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.  */
@@ -1009,7 +1219,7 @@
   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 +1241,7 @@
   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 +1263,7 @@
   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 +1417,7 @@
   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;
 
@@ -1216,13 +1426,14 @@
 }
 #undef FUNC_NAME
 
-SCM_DEFINE (scm_sendto, "sendto", 4, 0, 1,
-            (SCM sock, SCM message, SCM fam, SCM address, SCM args_and_flags),
+SCM_DEFINE (scm_sendto, "sendto", 3, 1, 1,
+            (SCM sock, SCM message, SCM fam_or_sockaddr, SCM address, SCM args_and_flags),
 	    "Transmit the string @var{message} on the socket port\n"
 	    "@var{sock}.  The\n"
 	    "destination address is specified using the @var{fam},\n"
 	    "@var{address} and\n"
-	    "@var{args_and_flags} arguments, in a similar way to the\n"
+	    "@var{args_and_flags} arguments, or just a socket address object "
+	    "returned by @code{make-socket-address}, in a similar way to the\n"
 	    "@code{connect} procedure.  @var{args_and_flags} contains\n"
 	    "the usual connection arguments optionally followed by\n"
 	    "a flags argument, which is a value or\n"
@@ -1241,14 +1452,26 @@
   int fd;
   int flg;
   struct sockaddr *soka;
-  int size;
+  size_t size;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_FPORT (1, sock);
   SCM_VALIDATE_STRING (2, message);
   fd = SCM_FPORT_FDES (sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args_and_flags, 4,
-			    FUNC_NAME, &size);
+
+  if (!scm_is_number (fam_or_sockaddr))
+    {
+      /* FAM_OR_SOCKADDR must actually be a `socket address' object.  This
+	 means that the following arguments, i.e. ADDRESS and those listed in
+	 ARGS_AND_FLAGS, are the `MSG_' flags.  */
+      soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+      if (address != SCM_UNDEFINED)
+	args_and_flags = scm_cons (address, args_and_flags);
+    }
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args_and_flags, 3, FUNC_NAME, &size);
+
   if (scm_is_null (args_and_flags))
     flg = 0;
   else


--- orig/libguile/socket.h
+++ mod/libguile/socket.h
@@ -54,6 +54,16 @@
 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 */
 
 /*

--- orig/test-suite/tests/socket.test
+++ mod/test-suite/tests/socket.test
@@ -6,12 +6,12 @@
 ;;;; 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 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
@@ -19,6 +19,7 @@
 (define-module (test-suite test-numbers)
   #:use-module (test-suite lib))
 
+\f
 ;;;
 ;;; inet-ntop
 ;;;
@@ -78,3 +79,123 @@
 	  (eqv? #xF0
 		(inet-pton AF_INET6
 			   "0000:0000:0000:0000:0000:0000:0000:00F0"))))))
+
+\f
+;;;
+;;; make-socket-address
+;;;
+
+(with-test-prefix "make-socket-address"
+  (if (defined? 'AF_INET)
+      (pass-if "AF_INET"
+	(let ((sa (make-socket-address AF_INET 123456 80)))
+	  (and (= (sockaddr:fam  sa) AF_INET)
+	       (= (sockaddr:addr sa) 123456)
+	       (= (sockaddr:port sa) 80)))))
+
+  (if (defined? 'AF_INET6)
+      (pass-if "AF_INET6"
+	;; Since the platform doesn't necessarily support `scopeid', we won't
+        ;; test it.
+	(let ((sa* (make-socket-address AF_INET6 123456 80 1))
+	      (sa+ (make-socket-address AF_INET6 123456 80)))
+	  (and (= (sockaddr:fam  sa*) (sockaddr:fam  sa+) AF_INET6)
+	       (= (sockaddr:addr sa*) (sockaddr:addr sa+) 123456)
+	       (= (sockaddr:port sa*) (sockaddr:port sa+) 80)
+	       (= (sockaddr:flowinfo sa*) 1)))))
+
+  (if (defined? 'AF_UNIX)
+      (pass-if "AF_UNIX"
+	(let ((sa (make-socket-address AF_UNIX "/tmp/unix-socket")))
+	  (and (= (sockaddr:fam sa) AF_UNIX)
+	       (string=? (sockaddr:path sa) "/tmp/unix-socket"))))))
+
+
+\f
+;;;
+;;; AF_UNIX sockets and `make-socket-address'
+;;;
+
+(if (defined? 'AF_UNIX)
+    (with-test-prefix "AF_UNIX"
+      (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
+	    (server-bound? #f)
+	    (server-listening? #f)
+	    (server-pid #f)
+	    (path (tmpnam)))
+
+      (pass-if "bind"
+	(catch 'system-error
+	  (lambda ()
+	    (bind server-socket AF_UNIX path)
+	    (set! server-bound? #t)
+	    #t)
+	  (lambda args
+	    (let ((errno (system-error-errno args)))
+	      (cond ((= errno EADDRINUSE) (throw 'unresolved))
+		    (else (apply throw args)))))))
+
+      (pass-if "bind/sockaddr"
+	(let* ((sock (socket AF_UNIX SOCK_STREAM 0))
+	       (path (tmpnam))
+	       (sockaddr (make-socket-address AF_UNIX path)))
+	  (catch 'system-error
+	    (lambda ()
+	      (bind sock sockaddr)
+	      (false-if-exception (delete-file path))
+	      #t)
+	    (lambda args
+	      (let ((errno (system-error-errno args)))
+		(cond ((= errno EADDRINUSE) (throw 'unresolved))
+		      (else (apply throw args))))))))
+
+      (pass-if "listen"
+	(if (not server-bound?)
+	    (throw 'unresolved)
+	    (begin
+	      (listen server-socket 123)
+	      (set! server-listening? #t)
+	      #t)))
+
+      (if server-listening?
+	  (let ((pid (primitive-fork)))
+	    ;; Spawn a server process.
+	    (case pid
+	      ((-1) (throw 'unresolved))
+	      ((0)   ;; the kid:  serve two connections and exit
+	       (let serve ((conn (false-if-exception (accept server-socket)))
+			   (count 1))
+		 (if (not conn)
+		     (exit 1)
+		     (if (> count 0)
+			 (serve (false-if-exception (accept server-socket))
+				(- count 1)))))
+	       (exit 0))
+	      (else  ;; the parent
+	       (set! server-pid pid)
+	       #t))))
+
+      (pass-if "connect"
+	(if (not server-pid)
+	    (throw 'unresolved)
+	    (let ((s (socket AF_UNIX SOCK_STREAM 0)))
+	      (connect s AF_UNIX path)
+	      #t)))
+
+      (pass-if "connect/sockaddr"
+	(if (not server-pid)
+	    (throw 'unresolved)
+	    (let ((s (socket AF_UNIX SOCK_STREAM 0)))
+	      (connect s (make-socket-address AF_UNIX path))
+	      #t)))
+
+      (pass-if "accept"
+	(if (not server-pid)
+	    (throw 'unresolved)
+	    (let ((status (cdr (waitpid server-pid))))
+	      (eq? 0 (status:exit-val status)))))
+
+      (false-if-exception (delete-file path))
+
+      #t)))
+



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-09-22 13:46             ` Ludovic Courtès
@ 2005-09-22 21:30               ` Kevin Ryde
  2005-09-26  9:37                 ` Ludovic Courtès
  2005-09-28 21:30               ` Kevin Ryde
  1 sibling, 1 reply; 29+ messages in thread
From: Kevin Ryde @ 2005-09-22 21:30 UTC (permalink / raw)
  Cc: guile-user

ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> Regarding `sendto', I tested it informally as follows:

An AF_UNIX socket can probably exercise that.

> I didn't test IPv6 stuff

Something using localhost would be good.  I thought at one stage to
add "IN6ADDR_LOOPBACK" or something as a constant to match
INADDR_LOOPBACK, but never got around to it.

> +    (with-test-prefix "AF_UNIX"
> ...
> +	    (path (tmpnam)))

The build directory would be an option here, so there's no chance of
leaving garbage outside the tree.  CLEANFILES in Makefile.am could
ensure it's removed, which may be easier than catches in the test
code.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-09-22 21:30               ` Kevin Ryde
@ 2005-09-26  9:37                 ` Ludovic Courtès
  0 siblings, 0 replies; 29+ messages in thread
From: Ludovic Courtès @ 2005-09-26  9:37 UTC (permalink / raw)


Hi,

Kevin Ryde <user42@zip.com.au> writes:

> ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>>
>> Regarding `sendto', I tested it informally as follows:
>
> An AF_UNIX socket can probably exercise that.

The attached patch does this (note that this patch only updated the test
itself; for the code, you still need to apply the previous one, minus
the `socket.test' part).

Note that this makes the test quite large.  What I fear is that this
may behave completely differently on other Unices, making the test
useless.  So I'm not in favor of writing lots of test cases for
networking -- although that's just what I've been doing.  ;-)

> Something using localhost would be good.  I thought at one stage to
> add "IN6ADDR_LOOPBACK" or something as a constant to match
> INADDR_LOOPBACK, but never got around to it.

When you do it, could you add a test yourself?

> The build directory would be an option here, so there's no chance of
> leaving garbage outside the tree.  CLEANFILES in Makefile.am could
> ensure it's removed, which may be easier than catches in the test
> code.

Yes.  But we want the test to do its best to avoid EADDRINUSE errors.
In that respect, I believe `tmpnam' is the best solution.

BTW, for the sake of consistency, should we use `make-sockaddr' instead
of `make-socket-address'?  Or both?  IOW, do you value readability more
than consistency?  ;-)

Thanks,
Ludovic.

\f
--- orig/test-suite/tests/socket.test
+++ mod/test-suite/tests/socket.test
@@ -6,12 +6,12 @@
 ;;;; 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 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
@@ -19,6 +19,7 @@
 (define-module (test-suite test-numbers)
   #:use-module (test-suite lib))
 
+\f
 ;;;
 ;;; inet-ntop
 ;;;
@@ -78,3 +79,177 @@
 	  (eqv? #xF0
 		(inet-pton AF_INET6
 			   "0000:0000:0000:0000:0000:0000:0000:00F0"))))))
+
+\f
+;;;
+;;; make-socket-address
+;;;
+
+(with-test-prefix "make-socket-address"
+  (if (defined? 'AF_INET)
+      (pass-if "AF_INET"
+	(let ((sa (make-socket-address AF_INET 123456 80)))
+	  (and (= (sockaddr:fam  sa) AF_INET)
+	       (= (sockaddr:addr sa) 123456)
+	       (= (sockaddr:port sa) 80)))))
+
+  (if (defined? 'AF_INET6)
+      (pass-if "AF_INET6"
+	;; Since the platform doesn't necessarily support `scopeid', we won't
+        ;; test it.
+	(let ((sa* (make-socket-address AF_INET6 123456 80 1))
+	      (sa+ (make-socket-address AF_INET6 123456 80)))
+	  (and (= (sockaddr:fam  sa*) (sockaddr:fam  sa+) AF_INET6)
+	       (= (sockaddr:addr sa*) (sockaddr:addr sa+) 123456)
+	       (= (sockaddr:port sa*) (sockaddr:port sa+) 80)
+	       (= (sockaddr:flowinfo sa*) 1)))))
+
+  (if (defined? 'AF_UNIX)
+      (pass-if "AF_UNIX"
+	(let ((sa (make-socket-address AF_UNIX "/tmp/unix-socket")))
+	  (and (= (sockaddr:fam sa) AF_UNIX)
+	       (string=? (sockaddr:path sa) "/tmp/unix-socket"))))))
+
+
+\f
+;;;
+;;; AF_UNIX sockets and `make-socket-address'
+;;;
+
+(if (defined? 'AF_UNIX)
+    (with-test-prefix "AF_UNIX/SOCK_DGRAM"
+
+      ;; testing `bind' and `sendto' and datagram sockets
+
+      (let ((server-socket (socket AF_UNIX SOCK_DGRAM 0))
+	    (server-bound? #f)
+	    (path (tmpnam)))
+
+	(pass-if "bind"
+	  (catch 'system-error
+	    (lambda ()
+	      (bind server-socket AF_UNIX path)
+	      (set! server-bound? #t)
+	      #t)
+	    (lambda args
+	      (let ((errno (system-error-errno args)))
+		(cond ((= errno EADDRINUSE) (throw 'unresolved))
+		      (else (apply throw args)))))))
+
+	(pass-if "bind/sockaddr"
+	  (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
+		 (path (tmpnam))
+		 (sockaddr (make-socket-address AF_UNIX path)))
+	    (catch 'system-error
+	      (lambda ()
+		(bind sock sockaddr)
+		(false-if-exception (delete-file path))
+		#t)
+	      (lambda args
+		(let ((errno (system-error-errno args)))
+		  (cond ((= errno EADDRINUSE) (throw 'unresolved))
+			(else (apply throw args))))))))
+
+	(pass-if "sendto"
+	  (if (not server-bound?)
+	      (throw 'unresolved)
+	      (let ((client (socket AF_UNIX SOCK_DGRAM 0)))
+		(> (sendto client "hello" AF_UNIX path) 0))))
+
+	(pass-if "sendto/sockaddr"
+	  (if (not server-bound?)
+	      (throw 'unresolved)
+	      (let ((client (socket AF_UNIX SOCK_DGRAM 0))
+		    (sockaddr (make-socket-address AF_UNIX path)))
+		(> (sendto client "hello" sockaddr) 0))))
+
+	(false-if-exception (delete-file path)))))
+
+
+(if (defined? 'AF_UNIX)
+    (with-test-prefix "AF_UNIX/SOCK_STREAM"
+
+      ;; testing `bind', `listen' and `connect' on stream-oriented sockets
+
+      (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
+	    (server-bound? #f)
+	    (server-listening? #f)
+	    (server-pid #f)
+	    (path (tmpnam)))
+
+	(pass-if "bind"
+	  (catch 'system-error
+	    (lambda ()
+	      (bind server-socket AF_UNIX path)
+	      (set! server-bound? #t)
+	      #t)
+	    (lambda args
+	      (let ((errno (system-error-errno args)))
+		(cond ((= errno EADDRINUSE) (throw 'unresolved))
+		      (else (apply throw args)))))))
+
+	(pass-if "bind/sockaddr"
+	  (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
+		 (path (tmpnam))
+		 (sockaddr (make-socket-address AF_UNIX path)))
+	    (catch 'system-error
+	      (lambda ()
+		(bind sock sockaddr)
+		(false-if-exception (delete-file path))
+		#t)
+	      (lambda args
+		(let ((errno (system-error-errno args)))
+		  (cond ((= errno EADDRINUSE) (throw 'unresolved))
+			(else (apply throw args))))))))
+
+	(pass-if "listen"
+	  (if (not server-bound?)
+	      (throw 'unresolved)
+	      (begin
+		(listen server-socket 123)
+		(set! server-listening? #t)
+		#t)))
+
+	(if server-listening?
+	    (let ((pid (primitive-fork)))
+	      ;; Spawn a server process.
+	      (case pid
+		((-1) (throw 'unresolved))
+		((0)   ;; the kid:  serve two connections and exit
+		 (let serve ((conn
+			      (false-if-exception (accept server-socket)))
+			     (count 1))
+		   (if (not conn)
+		       (exit 1)
+		       (if (> count 0)
+			   (serve (false-if-exception (accept server-socket))
+				  (- count 1)))))
+		 (exit 0))
+		(else  ;; the parent
+		 (set! server-pid pid)
+		 #t))))
+
+	(pass-if "connect"
+	  (if (not server-pid)
+	      (throw 'unresolved)
+	      (let ((s (socket AF_UNIX SOCK_STREAM 0)))
+		(connect s AF_UNIX path)
+		#t)))
+
+	(pass-if "connect/sockaddr"
+	  (if (not server-pid)
+	      (throw 'unresolved)
+	      (let ((s (socket AF_UNIX SOCK_STREAM 0)))
+		(connect s (make-socket-address AF_UNIX path))
+		#t)))
+
+	(pass-if "accept"
+	  (if (not server-pid)
+	      (throw 'unresolved)
+	      (let ((status (cdr (waitpid server-pid))))
+		(eq? 0 (status:exit-val status)))))
+
+	(false-if-exception (delete-file path))
+
+	#t)))
+




_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Exposing common type wrapping/unwrapping methods
  2005-09-22 13:46             ` Ludovic Courtès
  2005-09-22 21:30               ` Kevin Ryde
@ 2005-09-28 21:30               ` Kevin Ryde
  2005-10-04 14:08                 ` Socket API improvement, patch #6 Ludovic Courtès
  1 sibling, 1 reply; 29+ messages in thread
From: Kevin Ryde @ 2005-09-28 21:30 UTC (permalink / raw)
  Cc: guile-user

ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> [AF_INET...]
> +	    c_address = scm_malloc (sizeof (struct sockaddr_in));
> +	    c_inet = (struct sockaddr_in *)c_address;
> +
> +	    c_inet->sin_addr.s_addr =
> +	      htonl (scm_to_ulong (SCM_SIMPLE_VECTOR_REF (address, 1)));

Looks like a memory leak here if scm_to_ulong throws an error.
Obviously it won't normally, but a vector with any garbage could reach
here.  Maybe build the addr on the stack then memdup.  Ditto the other
cases.

> [AF_UNIX...]
> +
> +		if (path == SCM_BOOL_F)
> +		  path_len = 0;

What is #f here meant to support?

> +#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)

How about sizeof(c_unix->sun_path)?

> +			scm_to_locale_stringbuf (path, c_unix->sun_path,
> +						 UNIX_PATH_MAX);
> +			c_unix->sun_path[path_len] = '\0';
> +		      }
> +		    else
> +		      c_unix->sun_path[0] = '\0';
> +
> +		    c_unix->sun_family = AF_UNIX;
> +		    *address_size = SUN_LEN (c_unix);

I think scm_to_locale_stringbuf will store nulls from the string but
then SUN_LEN will truncate at the first one of those.  Maybe nulls in
the SCM should be an error (per scm_to_locale_stringn).


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Socket API improvement, patch #6
  2005-09-28 21:30               ` Kevin Ryde
@ 2005-10-04 14:08                 ` Ludovic Courtès
  2005-10-17 10:55                   ` Ludovic Courtès
  0 siblings, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-10-04 14:08 UTC (permalink / raw)
  Cc: guile-user

Hi Kevin,

Kevin Ryde <user42@zip.com.au> writes:

> Looks like a memory leak here if scm_to_ulong throws an error.
> Obviously it won't normally, but a vector with any garbage could reach
> here.  Maybe build the addr on the stack then memdup.  Ditto the other
> cases.

Right, I fixed this one.

> What is #f here meant to support?

Mostly, it aims at being consistent with `_scm_from_sockaddr ()' which
may set the `path' element to `#f'.

> How about sizeof(c_unix->sun_path)?

Right, fixed.

> I think scm_to_locale_stringbuf will store nulls from the string but
> then SUN_LEN will truncate at the first one of those.  Maybe nulls in
> the SCM should be an error (per scm_to_locale_stringn).

I added a sanity check for this, too (although I'm unsure if it's really
useful).

I attach a full patch which includes the test-case too, so that we don't
have too much of a hard time keeping track of the thing.  ;-)

BTW, I should receive the papers from the FSF shortly.

Thanks,
Ludovic.

\f
--- orig/ice-9/networking.scm
+++ mod/ice-9/networking.scm
@@ -80,3 +80,5 @@
 (define (sockaddr:path obj) (vector-ref obj 1))
 (define (sockaddr:addr obj) (vector-ref obj 1))
 (define (sockaddr:port obj) (vector-ref obj 2))
+(define (sockaddr:flowinfo obj) (vector-ref obj 3))
+(define (sockaddr:scopeid obj) (vector-ref obj 4))


--- orig/libguile/socket.c
+++ mod/libguile/socket.c
@@ -664,9 +664,9 @@
    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)
+		   const char *proc, size_t *size)
 #define FUNC_NAME proc
 {
   switch (fam)
@@ -682,8 +682,7 @@
 	port = scm_to_int (SCM_CAR (*args));
 	*args = SCM_CDR (*args);
 	soka = (struct sockaddr_in *) scm_malloc (sizeof (struct sockaddr_in));
-	if (!soka)
-	  scm_memory_error (proc);
+
 #if HAVE_STRUCT_SOCKADDR_SIN_LEN
 	soka->sin_len = sizeof (struct sockaddr_in);
 #endif
@@ -717,8 +716,7 @@
 	      }
 	  }
 	soka = (struct sockaddr_in6 *) scm_malloc (sizeof (struct sockaddr_in6));
-	if (!soka)
-	  scm_memory_error (proc);
+
 #if HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
 	soka->sin6_len = sizeof (struct sockaddr_in6);
 #endif
@@ -768,9 +766,9 @@
     }
 }
 #undef FUNC_NAME
-  
-SCM_DEFINE (scm_connect, "connect", 3, 0, 1,
-            (SCM sock, SCM fam, SCM address, SCM args),
+
+SCM_DEFINE (scm_connect, "connect", 2, 1, 1,
+            (SCM sock, SCM fam_or_sockaddr, SCM address, SCM args),
 	    "Initiate a connection from a socket using a specified address\n"
 	    "family to the address\n"
 	    "specified by @var{address} and possibly @var{args}.\n"
@@ -787,22 +785,32 @@
 	    "@var{args} may be up to three integers:\n"
 	    "port [flowinfo] [scope_id],\n"
 	    "where flowinfo and scope_id default to zero.\n\n"
+	    "Alternatively, the second argument can be a socket address object "
+	    "as returned by @code{make-socket-address}, in which case the "
+	    "no additional arguments should be passed.\n\n"
 	    "The return value is unspecified.")
 #define FUNC_NAME s_scm_connect
 {
   int fd;
   struct sockaddr *soka;
-  int size;
+  size_t size;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_OPFPORT (1, sock);
   fd = SCM_FPORT_FDES (sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args, 3, FUNC_NAME,
-			    &size);
+
+  if (address == SCM_UNDEFINED)
+    /* No third argument was passed to FAM_OR_SOCKADDR must actually be a
+       `socket address' object.  */
+    soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args, 3, FUNC_NAME, &size);
+
   if (connect (fd, soka, size) == -1)
     {
       int save_errno = errno;
-      
+
       free (soka);
       errno = save_errno;
       SCM_SYSERROR;
@@ -812,8 +820,8 @@
 }
 #undef FUNC_NAME
 
-SCM_DEFINE (scm_bind, "bind", 3, 0, 1,
-            (SCM sock, SCM fam, SCM address, SCM args),
+SCM_DEFINE (scm_bind, "bind", 2, 1, 1,
+            (SCM sock, SCM fam_or_sockaddr, SCM address, SCM args),
 	    "Assign an address to the socket port @var{sock}.\n"
 	    "Generally this only needs to be done for server sockets,\n"
 	    "so they know where to look for incoming connections.  A socket\n"
@@ -846,22 +854,33 @@
 	    "may be up to three integers:\n"
 	    "port [flowinfo] [scope_id],\n"
 	    "where flowinfo and scope_id default to zero.\n\n"
+	    "Alternatively, the second argument can be a socket address object "
+	    "as returned by @code{make-socket-address}, in which case the "
+	    "no additional arguments should be passed.\n\n"
 	    "The return value is unspecified.")
 #define FUNC_NAME s_scm_bind
 {
   struct sockaddr *soka;
-  int size;
+  size_t size;
   int fd;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_OPFPORT (1, sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args, 3, FUNC_NAME,
-			    &size);
   fd = SCM_FPORT_FDES (sock);
+
+  if (address == SCM_UNDEFINED)
+    /* No third argument was passed to FAM_OR_SOCKADDR must actually be a
+       `socket address' object.  */
+    soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args, 3, FUNC_NAME, &size);
+
+
   if (bind (fd, soka, size) == -1)
   {
     int save_errno = errno;
-      
+
     free (soka);
     errno = save_errno;
     SCM_SYSERROR;
@@ -893,8 +912,8 @@
 #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,12 +972,212 @@
       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;
 }
 
+/* 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:
+      {
+	if (SCM_SIMPLE_VECTOR_LENGTH (address) != 3)
+	  scm_misc_error (FUNC_NAME,
+			  "invalid inet address representation: ~A",
+			  scm_list_1 (address));
+	else
+	  {
+	    struct sockaddr_in c_inet;
+
+	    c_inet.sin_addr.s_addr =
+	      htonl (scm_to_ulong (SCM_SIMPLE_VECTOR_REF (address, 1)));
+	    c_inet.sin_port =
+	      htons (scm_to_ushort (SCM_SIMPLE_VECTOR_REF (address, 2)));
+	    c_inet.sin_family = AF_INET;
+
+	    *address_size = sizeof (c_inet);
+	    c_address = scm_malloc (sizeof (c_inet));
+	    memcpy (c_address, &c_inet, sizeof (c_inet));
+	  }
+
+	break;
+      }
+
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      {
+	if (SCM_SIMPLE_VECTOR_LENGTH (address) != 5)
+	  scm_misc_error (FUNC_NAME, "invalid inet6 address representation: ~A",
+			  scm_list_1 (address));
+	else
+	  {
+	    struct sockaddr_in6 c_inet6;
+
+	    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
+
+	    c_inet6.sin6_family = AF_INET6;
+
+	    *address_size = sizeof (c_inet6);
+	    c_address = scm_malloc (sizeof (c_inet6));
+	    memcpy (c_address, &c_inet6, sizeof (c_inet6));
+	  }
+
+	break;
+      }
+#endif
+
+#ifdef HAVE_UNIX_DOMAIN_SOCKETS
+    case AF_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
+	      {
+		struct sockaddr_un c_unix;
+
+		if (path == SCM_BOOL_F)
+		  path_len = 0;
+		else
+		  path_len = scm_c_string_length (path);
+
+#ifdef UNIX_PATH_MAX
+		if (path_len >= UNIX_PATH_MAX)
+#else
+/* We can hope that this limit will eventually vanish, at least on GNU.
+   However, currently, while glibc doesn't define `UNIX_PATH_MAX', it
+   documents it has being limited to 108 bytes.  */
+		if (path_len >= sizeof (c_unix.sun_path))
+#endif
+		  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,
+#ifdef UNIX_PATH_MAX
+						 UNIX_PATH_MAX);
+#else
+			                         sizeof (c_unix.sun_path));
+#endif
+			c_unix.sun_path[path_len] = '\0';
+
+			/* Sanity check.  */
+			if (strlen (c_unix.sun_path) != path_len)
+			  scm_misc_error (FUNC_NAME, "unix address path "
+					  "contains nul characters: ~A",
+					  scm_list_1 (path));
+		      }
+		    else
+		      c_unix.sun_path[0] = '\0';
+
+		    c_unix.sun_family = AF_UNIX;
+
+		    *address_size = SUN_LEN (&c_unix);
+		    c_address = scm_malloc (sizeof (c_unix));
+		    memcpy (c_address, &c_unix, sizeof (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;
+}
+
+SCM_DEFINE (scm_make_socket_address, "make-socket-address", 2, 0, 1,
+	    (SCM family, SCM address, SCM args),
+	    "Return a Scheme address object that reflects @var{address}, "
+	    "being an address of family @var{family}, with the "
+	    "family-specific parameters @var{args} (see the description of "
+	    "@code{connect} for details).")
+#define FUNC_NAME s_scm_make_socket_address
+{
+  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));
+}
+#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.  */
@@ -1009,7 +1228,7 @@
   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 +1250,7 @@
   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 +1272,7 @@
   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 +1426,7 @@
   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;
 
@@ -1216,13 +1435,14 @@
 }
 #undef FUNC_NAME
 
-SCM_DEFINE (scm_sendto, "sendto", 4, 0, 1,
-            (SCM sock, SCM message, SCM fam, SCM address, SCM args_and_flags),
+SCM_DEFINE (scm_sendto, "sendto", 3, 1, 1,
+            (SCM sock, SCM message, SCM fam_or_sockaddr, SCM address, SCM args_and_flags),
 	    "Transmit the string @var{message} on the socket port\n"
 	    "@var{sock}.  The\n"
 	    "destination address is specified using the @var{fam},\n"
 	    "@var{address} and\n"
-	    "@var{args_and_flags} arguments, in a similar way to the\n"
+	    "@var{args_and_flags} arguments, or just a socket address object "
+	    "returned by @code{make-socket-address}, in a similar way to the\n"
 	    "@code{connect} procedure.  @var{args_and_flags} contains\n"
 	    "the usual connection arguments optionally followed by\n"
 	    "a flags argument, which is a value or\n"
@@ -1241,14 +1461,26 @@
   int fd;
   int flg;
   struct sockaddr *soka;
-  int size;
+  size_t size;
 
   sock = SCM_COERCE_OUTPORT (sock);
   SCM_VALIDATE_FPORT (1, sock);
   SCM_VALIDATE_STRING (2, message);
   fd = SCM_FPORT_FDES (sock);
-  soka = scm_fill_sockaddr (scm_to_int (fam), address, &args_and_flags, 4,
-			    FUNC_NAME, &size);
+
+  if (!scm_is_number (fam_or_sockaddr))
+    {
+      /* FAM_OR_SOCKADDR must actually be a `socket address' object.  This
+	 means that the following arguments, i.e. ADDRESS and those listed in
+	 ARGS_AND_FLAGS, are the `MSG_' flags.  */
+      soka = scm_to_sockaddr (fam_or_sockaddr, &size);
+      if (address != SCM_UNDEFINED)
+	args_and_flags = scm_cons (address, args_and_flags);
+    }
+  else
+    soka = scm_fill_sockaddr (scm_to_int (fam_or_sockaddr), address,
+			      &args_and_flags, 3, FUNC_NAME, &size);
+
   if (scm_is_null (args_and_flags))
     flg = 0;
   else


--- orig/libguile/socket.h
+++ mod/libguile/socket.h
@@ -54,6 +54,16 @@
 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 */
 
 /*

--- orig/test-suite/tests/socket.test
+++ mod/test-suite/tests/socket.test
@@ -6,12 +6,12 @@
 ;;;; 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 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
@@ -19,6 +19,7 @@
 (define-module (test-suite test-numbers)
   #:use-module (test-suite lib))
 
+\f
 ;;;
 ;;; inet-ntop
 ;;;
@@ -78,3 +79,177 @@
 	  (eqv? #xF0
 		(inet-pton AF_INET6
 			   "0000:0000:0000:0000:0000:0000:0000:00F0"))))))
+
+\f
+;;;
+;;; make-socket-address
+;;;
+
+(with-test-prefix "make-socket-address"
+  (if (defined? 'AF_INET)
+      (pass-if "AF_INET"
+	(let ((sa (make-socket-address AF_INET 123456 80)))
+	  (and (= (sockaddr:fam  sa) AF_INET)
+	       (= (sockaddr:addr sa) 123456)
+	       (= (sockaddr:port sa) 80)))))
+
+  (if (defined? 'AF_INET6)
+      (pass-if "AF_INET6"
+	;; Since the platform doesn't necessarily support `scopeid', we won't
+        ;; test it.
+	(let ((sa* (make-socket-address AF_INET6 123456 80 1))
+	      (sa+ (make-socket-address AF_INET6 123456 80)))
+	  (and (= (sockaddr:fam  sa*) (sockaddr:fam  sa+) AF_INET6)
+	       (= (sockaddr:addr sa*) (sockaddr:addr sa+) 123456)
+	       (= (sockaddr:port sa*) (sockaddr:port sa+) 80)
+	       (= (sockaddr:flowinfo sa*) 1)))))
+
+  (if (defined? 'AF_UNIX)
+      (pass-if "AF_UNIX"
+	(let ((sa (make-socket-address AF_UNIX "/tmp/unix-socket")))
+	  (and (= (sockaddr:fam sa) AF_UNIX)
+	       (string=? (sockaddr:path sa) "/tmp/unix-socket"))))))
+
+
+\f
+;;;
+;;; AF_UNIX sockets and `make-socket-address'
+;;;
+
+(if (defined? 'AF_UNIX)
+    (with-test-prefix "AF_UNIX/SOCK_DGRAM"
+
+      ;; testing `bind' and `sendto' and datagram sockets
+
+      (let ((server-socket (socket AF_UNIX SOCK_DGRAM 0))
+	    (server-bound? #f)
+	    (path (tmpnam)))
+
+	(pass-if "bind"
+	  (catch 'system-error
+	    (lambda ()
+	      (bind server-socket AF_UNIX path)
+	      (set! server-bound? #t)
+	      #t)
+	    (lambda args
+	      (let ((errno (system-error-errno args)))
+		(cond ((= errno EADDRINUSE) (throw 'unresolved))
+		      (else (apply throw args)))))))
+
+	(pass-if "bind/sockaddr"
+	  (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
+		 (path (tmpnam))
+		 (sockaddr (make-socket-address AF_UNIX path)))
+	    (catch 'system-error
+	      (lambda ()
+		(bind sock sockaddr)
+		(false-if-exception (delete-file path))
+		#t)
+	      (lambda args
+		(let ((errno (system-error-errno args)))
+		  (cond ((= errno EADDRINUSE) (throw 'unresolved))
+			(else (apply throw args))))))))
+
+	(pass-if "sendto"
+	  (if (not server-bound?)
+	      (throw 'unresolved)
+	      (let ((client (socket AF_UNIX SOCK_DGRAM 0)))
+		(> (sendto client "hello" AF_UNIX path) 0))))
+
+	(pass-if "sendto/sockaddr"
+	  (if (not server-bound?)
+	      (throw 'unresolved)
+	      (let ((client (socket AF_UNIX SOCK_DGRAM 0))
+		    (sockaddr (make-socket-address AF_UNIX path)))
+		(> (sendto client "hello" sockaddr) 0))))
+
+	(false-if-exception (delete-file path)))))
+
+
+(if (defined? 'AF_UNIX)
+    (with-test-prefix "AF_UNIX/SOCK_STREAM"
+
+      ;; testing `bind', `listen' and `connect' on stream-oriented sockets
+
+      (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
+	    (server-bound? #f)
+	    (server-listening? #f)
+	    (server-pid #f)
+	    (path (tmpnam)))
+
+	(pass-if "bind"
+	  (catch 'system-error
+	    (lambda ()
+	      (bind server-socket AF_UNIX path)
+	      (set! server-bound? #t)
+	      #t)
+	    (lambda args
+	      (let ((errno (system-error-errno args)))
+		(cond ((= errno EADDRINUSE) (throw 'unresolved))
+		      (else (apply throw args)))))))
+
+	(pass-if "bind/sockaddr"
+	  (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
+		 (path (tmpnam))
+		 (sockaddr (make-socket-address AF_UNIX path)))
+	    (catch 'system-error
+	      (lambda ()
+		(bind sock sockaddr)
+		(false-if-exception (delete-file path))
+		#t)
+	      (lambda args
+		(let ((errno (system-error-errno args)))
+		  (cond ((= errno EADDRINUSE) (throw 'unresolved))
+			(else (apply throw args))))))))
+
+	(pass-if "listen"
+	  (if (not server-bound?)
+	      (throw 'unresolved)
+	      (begin
+		(listen server-socket 123)
+		(set! server-listening? #t)
+		#t)))
+
+	(if server-listening?
+	    (let ((pid (primitive-fork)))
+	      ;; Spawn a server process.
+	      (case pid
+		((-1) (throw 'unresolved))
+		((0)   ;; the kid:  serve two connections and exit
+		 (let serve ((conn
+			      (false-if-exception (accept server-socket)))
+			     (count 1))
+		   (if (not conn)
+		       (exit 1)
+		       (if (> count 0)
+			   (serve (false-if-exception (accept server-socket))
+				  (- count 1)))))
+		 (exit 0))
+		(else  ;; the parent
+		 (set! server-pid pid)
+		 #t))))
+
+	(pass-if "connect"
+	  (if (not server-pid)
+	      (throw 'unresolved)
+	      (let ((s (socket AF_UNIX SOCK_STREAM 0)))
+		(connect s AF_UNIX path)
+		#t)))
+
+	(pass-if "connect/sockaddr"
+	  (if (not server-pid)
+	      (throw 'unresolved)
+	      (let ((s (socket AF_UNIX SOCK_STREAM 0)))
+		(connect s (make-socket-address AF_UNIX path))
+		#t)))
+
+	(pass-if "accept"
+	  (if (not server-pid)
+	      (throw 'unresolved)
+	      (let ((status (cdr (waitpid server-pid))))
+		(eq? 0 (status:exit-val status)))))
+
+	(false-if-exception (delete-file path))
+
+	#t)))
+



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-04 14:08                 ` Socket API improvement, patch #6 Ludovic Courtès
@ 2005-10-17 10:55                   ` Ludovic Courtès
  2005-10-17 21:43                     ` Kevin Ryde
  0 siblings, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-10-17 10:55 UTC (permalink / raw)
  Cc: guile-user

Hi,

Just a reminder about this socket patch, <87wtkt9xyq.fsf_-_@laas.fr>.  I
got my copyright assignment form signed and approved so if this change
looks reasonable to you, it can probably go in.  Kevin?

Thanks,
Ludovic.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-17 10:55                   ` Ludovic Courtès
@ 2005-10-17 21:43                     ` Kevin Ryde
  2005-10-18  7:45                       ` Ludovic Courtès
  0 siblings, 1 reply; 29+ messages in thread
From: Kevin Ryde @ 2005-10-17 21:43 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> I got my copyright assignment form signed and approved so if this
> change looks reasonable to you, it can probably go in.  Kevin?

Then you're just waiting for the nod from Marius. :)


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-17 21:43                     ` Kevin Ryde
@ 2005-10-18  7:45                       ` Ludovic Courtès
  2005-10-18 20:17                         ` Marius Vollmer
  0 siblings, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-10-18  7:45 UTC (permalink / raw)
  Cc: guile-user

Kevin Ryde <user42@zip.com.au> writes:

> Then you're just waiting for the nod from Marius. :)

Oh, but it looks like he's been away for a couple of months or so.
Anyway, we'll see.

Thanks,
Ludovic.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-18  7:45                       ` Ludovic Courtès
@ 2005-10-18 20:17                         ` Marius Vollmer
  2005-10-24 11:35                           ` Ludovic Courtès
  0 siblings, 1 reply; 29+ messages in thread
From: Marius Vollmer @ 2005-10-18 20:17 UTC (permalink / raw)
  Cc: guile-user

ludovic.courtes@laas.fr (Ludovic Courtès) writes:

> Kevin Ryde <user42@zip.com.au> writes:
>
>> Then you're just waiting for the nod from Marius. :)
>
> Oh, but it looks like he's been away for a couple of months or so.
> Anyway, we'll see.

I'm back! :-)

Yeah, I had accidentally disconnected myself from the guile-devel
mailing list and way too busy with other things to really
notice... sorry for that.  I will take a look at the patch
immediately...

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-18 20:17                         ` Marius Vollmer
@ 2005-10-24 11:35                           ` Ludovic Courtès
  2005-10-24 21:42                             ` Kevin Ryde
  0 siblings, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-10-24 11:35 UTC (permalink / raw)
  Cc: guile-user, Kevin Ryde

Hi Marius,

Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:

> Yeah, I had accidentally disconnected myself from the guile-devel
> mailing list and way too busy with other things to really
> notice... sorry for that.  I will take a look at the patch
> immediately...

Did you have a chance to look at that patch?  :-)

Thanks,
Ludovic.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-24 11:35                           ` Ludovic Courtès
@ 2005-10-24 21:42                             ` Kevin Ryde
  2005-10-25 21:24                               ` Marius Vollmer
  0 siblings, 1 reply; 29+ messages in thread
From: Kevin Ryde @ 2005-10-24 21:42 UTC (permalink / raw)
  Cc: Marius Vollmer

ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> Did you have a chance to look at that patch?  :-)

He liked it before, I'll install it shortly, now your paperwork is on
file.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-24 21:42                             ` Kevin Ryde
@ 2005-10-25 21:24                               ` Marius Vollmer
  2005-10-27  1:06                                 ` Kevin Ryde
  0 siblings, 1 reply; 29+ messages in thread
From: Marius Vollmer @ 2005-10-25 21:24 UTC (permalink / raw)
  Cc: guile-user

Kevin Ryde <user42@zip.com.au> writes:

> He liked it before, I'll install it shortly, now your paperwork is on
> file.

Thanks!  (Sorry for being soooo sloooow....)

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-25 21:24                               ` Marius Vollmer
@ 2005-10-27  1:06                                 ` Kevin Ryde
  2005-10-27  8:49                                   ` Ludovic Courtès
  0 siblings, 1 reply; 29+ messages in thread
From: Kevin Ryde @ 2005-10-27  1:06 UTC (permalink / raw)


Ok, we got there eventually.  I checked it in, and I updated the docs
(have a read to see it they look right).

I want to give the docs a bit more polish, on the various constants
and the address endianness for a start, so don't worry if they're not
yet tip-top.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-27  1:06                                 ` Kevin Ryde
@ 2005-10-27  8:49                                   ` Ludovic Courtès
  2005-10-28 23:00                                     ` Kevin Ryde
  0 siblings, 1 reply; 29+ messages in thread
From: Ludovic Courtès @ 2005-10-27  8:49 UTC (permalink / raw)
  Cc: guile-user

Hi,

Kevin Ryde <user42@zip.com.au> writes:

> Ok, we got there eventually.  I checked it in, and I updated the docs
> (have a read to see it they look right).

Great, thanks!

The doc looks good to me.  I'd just suggest the following patch.  It
documents the wrapping/unwrapping C functions (since that was my
original goal).

Thanks,
Ludovic.


--- orig/doc/ref/posix.texi
+++ mod/doc/ref/posix.texi
@@ -2449,18 +2449,20 @@
 @subsubsection Network Socket Address
 @cindex socket
 @cindex network socket
+@cindex socket address
 
-A socket address object identifies a socket endpoint for
-communication.  In the case of @code{AF_INET} for instance, the host
-address is only the machine (or interface on the machine), a port
-number is also needed to specify a particular open socket in a running
+A @dfn{socket address} object identifies a socket endpoint for
+communication.  In the case of @code{AF_INET} for instance, the socket
+address object comprises the machine (or interface on the machine) and
+a port number needed to specify a particular open socket in a running
 client or server process.
 
 A socket address object can be created with,
 
-@defun {Scheme Procedure} make-socket-address AF_INET ipv4addr port
-@defunx {Scheme Procedure} make-socket-address AF_INET6 ipv6addr port [flowinfo [scopeid]]
-@defunx {Scheme Procedure} make-socket-address AF_UNIX path
+@deffn {Scheme Procedure} make-socket-address AF_INET ipv4addr port
+@deffnx {Scheme Procedure} make-socket-address AF_INET6 ipv6addr port [flowinfo [scopeid]]
+@deffnx {Scheme Procedure} make-socket-address AF_UNIX path
+@deffnx {C Function} scm_make_socket_address family address args
 Return a new socket address object.  The first argument is the address
 family, one of the @code{AF} constants, then the arguments vary
 according to the family.
@@ -2473,7 +2475,7 @@
 arguments may be given (both integers, default 0).
 
 For @code{AF_UNIX} the argument is a filename (a string).
-@end defun
+@end deffn
 
 @noindent
 The following functions access the fields of a socket address object,
@@ -2508,6 +2510,34 @@
 scope ID value.
 @end deffn
 
+Guile also defines C functions to manipulate socket address objects
+and to convert them from/to their C representation (a @code{struct
+sockaddr} object) to/from their Scheme representation.
+
+@deftypefn {C Function} {struct sockaddr *}scm_c_make_socket_address (SCM family, SCM address, SCM args, size_t *address_size)
+Return a newly-allocated @code{sockaddr} structure that reflects
+@var{address}, an address of family @var{family}, with the
+family-specific parameters @var{args} (see the description of
+@var{make-socket-address} for details).  On success, a non-@code{NULL}
+pointer is returned and @var{address_size} is updated to the actual
+size (in bytes) of the returned address.  The returned structure must
+eventually be freed using @code{free ()}.
+@end deftypefn
+
+@deftypefn {C Function} SCM scm_from_sockaddr (const struct sockaddr *address, unsigned address_size)
+Return the Scheme object representing @var{address}, a C socket
+address object of size @var{address_size} bytes.
+@end deftypefn
+
+@deftypefn {C Function} {struct sockaddr *}scm_to_sockaddr (SCM address, size_t *address_size)
+Return a newly-allocated @code{sockaddr} structure that reflects
+@var{address}, an address object returned by either
+@code{scm_from_sockaddr ()} or @code{scm_make_socket_address ()}, into
+its C representation.  On success, a non-@code{NULL} pointer is
+returned and @var{address_size} is updated to the actual size (in
+bytes) of the returned address.  The returned value must eventually be
+freed using @code{free ()}.
+@end deftypefn
 
 @node Network Sockets and Communication
 @subsubsection Network Sockets and Communication



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-27  8:49                                   ` Ludovic Courtès
@ 2005-10-28 23:00                                     ` Kevin Ryde
  2005-10-29 17:45                                       ` Marius Vollmer
  0 siblings, 1 reply; 29+ messages in thread
From: Kevin Ryde @ 2005-10-28 23:00 UTC (permalink / raw)


ludovic.courtes@laas.fr (Ludovic Courtès) writes:
>
> I'd just suggest the following patch.

Beaut, I gave it a bit of a tweak and applied it.

(Incidentally, I'm sure this whole thread belongs on guile-devel, not
guile-user.)


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: Socket API improvement, patch #6
  2005-10-28 23:00                                     ` Kevin Ryde
@ 2005-10-29 17:45                                       ` Marius Vollmer
  0 siblings, 0 replies; 29+ messages in thread
From: Marius Vollmer @ 2005-10-29 17:45 UTC (permalink / raw)
  Cc: guile-user

Kevin Ryde <user42@zip.com.au> writes:

> Beaut, I gave it a bit of a tweak and applied it.

Thanks!

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2005-10-29 17:45 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-04 14:37 Exposing common type wrapping/unwrapping methods Ludovic Courtès
2005-05-24 17:53 ` Marius Vollmer
2005-06-14 16:38   ` Ludovic Courtès
2005-08-19  7:57     ` Ludovic Courtès
2005-08-20  6:01       ` Ken Raeburn
2005-08-20 12:40         ` Marius Vollmer
2005-08-20 13:53           ` Ken Raeburn
2005-09-04 22:17             ` Marius Vollmer
2005-09-07  4:17               ` Rob Browning
2005-09-04 22:09     ` Marius Vollmer
2005-09-07  9:49       ` Ludovic Courtès
2005-09-21  9:16         ` Ludovic Courtès
2005-09-22  0:14           ` Kevin Ryde
2005-09-22 13:46             ` Ludovic Courtès
2005-09-22 21:30               ` Kevin Ryde
2005-09-26  9:37                 ` Ludovic Courtès
2005-09-28 21:30               ` Kevin Ryde
2005-10-04 14:08                 ` Socket API improvement, patch #6 Ludovic Courtès
2005-10-17 10:55                   ` Ludovic Courtès
2005-10-17 21:43                     ` Kevin Ryde
2005-10-18  7:45                       ` Ludovic Courtès
2005-10-18 20:17                         ` Marius Vollmer
2005-10-24 11:35                           ` Ludovic Courtès
2005-10-24 21:42                             ` Kevin Ryde
2005-10-25 21:24                               ` Marius Vollmer
2005-10-27  1:06                                 ` Kevin Ryde
2005-10-27  8:49                                   ` Ludovic Courtès
2005-10-28 23:00                                     ` Kevin Ryde
2005-10-29 17:45                                       ` Marius Vollmer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).