diff --git a/collects/scribblings/reference/networking.scrbl b/collects/scribblings/reference/networking.scrbl index 562fb76e52..e241ea210e 100644 --- a/collects/scribblings/reference/networking.scrbl +++ b/collects/scribblings/reference/networking.scrbl @@ -293,7 +293,8 @@ non-@racket[#f], then the socket's protocol family is IPv4.} @defproc[(udp-bind! [udp-socket udp?] [hostname-string (or/c string? #f)] [port-no (and/c exact-nonnegative-integer? - (integer-in 0 65535))]) + (integer-in 0 65535))] + [reuse? any/c #f]) void?]{ Binds an unbound @racket[udp-socket] to the local port number @@ -325,8 +326,12 @@ socket is later used again in a send, then the later send may change the socket's automatic binding. If @racket[udp-socket] is already bound or closed, the -@exnraise[exn:fail:network].} +@exnraise[exn:fail:network]. +If the @racket[reuse?] argument is true, then @racket[udp-bind!] will +set the @tt{SO_REUSEADDR} socket option before binding, permitting the +sharing of access to a UDP port between many processes on a single +machine when using UDP multicast.} @defproc[(udp-connect! [udp-socket udp?] [hostname-string (or/c string? #f)] diff --git a/src/racket/src/network.c b/src/racket/src/network.c index b64d8ca6ad..0a045dba08 100644 --- a/src/racket/src/network.c +++ b/src/racket/src/network.c @@ -269,7 +269,7 @@ void scheme_init_network(Scheme_Env *env) GLOBAL_FOLDING_PRIM ( "udp?" , udp_p , 1 , 1 , 1 , netenv ) ; GLOBAL_PRIM_W_ARITY ( "udp-bound?" , udp_bound_p , 1 , 1 , netenv ) ; GLOBAL_PRIM_W_ARITY ( "udp-connected?" , udp_connected_p , 1 , 1 , netenv ) ; - GLOBAL_PRIM_W_ARITY ( "udp-bind!" , udp_bind , 3 , 3 , netenv ) ; + GLOBAL_PRIM_W_ARITY ( "udp-bind!" , udp_bind , 3 , 4 , netenv ) ; GLOBAL_PRIM_W_ARITY ( "udp-connect!" , udp_connect , 3 , 3 , netenv ) ; GLOBAL_PRIM_W_ARITY ( "udp-send-to" , udp_send_to , 4 , 6 , netenv ) ; @@ -3276,6 +3276,19 @@ static Scheme_Object *udp_bind_or_connect(const char *name, int argc, Scheme_Obj /* BIND CASE */ else { int ok; + + if ((argc > 3) && SCHEME_TRUEP(argv[3])) { + int one = 1; + if (setsockopt(udp->s, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one))) { + scheme_raise_exn(MZEXN_FAIL_NETWORK, + "%s: can't set SO_REUSEADDR\n" + " system error: %E", + name, + SOCK_ERRNO()); + return NULL; + } + } + if (udp_bind_addr == NULL ) { GC_CAN_IGNORE mz_unspec_address ua; memset(&ua, 0, sizeof(mz_unspec_address));