diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2001-02-08 09:19:27 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2001-02-08 09:19:27 +0000 |
commit | ed520cf6e96dcae2b7900127e325fcea1f4abc26 (patch) | |
tree | 89c098f2e02099588c8b4f74fbb8e37c15045d49 /ext/socket/socket.c | |
parent | b576f57aa02c4983eeb081f625c45b9445c50538 (diff) |
* parse.y (parse_quotedwords): %w should allow parenthesis escape.
* parse.y (parse_qstring): %q should allow terminator escape.
* re.c (rb_reg_options): new method to give an option values.
* parse.y (cond0): disable special treating of integer literal in
conditional unless option -e is supplied. changes current
behavior. experimental.
* parse.y (cond0): give warning for string/integer literals and
dot operators in conditionals unless option -e is supplied.
* re.c (rb_reg_equal): all option flags should be same to be equal.
* error.c (Init_Exception): make Interrupt a subclass of
SignalException.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1167 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/socket/socket.c')
-rw-r--r-- | ext/socket/socket.c | 96 |
1 files changed, 73 insertions, 23 deletions
diff --git a/ext/socket/socket.c b/ext/socket/socket.c index d688869c65..1ef2e894f0 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -776,18 +776,17 @@ ruby_connect(fd, sockaddr, len, socks) } static VALUE -open_inet(class, h, serv, type) - VALUE class, h, serv; +load_addr_info(h, serv, type, res) + VALUE h, serv; int type; + struct addrinfo **res; { - struct addrinfo hints, *res, *res0; - int fd, status; - char *syscall; - char pbuf[1024], *portp; char *host; + char pbuf[1024], *portp; + struct addrinfo hints; int error; - if (h) { + if (!NIL_P(h)) { Check_SafeStr(h); host = RSTRING(h)->ptr; } @@ -811,13 +810,32 @@ open_inet(class, h, serv, type) if (type == INET_SERVER) { hints.ai_flags = AI_PASSIVE; } - error = getaddrinfo(host, portp, &hints, &res0); + error = getaddrinfo(host, portp, &hints, res); if (error) { rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error)); } +} +static VALUE +open_inet(class, remote_host, remote_serv, local_host, local_serv, type) + VALUE class, remote_host, remote_serv, local_host, local_serv; + int type; +{ + struct addrinfo hints, *res, *res_remote, *res_local = NULL; + int fd, status; + char *syscall; + + load_addr_info(remote_host, remote_serv, type, &res_remote); + + /* + * Maybe also accept a local address + */ + + if (type != INET_SERVER && (!NIL_P(local_host) || !NIL_P(local_serv))) + load_addr_info(local_host, local_serv, type, &res_local); + fd = -1; - for (res = res0; res; res = res->ai_next) { + for (res = res_remote; res; res = res->ai_next) { status = ruby_socket(res->ai_family,res->ai_socktype,res->ai_protocol); syscall = "socket(2)"; fd = status; @@ -832,9 +850,16 @@ open_inet(class, h, serv, type) syscall = "bind(2)"; } else { - status = ruby_connect(fd, res->ai_addr, res->ai_addrlen, - (type == INET_SOCKS)); - syscall = "connect(2)"; + if (res_local) { + status = bind(fd, res_local->ai_addr, res_local->ai_addrlen); + syscall = "bind(2)"; + } + + if (status >= 0) { + status = ruby_connect(fd, res->ai_addr, res->ai_addrlen, + (type == INET_SOCKS)); + syscall = "connect(2)"; + } } if (status < 0) { @@ -855,7 +880,10 @@ open_inet(class, h, serv, type) #else close(fd); #endif - freeaddrinfo(res0); + freeaddrinfo(res_remote); + if (res_local) { + freeaddrinfo(res_local); + } rb_sys_fail(syscall); } @@ -863,16 +891,38 @@ open_inet(class, h, serv, type) listen(fd, 5); /* create new instance */ - freeaddrinfo(res0); + if (res_local) + freeaddrinfo(res_local); + freeaddrinfo(res_remote); return sock_new(class, fd); } static VALUE -tcp_s_open(class, host, serv) - VALUE class, host, serv; +tcp_s_open(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; { - Check_SafeStr(host); - return open_inet(class, host, serv, INET_CLIENT); + VALUE remote_host, remote_serv; + VALUE local_host, local_serv; + + int pcount = rb_scan_args(argc, argv, "22", + &remote_host, &remote_serv, + &local_host, &local_serv); + + Check_SafeStr(remote_host); + + + if (!NIL_P(local_host)) { + Check_SafeStr(local_host); + } + + if (NIL_P(local_serv)) { + local_serv = INT2NUM(0); + } + + return open_inet(class, remote_host, remote_serv, + local_host, local_serv, INET_CLIENT); } #ifdef SOCKS @@ -888,7 +938,7 @@ socks_s_open(class, host, serv) } Check_SafeStr(host); - return open_inet(class, host, serv, INET_SOCKS); + return open_inet(class, host, serv, Qnil, Qnil, INET_SOCKS); } #ifdef SOCKS5 @@ -1031,9 +1081,9 @@ tcp_svr_s_open(argc, argv, class) VALUE arg1, arg2; if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) - return open_inet(class, arg1, arg2, INET_SERVER); + return open_inet(class, arg1, arg2, NULL, Qnil, INET_SERVER); else - return open_inet(class, 0, arg1, INET_SERVER); + return open_inet(class, Qnil, arg1, NULL, Qnil, INET_SERVER); } static VALUE @@ -2053,8 +2103,8 @@ Init_socket() rb_cTCPSocket = rb_define_class("TCPSocket", rb_cIPSocket); rb_define_global_const("TCPsocket", rb_cTCPSocket); - rb_define_singleton_method(rb_cTCPSocket, "open", tcp_s_open, 2); - rb_define_singleton_method(rb_cTCPSocket, "new", tcp_s_open, 2); + rb_define_singleton_method(rb_cTCPSocket, "open", tcp_s_open, -1); + rb_define_singleton_method(rb_cTCPSocket, "new", tcp_s_open, -1); rb_define_singleton_method(rb_cTCPSocket, "gethostbyname", tcp_s_gethostbyname, 1); #ifdef SOCKS |