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