1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-29 16:30:19 +02:00

(scm_setsockopt): Handle IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP

options.  Also, reorganized the code a bit for cleanliness.  Thanks to
Greg Troxel!
This commit is contained in:
Marius Vollmer 2005-02-27 23:50:30 +00:00
parent 73a90115e6
commit 1c80707c55

View file

@ -545,13 +545,16 @@ SCM_DEFINE (scm_setsockopt, "setsockopt", 4, 0, 0,
#define FUNC_NAME s_scm_setsockopt #define FUNC_NAME s_scm_setsockopt
{ {
int fd; int fd;
int optlen = -1;
/* size of optval is the largest supported option. */ int opt_int;
#ifdef HAVE_STRUCT_LINGER #ifdef HAVE_STRUCT_LINGER
char optval[sizeof (struct linger)]; struct linger opt_linger;
#else
char optval[sizeof (size_t)];
#endif #endif
struct ip_mreq opt_mreq;
const void *optval = NULL;
socklen_t optlen = 0;
int ilevel, ioptname; int ilevel, ioptname;
sock = SCM_COERCE_OUTPORT (sock); sock = SCM_COERCE_OUTPORT (sock);
@ -568,32 +571,18 @@ SCM_DEFINE (scm_setsockopt, "setsockopt", 4, 0, 0,
if (ioptname == SO_LINGER) if (ioptname == SO_LINGER)
{ {
#ifdef HAVE_STRUCT_LINGER #ifdef HAVE_STRUCT_LINGER
struct linger ling;
long lv;
SCM_ASSERT (scm_is_pair (value), value, SCM_ARG4, FUNC_NAME); SCM_ASSERT (scm_is_pair (value), value, SCM_ARG4, FUNC_NAME);
lv = SCM_NUM2LONG (4, SCM_CAR (value)); opt_linger.l_onoff = scm_to_int (SCM_CAR (value));
ling.l_onoff = (int) lv; opt_linger.l_linger = scm_to_int (SCM_CDR (value));
SCM_ASSERT_RANGE (SCM_ARG4, value, ling.l_onoff == lv); optlen = sizeof (struct linger);
lv = SCM_NUM2LONG (4, SCM_CDR (value)); optval = &opt_linger;
ling.l_linger = (int) lv;
SCM_ASSERT_RANGE (SCM_ARG4, value, ling.l_linger == lv);
optlen = (int) sizeof (struct linger);
memcpy (optval, (void *) &ling, optlen);
#else #else
int ling;
long lv;
SCM_ASSERT (scm_is_pair (value), value, SCM_ARG4, FUNC_NAME); SCM_ASSERT (scm_is_pair (value), value, SCM_ARG4, FUNC_NAME);
opt_int = scm_to_int (SCM_CAR (value));
/* timeout is ignored, but may as well validate it. */ /* timeout is ignored, but may as well validate it. */
lv = SCM_NUM2LONG (4, SCM_CDR (value)); scm_to_int (SCM_CDR (value));
ling = (int) lv; optlen = sizeof (int);
SCM_ASSERT_RANGE (SCM_ARG4, value, ling == lv); optval = &opt_int;
lv = SCM_NUM2LONG (4, SCM_CAR (value));
ling = (int) lv;
SCM_ASSERT_RANGE (SCM_ARG4, value, ling == lv);
optlen = (int) sizeof (int);
(*(int *) optval) = ling;
#endif #endif
} }
else else
@ -607,23 +596,32 @@ SCM_DEFINE (scm_setsockopt, "setsockopt", 4, 0, 0,
#endif #endif
) )
{ {
long lv = SCM_NUM2LONG (4, value); opt_int = scm_to_int (value);
optlen = sizeof (size_t);
optval = &opt_int;
}
}
optlen = (int) sizeof (size_t); if (ilevel == IPPROTO_IP &&
(*(size_t *) optval) = (size_t) lv; (ioptname == IP_ADD_MEMBERSHIP || ioptname == IP_DROP_MEMBERSHIP))
{
/* Fourth argument must be a pair of addresses. */
SCM_ASSERT (scm_is_pair (value), value, SCM_ARG4, FUNC_NAME);
opt_mreq.imr_multiaddr.s_addr = htonl (scm_to_ulong (SCM_CAR (value)));
opt_mreq.imr_interface.s_addr = htonl (scm_to_ulong (SCM_CDR (value)));
optlen = sizeof (opt_mreq);
optval = &opt_mreq;
} }
}
if (optlen == -1) if (optval == NULL)
{ {
/* Most options take an int. */ /* Most options take an int. */
long lv = SCM_NUM2LONG (4, value); opt_int = scm_to_int (value);
int val = (int) lv; optlen = sizeof (int);
optval = &opt_int;
SCM_ASSERT_RANGE (SCM_ARG4, value, val == lv);
optlen = (int) sizeof (int);
(*(int *) optval) = val;
} }
if (setsockopt (fd, ilevel, ioptname, (void *) optval, optlen) == -1)
if (setsockopt (fd, ilevel, ioptname, optval, optlen) == -1)
SCM_SYSERROR; SCM_SYSERROR;
return SCM_UNSPECIFIED; return SCM_UNSPECIFIED;
} }
@ -1415,6 +1413,11 @@ scm_init_socket ()
scm_i_init_socket_Win32 (); scm_i_init_socket_Win32 ();
#endif #endif
#ifdef IP_ADD_MEMBERSHIP
scm_c_define ("IP_ADD_MEMBERSHIP", scm_from_int (IP_ADD_MEMBERSHIP));
scm_c_define ("IP_DROP_MEMBERSHIP", scm_from_int (IP_DROP_MEMBERSHIP));
#endif
scm_add_feature ("socket"); scm_add_feature ("socket");
#include "libguile/socket.x" #include "libguile/socket.x"