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:
parent
73a90115e6
commit
1c80707c55
1 changed files with 43 additions and 40 deletions
|
@ -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"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue