/* * Document-method: setsockopt * call-seq: * setsockopt(level, optname, optval) * setsockopt(socketoption) * * Sets a socket option. These are protocol and system specific, see your * local system documentation for details. * * === Parameters * * +level+ is an integer, usually one of the SOL_ constants such as * Socket::SOL_SOCKET, or a protocol level. * A string or symbol of the name, possibly without prefix, is also * accepted. * * +optname+ is an integer, usually one of the SO_ constants, such * as Socket::SO_REUSEADDR. * A string or symbol of the name, possibly without prefix, is also * accepted. * * +optval+ is the value of the option, it is passed to the underlying * setsockopt() as a pointer to a certain number of bytes. How this is * done depends on the type: * - Fixnum: value is assigned to an int, and a pointer to the int is * passed, with length of sizeof(int). * - true or false: 1 or 0 (respectively) is assigned to an int, and the * int is passed as for a Fixnum. Note that +false+ must be passed, * not +nil+. * - String: the string's data and length is passed to the socket. * * +socketoption+ is an instance of Socket::Option * * === Examples * * Some socket options are integers with boolean values, in this case * #setsockopt could be called like this: * sock.setsockopt(:SOCKET, :REUSEADDR, true) * sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true) * sock.setsockopt(Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)) * * Some socket options are integers with numeric values, in this case * #setsockopt could be called like this: * sock.setsockopt(:IP, :TTL, 255) * sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255) * sock.setsockopt(Socket::Option.int(:INET, :IP, :TTL, 255)) * * Option values may be structs. Passing them can be complex as it involves * examining your system headers to determine the correct definition. An * example is an +ip_mreq+, which may be defined in your system headers as: * struct ip_mreq { * struct in_addr imr_multiaddr; * struct in_addr imr_interface; * }; * * In this case #setsockopt could be called like this: * optval = IPAddr.new("224.0.0.251").hton + * IPAddr.new(Socket::INADDR_ANY, Socket::AF_INET).hton * sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, optval) * */ static VALUE bsock_setsockopt(int argc, VALUE *argv, VALUE sock) { UNRUBBY_SOCKET_HACK; VALUE lev, optname, val; int family, level, option; rb_io_t *fptr; int i; char *v; int vlen; if (argc == 1) { lev = rb_funcall(argv[0], rb_intern("level"), 0); optname = rb_funcall(argv[0], rb_intern("optname"), 0); val = rb_funcall(argv[0], rb_intern("data"), 0); } else { rb_scan_args(argc, argv, "30", &lev, &optname, &val); } rb_secure(2); GetOpenFile(sock, fptr); family = rsock_getfamily(fptr->fd); level = rsock_level_arg(family, lev); option = rsock_optname_arg(family, level, optname); switch (TYPE(val)) { case T_FIXNUM: i = FIX2INT(val); goto numval; case T_FALSE: i = 0; goto numval; case T_TRUE: i = 1; numval: v = (char*)&i; vlen = (int)sizeof(i); break; default: StringValue(val); v = RSTRING_PTR(val); vlen = RSTRING_LENINT(val); break; } #define rb_sys_fail_path(path) rb_sys_fail(NIL_P(path) ? 0 : RSTRING_PTR(path)) rb_io_check_closed(fptr); if (setsockopt(fptr->fd, level, option, v, vlen) < 0) rb_sys_fail_path(fptr->pathv); return INT2FIX(0); }
/* * Document-method: getsockopt * call-seq: * getsockopt(level, optname) => socketoption * * Gets a socket option. These are protocol and system specific, see your * local system documentation for details. The option is returned as * a Socket::Option object. * * === Parameters * * +level+ is an integer, usually one of the SOL_ constants such as * Socket::SOL_SOCKET, or a protocol level. * A string or symbol of the name, possibly without prefix, is also * accepted. * * +optname+ is an integer, usually one of the SO_ constants, such * as Socket::SO_REUSEADDR. * A string or symbol of the name, possibly without prefix, is also * accepted. * * === Examples * * Some socket options are integers with boolean values, in this case * #getsockopt could be called like this: * * reuseaddr = sock.getsockopt(:SOCKET, :REUSEADDR).bool * * optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR) * optval = optval.unpack "i" * reuseaddr = optval[0] == 0 ? false : true * * Some socket options are integers with numeric values, in this case * #getsockopt could be called like this: * * ipttl = sock.getsockopt(:IP, :TTL).int * * optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL) * ipttl = optval.unpack("i")[0] * * Option values may be structs. Decoding them can be complex as it involves * examining your system headers to determine the correct definition. An * example is a +struct linger+, which may be defined in your system headers * as: * struct linger { * int l_onoff; * int l_linger; * }; * * In this case #getsockopt could be called like this: * * # Socket::Option knows linger structure. * onoff, linger = sock.getsockopt(:SOCKET, :LINGER).linger * * optval = sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER) * onoff, linger = optval.unpack "ii" * onoff = onoff == 0 ? false : true */ static VALUE bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname) { int level, option; socklen_t len; char *buf; rb_io_t *fptr; int family; GetOpenFile(sock, fptr); family = rsock_getfamily(fptr->fd); level = rsock_level_arg(family, lev); option = rsock_optname_arg(family, level, optname); len = 256; buf = ALLOCA_N(char,len); rb_io_check_closed(fptr); if (getsockopt(fptr->fd, level, option, buf, &len) < 0) rb_sys_fail_path(fptr->pathv); return rsock_sockopt_new(family, level, option, rb_str_new(buf, len)); }