Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /************************************************ 00002 00003 socket.c - 00004 00005 created at: Thu Mar 31 12:21:29 JST 1994 00006 00007 Copyright (C) 1993-2007 Yukihiro Matsumoto 00008 00009 ************************************************/ 00010 00011 #include "rubysocket.h" 00012 00013 static void 00014 setup_domain_and_type(VALUE domain, int *dv, VALUE type, int *tv) 00015 { 00016 *dv = rsock_family_arg(domain); 00017 *tv = rsock_socktype_arg(type); 00018 } 00019 00020 /* 00021 * call-seq: 00022 * Socket.new(domain, socktype [, protocol]) => socket 00023 * 00024 * Creates a new socket object. 00025 * 00026 * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc. 00027 * 00028 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc. 00029 * 00030 * _protocol_ is optional and should be a protocol defined in the domain. 00031 * If protocol is not given, 0 is used internally. 00032 * 00033 * Socket.new(:INET, :STREAM) # TCP socket 00034 * Socket.new(:INET, :DGRAM) # UDP socket 00035 * Socket.new(:UNIX, :STREAM) # UNIX stream socket 00036 * Socket.new(:UNIX, :DGRAM) # UNIX datagram socket 00037 */ 00038 static VALUE 00039 sock_initialize(int argc, VALUE *argv, VALUE sock) 00040 { 00041 VALUE domain, type, protocol; 00042 int fd; 00043 int d, t; 00044 00045 rb_scan_args(argc, argv, "21", &domain, &type, &protocol); 00046 if (NIL_P(protocol)) 00047 protocol = INT2FIX(0); 00048 00049 rb_secure(3); 00050 setup_domain_and_type(domain, &d, type, &t); 00051 fd = rsock_socket(d, t, NUM2INT(protocol)); 00052 if (fd < 0) rb_sys_fail("socket(2)"); 00053 00054 return rsock_init_sock(sock, fd); 00055 } 00056 00057 #if defined HAVE_SOCKETPAIR 00058 static VALUE 00059 io_call_close(VALUE io) 00060 { 00061 return rb_funcall(io, rb_intern("close"), 0, 0); 00062 } 00063 00064 static VALUE 00065 io_close(VALUE io) 00066 { 00067 return rb_rescue(io_call_close, io, 0, 0); 00068 } 00069 00070 static VALUE 00071 pair_yield(VALUE pair) 00072 { 00073 return rb_ensure(rb_yield, pair, io_close, rb_ary_entry(pair, 1)); 00074 } 00075 #endif 00076 00077 #if defined HAVE_SOCKETPAIR 00078 00079 static int 00080 rsock_socketpair0(int domain, int type, int protocol, int sv[2]) 00081 { 00082 int ret; 00083 00084 #ifdef SOCK_CLOEXEC 00085 static int try_sock_cloexec = 1; 00086 if (try_sock_cloexec) { 00087 ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv); 00088 if (ret == -1 && errno == EINVAL) { 00089 /* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */ 00090 ret = socketpair(domain, type, protocol, sv); 00091 if (ret != -1) { 00092 /* The reason of EINVAL may be other than SOCK_CLOEXEC. 00093 * So disable SOCK_CLOEXEC only if socketpair() succeeds without SOCK_CLOEXEC. 00094 * Ex. Socket.pair(:UNIX, 0xff) fails with EINVAL. 00095 */ 00096 try_sock_cloexec = 0; 00097 } 00098 } 00099 } 00100 else { 00101 ret = socketpair(domain, type, protocol, sv); 00102 } 00103 #else 00104 ret = socketpair(domain, type, protocol, sv); 00105 #endif 00106 00107 if (ret == -1) { 00108 return -1; 00109 } 00110 00111 rb_fd_fix_cloexec(sv[0]); 00112 rb_fd_fix_cloexec(sv[1]); 00113 00114 return ret; 00115 } 00116 00117 static int 00118 rsock_socketpair(int domain, int type, int protocol, int sv[2]) 00119 { 00120 int ret; 00121 00122 ret = rsock_socketpair0(domain, type, protocol, sv); 00123 if (ret < 0 && (errno == EMFILE || errno == ENFILE)) { 00124 rb_gc(); 00125 ret = rsock_socketpair0(domain, type, protocol, sv); 00126 } 00127 00128 return ret; 00129 } 00130 00131 /* 00132 * call-seq: 00133 * Socket.pair(domain, type, protocol) => [socket1, socket2] 00134 * Socket.socketpair(domain, type, protocol) => [socket1, socket2] 00135 * 00136 * Creates a pair of sockets connected each other. 00137 * 00138 * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc. 00139 * 00140 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc. 00141 * 00142 * _protocol_ should be a protocol defined in the domain, 00143 * defaults to 0 for the domain. 00144 * 00145 * s1, s2 = Socket.pair(:UNIX, :DGRAM, 0) 00146 * s1.send "a", 0 00147 * s1.send "b", 0 00148 * p s2.recv(10) #=> "a" 00149 * p s2.recv(10) #=> "b" 00150 * 00151 */ 00152 VALUE 00153 rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass) 00154 { 00155 VALUE domain, type, protocol; 00156 int d, t, p, sp[2]; 00157 int ret; 00158 VALUE s1, s2, r; 00159 00160 rb_scan_args(argc, argv, "21", &domain, &type, &protocol); 00161 if (NIL_P(protocol)) 00162 protocol = INT2FIX(0); 00163 00164 setup_domain_and_type(domain, &d, type, &t); 00165 p = NUM2INT(protocol); 00166 ret = rsock_socketpair(d, t, p, sp); 00167 if (ret < 0) { 00168 rb_sys_fail("socketpair(2)"); 00169 } 00170 rb_fd_fix_cloexec(sp[0]); 00171 rb_fd_fix_cloexec(sp[1]); 00172 00173 s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]); 00174 s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]); 00175 r = rb_assoc_new(s1, s2); 00176 if (rb_block_given_p()) { 00177 return rb_ensure(pair_yield, r, io_close, s1); 00178 } 00179 return r; 00180 } 00181 #else 00182 #define rsock_sock_s_socketpair rb_f_notimplement 00183 #endif 00184 00185 /* 00186 * call-seq: 00187 * socket.connect(remote_sockaddr) => 0 00188 * 00189 * Requests a connection to be made on the given +remote_sockaddr+. Returns 0 if 00190 * successful, otherwise an exception is raised. 00191 * 00192 * === Parameter 00193 * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object 00194 * 00195 * === Example: 00196 * # Pull down Google's web page 00197 * require 'socket' 00198 * include Socket::Constants 00199 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 00200 * sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' ) 00201 * socket.connect( sockaddr ) 00202 * socket.write( "GET / HTTP/1.0\r\n\r\n" ) 00203 * results = socket.read 00204 * 00205 * === Unix-based Exceptions 00206 * On unix-based systems the following system exceptions may be raised if 00207 * the call to _connect_ fails: 00208 * * Errno::EACCES - search permission is denied for a component of the prefix 00209 * path or write access to the +socket+ is denied 00210 * * Errno::EADDRINUSE - the _sockaddr_ is already in use 00211 * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the 00212 * local machine 00213 * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for 00214 * the address family of the specified +socket+ 00215 * * Errno::EALREADY - a connection is already in progress for the specified 00216 * socket 00217 * * Errno::EBADF - the +socket+ is not a valid file descriptor 00218 * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections 00219 * refused the connection request 00220 * * Errno::ECONNRESET - the remote host reset the connection request 00221 * * Errno::EFAULT - the _sockaddr_ cannot be accessed 00222 * * Errno::EHOSTUNREACH - the destination host cannot be reached (probably 00223 * because the host is down or a remote router cannot reach it) 00224 * * Errno::EINPROGRESS - the O_NONBLOCK is set for the +socket+ and the 00225 * connection cannot be immediately established; the connection will be 00226 * established asynchronously 00227 * * Errno::EINTR - the attempt to establish the connection was interrupted by 00228 * delivery of a signal that was caught; the connection will be established 00229 * asynchronously 00230 * * Errno::EISCONN - the specified +socket+ is already connected 00231 * * Errno::EINVAL - the address length used for the _sockaddr_ is not a valid 00232 * length for the address family or there is an invalid family in _sockaddr_ 00233 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded 00234 * PATH_MAX 00235 * * Errno::ENETDOWN - the local interface used to reach the destination is down 00236 * * Errno::ENETUNREACH - no route to the network is present 00237 * * Errno::ENOBUFS - no buffer space is available 00238 * * Errno::ENOSR - there were insufficient STREAMS resources available to 00239 * complete the operation 00240 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket 00241 * * Errno::EOPNOTSUPP - the calling +socket+ is listening and cannot be connected 00242 * * Errno::EPROTOTYPE - the _sockaddr_ has a different type than the socket 00243 * bound to the specified peer address 00244 * * Errno::ETIMEDOUT - the attempt to connect time out before a connection 00245 * was made. 00246 * 00247 * On unix-based systems if the address family of the calling +socket+ is 00248 * AF_UNIX the follow exceptions may be raised if the call to _connect_ 00249 * fails: 00250 * * Errno::EIO - an i/o error occurred while reading from or writing to the 00251 * file system 00252 * * Errno::ELOOP - too many symbolic links were encountered in translating 00253 * the pathname in _sockaddr_ 00254 * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX 00255 * characters, or an entire pathname exceeded PATH_MAX characters 00256 * * Errno::ENOENT - a component of the pathname does not name an existing file 00257 * or the pathname is an empty string 00258 * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_ 00259 * is not a directory 00260 * 00261 * === Windows Exceptions 00262 * On Windows systems the following system exceptions may be raised if 00263 * the call to _connect_ fails: 00264 * * Errno::ENETDOWN - the network is down 00265 * * Errno::EADDRINUSE - the socket's local address is already in use 00266 * * Errno::EINTR - the socket was cancelled 00267 * * Errno::EINPROGRESS - a blocking socket is in progress or the service provider 00268 * is still processing a callback function. Or a nonblocking connect call is 00269 * in progress on the +socket+. 00270 * * Errno::EALREADY - see Errno::EINVAL 00271 * * Errno::EADDRNOTAVAIL - the remote address is not a valid address, such as 00272 * ADDR_ANY TODO check ADDRANY TO INADDR_ANY 00273 * * Errno::EAFNOSUPPORT - addresses in the specified family cannot be used with 00274 * with this +socket+ 00275 * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections 00276 * refused the connection request 00277 * * Errno::EFAULT - the socket's internal address or address length parameter 00278 * is too small or is not a valid part of the user space address 00279 * * Errno::EINVAL - the +socket+ is a listening socket 00280 * * Errno::EISCONN - the +socket+ is already connected 00281 * * Errno::ENETUNREACH - the network cannot be reached from this host at this time 00282 * * Errno::EHOSTUNREACH - no route to the network is present 00283 * * Errno::ENOBUFS - no buffer space is available 00284 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket 00285 * * Errno::ETIMEDOUT - the attempt to connect time out before a connection 00286 * was made. 00287 * * Errno::EWOULDBLOCK - the socket is marked as nonblocking and the 00288 * connection cannot be completed immediately 00289 * * Errno::EACCES - the attempt to connect the datagram socket to the 00290 * broadcast address failed 00291 * 00292 * === See 00293 * * connect manual pages on unix-based systems 00294 * * connect function in Microsoft's Winsock functions reference 00295 */ 00296 static VALUE 00297 sock_connect(VALUE sock, VALUE addr) 00298 { 00299 rb_io_t *fptr; 00300 int fd, n; 00301 00302 SockAddrStringValue(addr); 00303 addr = rb_str_new4(addr); 00304 GetOpenFile(sock, fptr); 00305 fd = fptr->fd; 00306 n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr), 0); 00307 if (n < 0) { 00308 rb_sys_fail("connect(2)"); 00309 } 00310 00311 return INT2FIX(n); 00312 } 00313 00314 /* 00315 * call-seq: 00316 * socket.connect_nonblock(remote_sockaddr) => 0 00317 * 00318 * Requests a connection to be made on the given +remote_sockaddr+ after 00319 * O_NONBLOCK is set for the underlying file descriptor. 00320 * Returns 0 if successful, otherwise an exception is raised. 00321 * 00322 * === Parameter 00323 * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object 00324 * 00325 * === Example: 00326 * # Pull down Google's web page 00327 * require 'socket' 00328 * include Socket::Constants 00329 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 00330 * sockaddr = Socket.sockaddr_in(80, 'www.google.com') 00331 * begin # emulate blocking connect 00332 * socket.connect_nonblock(sockaddr) 00333 * rescue IO::WaitWritable 00334 * IO.select(nil, [socket]) # wait 3-way handshake completion 00335 * begin 00336 * socket.connect_nonblock(sockaddr) # check connection failure 00337 * rescue Errno::EISCONN 00338 * end 00339 * end 00340 * socket.write("GET / HTTP/1.0\r\n\r\n") 00341 * results = socket.read 00342 * 00343 * Refer to Socket#connect for the exceptions that may be thrown if the call 00344 * to _connect_nonblock_ fails. 00345 * 00346 * Socket#connect_nonblock may raise any error corresponding to connect(2) failure, 00347 * including Errno::EINPROGRESS. 00348 * 00349 * If the exception is Errno::EINPROGRESS, 00350 * it is extended by IO::WaitWritable. 00351 * So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock. 00352 * 00353 * === See 00354 * * Socket#connect 00355 */ 00356 static VALUE 00357 sock_connect_nonblock(VALUE sock, VALUE addr) 00358 { 00359 rb_io_t *fptr; 00360 int n; 00361 00362 SockAddrStringValue(addr); 00363 addr = rb_str_new4(addr); 00364 GetOpenFile(sock, fptr); 00365 rb_io_set_nonblock(fptr); 00366 n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr)); 00367 if (n < 0) { 00368 if (errno == EINPROGRESS) 00369 rb_mod_sys_fail(rb_mWaitWritable, "connect(2) would block"); 00370 rb_sys_fail("connect(2)"); 00371 } 00372 00373 return INT2FIX(n); 00374 } 00375 00376 /* 00377 * call-seq: 00378 * socket.bind(local_sockaddr) => 0 00379 * 00380 * Binds to the given local address. 00381 * 00382 * === Parameter 00383 * * +local_sockaddr+ - the +struct+ sockaddr contained in a string or an Addrinfo object 00384 * 00385 * === Example 00386 * require 'socket' 00387 * 00388 * # use Addrinfo 00389 * socket = Socket.new(:INET, :STREAM, 0) 00390 * socket.bind(Addrinfo.tcp("127.0.0.1", 2222)) 00391 * p socket.local_address #=> #<Addrinfo: 127.0.0.1:2222 TCP> 00392 * 00393 * # use struct sockaddr 00394 * include Socket::Constants 00395 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 00396 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 00397 * socket.bind( sockaddr ) 00398 * 00399 * === Unix-based Exceptions 00400 * On unix-based based systems the following system exceptions may be raised if 00401 * the call to _bind_ fails: 00402 * * Errno::EACCES - the specified _sockaddr_ is protected and the current 00403 * user does not have permission to bind to it 00404 * * Errno::EADDRINUSE - the specified _sockaddr_ is already in use 00405 * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the 00406 * local machine 00407 * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for 00408 * the family of the calling +socket+ 00409 * * Errno::EBADF - the _sockaddr_ specified is not a valid file descriptor 00410 * * Errno::EFAULT - the _sockaddr_ argument cannot be accessed 00411 * * Errno::EINVAL - the +socket+ is already bound to an address, and the 00412 * protocol does not support binding to the new _sockaddr_ or the +socket+ 00413 * has been shut down. 00414 * * Errno::EINVAL - the address length is not a valid length for the address 00415 * family 00416 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded 00417 * PATH_MAX 00418 * * Errno::ENOBUFS - no buffer space is available 00419 * * Errno::ENOSR - there were insufficient STREAMS resources available to 00420 * complete the operation 00421 * * Errno::ENOTSOCK - the +socket+ does not refer to a socket 00422 * * Errno::EOPNOTSUPP - the socket type of the +socket+ does not support 00423 * binding to an address 00424 * 00425 * On unix-based based systems if the address family of the calling +socket+ is 00426 * Socket::AF_UNIX the follow exceptions may be raised if the call to _bind_ 00427 * fails: 00428 * * Errno::EACCES - search permission is denied for a component of the prefix 00429 * path or write access to the +socket+ is denied 00430 * * Errno::EDESTADDRREQ - the _sockaddr_ argument is a null pointer 00431 * * Errno::EISDIR - same as Errno::EDESTADDRREQ 00432 * * Errno::EIO - an i/o error occurred 00433 * * Errno::ELOOP - too many symbolic links were encountered in translating 00434 * the pathname in _sockaddr_ 00435 * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX 00436 * characters, or an entire pathname exceeded PATH_MAX characters 00437 * * Errno::ENOENT - a component of the pathname does not name an existing file 00438 * or the pathname is an empty string 00439 * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_ 00440 * is not a directory 00441 * * Errno::EROFS - the name would reside on a read only filesystem 00442 * 00443 * === Windows Exceptions 00444 * On Windows systems the following system exceptions may be raised if 00445 * the call to _bind_ fails: 00446 * * Errno::ENETDOWN-- the network is down 00447 * * Errno::EACCES - the attempt to connect the datagram socket to the 00448 * broadcast address failed 00449 * * Errno::EADDRINUSE - the socket's local address is already in use 00450 * * Errno::EADDRNOTAVAIL - the specified address is not a valid address for this 00451 * computer 00452 * * Errno::EFAULT - the socket's internal address or address length parameter 00453 * is too small or is not a valid part of the user space addressed 00454 * * Errno::EINVAL - the +socket+ is already bound to an address 00455 * * Errno::ENOBUFS - no buffer space is available 00456 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket 00457 * 00458 * === See 00459 * * bind manual pages on unix-based systems 00460 * * bind function in Microsoft's Winsock functions reference 00461 */ 00462 static VALUE 00463 sock_bind(VALUE sock, VALUE addr) 00464 { 00465 rb_io_t *fptr; 00466 00467 SockAddrStringValue(addr); 00468 GetOpenFile(sock, fptr); 00469 if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr)) < 0) 00470 rb_sys_fail("bind(2)"); 00471 00472 return INT2FIX(0); 00473 } 00474 00475 /* 00476 * call-seq: 00477 * socket.listen( int ) => 0 00478 * 00479 * Listens for connections, using the specified +int+ as the backlog. A call 00480 * to _listen_ only applies if the +socket+ is of type SOCK_STREAM or 00481 * SOCK_SEQPACKET. 00482 * 00483 * === Parameter 00484 * * +backlog+ - the maximum length of the queue for pending connections. 00485 * 00486 * === Example 1 00487 * require 'socket' 00488 * include Socket::Constants 00489 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 00490 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 00491 * socket.bind( sockaddr ) 00492 * socket.listen( 5 ) 00493 * 00494 * === Example 2 (listening on an arbitrary port, unix-based systems only): 00495 * require 'socket' 00496 * include Socket::Constants 00497 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 00498 * socket.listen( 1 ) 00499 * 00500 * === Unix-based Exceptions 00501 * On unix based systems the above will work because a new +sockaddr+ struct 00502 * is created on the address ADDR_ANY, for an arbitrary port number as handed 00503 * off by the kernel. It will not work on Windows, because Windows requires that 00504 * the +socket+ is bound by calling _bind_ before it can _listen_. 00505 * 00506 * If the _backlog_ amount exceeds the implementation-dependent maximum 00507 * queue length, the implementation's maximum queue length will be used. 00508 * 00509 * On unix-based based systems the following system exceptions may be raised if the 00510 * call to _listen_ fails: 00511 * * Errno::EBADF - the _socket_ argument is not a valid file descriptor 00512 * * Errno::EDESTADDRREQ - the _socket_ is not bound to a local address, and 00513 * the protocol does not support listening on an unbound socket 00514 * * Errno::EINVAL - the _socket_ is already connected 00515 * * Errno::ENOTSOCK - the _socket_ argument does not refer to a socket 00516 * * Errno::EOPNOTSUPP - the _socket_ protocol does not support listen 00517 * * Errno::EACCES - the calling process does not have appropriate privileges 00518 * * Errno::EINVAL - the _socket_ has been shut down 00519 * * Errno::ENOBUFS - insufficient resources are available in the system to 00520 * complete the call 00521 * 00522 * === Windows Exceptions 00523 * On Windows systems the following system exceptions may be raised if 00524 * the call to _listen_ fails: 00525 * * Errno::ENETDOWN - the network is down 00526 * * Errno::EADDRINUSE - the socket's local address is already in use. This 00527 * usually occurs during the execution of _bind_ but could be delayed 00528 * if the call to _bind_ was to a partially wildcard address (involving 00529 * ADDR_ANY) and if a specific address needs to be committed at the 00530 * time of the call to _listen_ 00531 * * Errno::EINPROGRESS - a Windows Sockets 1.1 call is in progress or the 00532 * service provider is still processing a callback function 00533 * * Errno::EINVAL - the +socket+ has not been bound with a call to _bind_. 00534 * * Errno::EISCONN - the +socket+ is already connected 00535 * * Errno::EMFILE - no more socket descriptors are available 00536 * * Errno::ENOBUFS - no buffer space is available 00537 * * Errno::ENOTSOC - +socket+ is not a socket 00538 * * Errno::EOPNOTSUPP - the referenced +socket+ is not a type that supports 00539 * the _listen_ method 00540 * 00541 * === See 00542 * * listen manual pages on unix-based systems 00543 * * listen function in Microsoft's Winsock functions reference 00544 */ 00545 VALUE 00546 rsock_sock_listen(VALUE sock, VALUE log) 00547 { 00548 rb_io_t *fptr; 00549 int backlog; 00550 00551 rb_secure(4); 00552 backlog = NUM2INT(log); 00553 GetOpenFile(sock, fptr); 00554 if (listen(fptr->fd, backlog) < 0) 00555 rb_sys_fail("listen(2)"); 00556 00557 return INT2FIX(0); 00558 } 00559 00560 /* 00561 * call-seq: 00562 * socket.recvfrom(maxlen) => [mesg, sender_addrinfo] 00563 * socket.recvfrom(maxlen, flags) => [mesg, sender_addrinfo] 00564 * 00565 * Receives up to _maxlen_ bytes from +socket+. _flags_ is zero or more 00566 * of the +MSG_+ options. The first element of the results, _mesg_, is the data 00567 * received. The second element, _sender_addrinfo_, contains protocol-specific 00568 * address information of the sender. 00569 * 00570 * === Parameters 00571 * * +maxlen+ - the maximum number of bytes to receive from the socket 00572 * * +flags+ - zero or more of the +MSG_+ options 00573 * 00574 * === Example 00575 * # In one file, start this first 00576 * require 'socket' 00577 * include Socket::Constants 00578 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 00579 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 00580 * socket.bind( sockaddr ) 00581 * socket.listen( 5 ) 00582 * client, client_addrinfo = socket.accept 00583 * data = client.recvfrom( 20 )[0].chomp 00584 * puts "I only received 20 bytes '#{data}'" 00585 * sleep 1 00586 * socket.close 00587 * 00588 * # In another file, start this second 00589 * require 'socket' 00590 * include Socket::Constants 00591 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 00592 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 00593 * socket.connect( sockaddr ) 00594 * socket.puts "Watch this get cut short!" 00595 * socket.close 00596 * 00597 * === Unix-based Exceptions 00598 * On unix-based based systems the following system exceptions may be raised if the 00599 * call to _recvfrom_ fails: 00600 * * Errno::EAGAIN - the +socket+ file descriptor is marked as O_NONBLOCK and no 00601 * data is waiting to be received; or MSG_OOB is set and no out-of-band data 00602 * is available and either the +socket+ file descriptor is marked as 00603 * O_NONBLOCK or the +socket+ does not support blocking to wait for 00604 * out-of-band-data 00605 * * Errno::EWOULDBLOCK - see Errno::EAGAIN 00606 * * Errno::EBADF - the +socket+ is not a valid file descriptor 00607 * * Errno::ECONNRESET - a connection was forcibly closed by a peer 00608 * * Errno::EFAULT - the socket's internal buffer, address or address length 00609 * cannot be accessed or written 00610 * * Errno::EINTR - a signal interrupted _recvfrom_ before any data was available 00611 * * Errno::EINVAL - the MSG_OOB flag is set and no out-of-band data is available 00612 * * Errno::EIO - an i/o error occurred while reading from or writing to the 00613 * filesystem 00614 * * Errno::ENOBUFS - insufficient resources were available in the system to 00615 * perform the operation 00616 * * Errno::ENOMEM - insufficient memory was available to fulfill the request 00617 * * Errno::ENOSR - there were insufficient STREAMS resources available to 00618 * complete the operation 00619 * * Errno::ENOTCONN - a receive is attempted on a connection-mode socket that 00620 * is not connected 00621 * * Errno::ENOTSOCK - the +socket+ does not refer to a socket 00622 * * Errno::EOPNOTSUPP - the specified flags are not supported for this socket type 00623 * * Errno::ETIMEDOUT - the connection timed out during connection establishment 00624 * or due to a transmission timeout on an active connection 00625 * 00626 * === Windows Exceptions 00627 * On Windows systems the following system exceptions may be raised if 00628 * the call to _recvfrom_ fails: 00629 * * Errno::ENETDOWN - the network is down 00630 * * Errno::EFAULT - the internal buffer and from parameters on +socket+ are not 00631 * part of the user address space, or the internal fromlen parameter is 00632 * too small to accommodate the peer address 00633 * * Errno::EINTR - the (blocking) call was cancelled by an internal call to 00634 * the WinSock function WSACancelBlockingCall 00635 * * Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or 00636 * the service provider is still processing a callback function 00637 * * Errno::EINVAL - +socket+ has not been bound with a call to _bind_, or an 00638 * unknown flag was specified, or MSG_OOB was specified for a socket with 00639 * SO_OOBINLINE enabled, or (for byte stream-style sockets only) the internal 00640 * len parameter on +socket+ was zero or negative 00641 * * Errno::EISCONN - +socket+ is already connected. The call to _recvfrom_ is 00642 * not permitted with a connected socket on a socket that is connection 00643 * oriented or connectionless. 00644 * * Errno::ENETRESET - the connection has been broken due to the keep-alive 00645 * activity detecting a failure while the operation was in progress. 00646 * * Errno::EOPNOTSUPP - MSG_OOB was specified, but +socket+ is not stream-style 00647 * such as type SOCK_STREAM. OOB data is not supported in the communication 00648 * domain associated with +socket+, or +socket+ is unidirectional and 00649 * supports only send operations 00650 * * Errno::ESHUTDOWN - +socket+ has been shutdown. It is not possible to 00651 * call _recvfrom_ on a socket after _shutdown_ has been invoked. 00652 * * Errno::EWOULDBLOCK - +socket+ is marked as nonblocking and a call to 00653 * _recvfrom_ would block. 00654 * * Errno::EMSGSIZE - the message was too large to fit into the specified buffer 00655 * and was truncated. 00656 * * Errno::ETIMEDOUT - the connection has been dropped, because of a network 00657 * failure or because the system on the other end went down without 00658 * notice 00659 * * Errno::ECONNRESET - the virtual circuit was reset by the remote side 00660 * executing a hard or abortive close. The application should close the 00661 * socket; it is no longer usable. On a UDP-datagram socket this error 00662 * indicates a previous send operation resulted in an ICMP Port Unreachable 00663 * message. 00664 */ 00665 static VALUE 00666 sock_recvfrom(int argc, VALUE *argv, VALUE sock) 00667 { 00668 return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET); 00669 } 00670 00671 /* 00672 * call-seq: 00673 * socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo] 00674 * socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo] 00675 * 00676 * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after 00677 * O_NONBLOCK is set for the underlying file descriptor. 00678 * _flags_ is zero or more of the +MSG_+ options. 00679 * The first element of the results, _mesg_, is the data received. 00680 * The second element, _sender_addrinfo_, contains protocol-specific address 00681 * information of the sender. 00682 * 00683 * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns 00684 * an empty string as data. 00685 * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc. 00686 * 00687 * === Parameters 00688 * * +maxlen+ - the maximum number of bytes to receive from the socket 00689 * * +flags+ - zero or more of the +MSG_+ options 00690 * 00691 * === Example 00692 * # In one file, start this first 00693 * require 'socket' 00694 * include Socket::Constants 00695 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 00696 * sockaddr = Socket.sockaddr_in(2200, 'localhost') 00697 * socket.bind(sockaddr) 00698 * socket.listen(5) 00699 * client, client_addrinfo = socket.accept 00700 * begin # emulate blocking recvfrom 00701 * pair = client.recvfrom_nonblock(20) 00702 * rescue IO::WaitReadable 00703 * IO.select([client]) 00704 * retry 00705 * end 00706 * data = pair[0].chomp 00707 * puts "I only received 20 bytes '#{data}'" 00708 * sleep 1 00709 * socket.close 00710 * 00711 * # In another file, start this second 00712 * require 'socket' 00713 * include Socket::Constants 00714 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 00715 * sockaddr = Socket.sockaddr_in(2200, 'localhost') 00716 * socket.connect(sockaddr) 00717 * socket.puts "Watch this get cut short!" 00718 * socket.close 00719 * 00720 * Refer to Socket#recvfrom for the exceptions that may be thrown if the call 00721 * to _recvfrom_nonblock_ fails. 00722 * 00723 * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, 00724 * including Errno::EWOULDBLOCK. 00725 * 00726 * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN, 00727 * it is extended by IO::WaitReadable. 00728 * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock. 00729 * 00730 * === See 00731 * * Socket#recvfrom 00732 */ 00733 static VALUE 00734 sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) 00735 { 00736 return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET); 00737 } 00738 00739 /* 00740 * call-seq: 00741 * socket.accept => [client_socket, client_addrinfo] 00742 * 00743 * Accepts a next connection. 00744 * Returns a new Socket object and Addrinfo object. 00745 * 00746 * serv = Socket.new(:INET, :STREAM, 0) 00747 * serv.listen(5) 00748 * c = Socket.new(:INET, :STREAM, 0) 00749 * c.connect(serv.connect_address) 00750 * p serv.accept #=> [#<Socket:fd 6>, #<Addrinfo: 127.0.0.1:48555 TCP>] 00751 * 00752 */ 00753 static VALUE 00754 sock_accept(VALUE sock) 00755 { 00756 rb_io_t *fptr; 00757 VALUE sock2; 00758 struct sockaddr_storage buf; 00759 socklen_t len = (socklen_t)sizeof buf; 00760 00761 GetOpenFile(sock, fptr); 00762 sock2 = rsock_s_accept(rb_cSocket,fptr->fd,(struct sockaddr*)&buf,&len); 00763 00764 return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len)); 00765 } 00766 00767 /* 00768 * call-seq: 00769 * socket.accept_nonblock => [client_socket, client_addrinfo] 00770 * 00771 * Accepts an incoming connection using accept(2) after 00772 * O_NONBLOCK is set for the underlying file descriptor. 00773 * It returns an array containing the accepted socket 00774 * for the incoming connection, _client_socket_, 00775 * and an Addrinfo, _client_addrinfo_. 00776 * 00777 * === Example 00778 * # In one script, start this first 00779 * require 'socket' 00780 * include Socket::Constants 00781 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 00782 * sockaddr = Socket.sockaddr_in(2200, 'localhost') 00783 * socket.bind(sockaddr) 00784 * socket.listen(5) 00785 * begin # emulate blocking accept 00786 * client_socket, client_addrinfo = socket.accept_nonblock 00787 * rescue IO::WaitReadable, Errno::EINTR 00788 * IO.select([socket]) 00789 * retry 00790 * end 00791 * puts "The client said, '#{client_socket.readline.chomp}'" 00792 * client_socket.puts "Hello from script one!" 00793 * socket.close 00794 * 00795 * # In another script, start this second 00796 * require 'socket' 00797 * include Socket::Constants 00798 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 00799 * sockaddr = Socket.sockaddr_in(2200, 'localhost') 00800 * socket.connect(sockaddr) 00801 * socket.puts "Hello from script 2." 00802 * puts "The server said, '#{socket.readline.chomp}'" 00803 * socket.close 00804 * 00805 * Refer to Socket#accept for the exceptions that may be thrown if the call 00806 * to _accept_nonblock_ fails. 00807 * 00808 * Socket#accept_nonblock may raise any error corresponding to accept(2) failure, 00809 * including Errno::EWOULDBLOCK. 00810 * 00811 * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO, 00812 * it is extended by IO::WaitReadable. 00813 * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock. 00814 * 00815 * === See 00816 * * Socket#accept 00817 */ 00818 static VALUE 00819 sock_accept_nonblock(VALUE sock) 00820 { 00821 rb_io_t *fptr; 00822 VALUE sock2; 00823 struct sockaddr_storage buf; 00824 socklen_t len = (socklen_t)sizeof buf; 00825 00826 GetOpenFile(sock, fptr); 00827 sock2 = rsock_s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)&buf, &len); 00828 return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len)); 00829 } 00830 00831 /* 00832 * call-seq: 00833 * socket.sysaccept => [client_socket_fd, client_addrinfo] 00834 * 00835 * Accepts an incoming connection returning an array containing the (integer) 00836 * file descriptor for the incoming connection, _client_socket_fd_, 00837 * and an Addrinfo, _client_addrinfo_. 00838 * 00839 * === Example 00840 * # In one script, start this first 00841 * require 'socket' 00842 * include Socket::Constants 00843 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 00844 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 00845 * socket.bind( sockaddr ) 00846 * socket.listen( 5 ) 00847 * client_fd, client_addrinfo = socket.sysaccept 00848 * client_socket = Socket.for_fd( client_fd ) 00849 * puts "The client said, '#{client_socket.readline.chomp}'" 00850 * client_socket.puts "Hello from script one!" 00851 * socket.close 00852 * 00853 * # In another script, start this second 00854 * require 'socket' 00855 * include Socket::Constants 00856 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 00857 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 00858 * socket.connect( sockaddr ) 00859 * socket.puts "Hello from script 2." 00860 * puts "The server said, '#{socket.readline.chomp}'" 00861 * socket.close 00862 * 00863 * Refer to Socket#accept for the exceptions that may be thrown if the call 00864 * to _sysaccept_ fails. 00865 * 00866 * === See 00867 * * Socket#accept 00868 */ 00869 static VALUE 00870 sock_sysaccept(VALUE sock) 00871 { 00872 rb_io_t *fptr; 00873 VALUE sock2; 00874 struct sockaddr_storage buf; 00875 socklen_t len = (socklen_t)sizeof buf; 00876 00877 GetOpenFile(sock, fptr); 00878 sock2 = rsock_s_accept(0,fptr->fd,(struct sockaddr*)&buf,&len); 00879 00880 return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len)); 00881 } 00882 00883 #ifdef HAVE_GETHOSTNAME 00884 /* 00885 * call-seq: 00886 * Socket.gethostname => hostname 00887 * 00888 * Returns the hostname. 00889 * 00890 * p Socket.gethostname #=> "hal" 00891 * 00892 * Note that it is not guaranteed to be able to convert to IP address using gethostbyname, getaddrinfo, etc. 00893 * If you need local IP address, use Socket.ip_address_list. 00894 */ 00895 static VALUE 00896 sock_gethostname(VALUE obj) 00897 { 00898 #ifndef HOST_NAME_MAX 00899 # define HOST_NAME_MAX 1024 00900 #endif 00901 char buf[HOST_NAME_MAX+1]; 00902 00903 rb_secure(3); 00904 if (gethostname(buf, (int)sizeof buf - 1) < 0) 00905 rb_sys_fail("gethostname"); 00906 00907 buf[sizeof buf - 1] = '\0'; 00908 return rb_str_new2(buf); 00909 } 00910 #else 00911 #ifdef HAVE_UNAME 00912 00913 #include <sys/utsname.h> 00914 00915 static VALUE 00916 sock_gethostname(VALUE obj) 00917 { 00918 struct utsname un; 00919 00920 rb_secure(3); 00921 uname(&un); 00922 return rb_str_new2(un.nodename); 00923 } 00924 #else 00925 #define sock_gethostname rb_f_notimplement 00926 #endif 00927 #endif 00928 00929 static VALUE 00930 make_addrinfo(struct addrinfo *res0, int norevlookup) 00931 { 00932 VALUE base, ary; 00933 struct addrinfo *res; 00934 00935 if (res0 == NULL) { 00936 rb_raise(rb_eSocket, "host not found"); 00937 } 00938 base = rb_ary_new(); 00939 for (res = res0; res; res = res->ai_next) { 00940 ary = rsock_ipaddr(res->ai_addr, norevlookup); 00941 if (res->ai_canonname) { 00942 RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname); 00943 } 00944 rb_ary_push(ary, INT2FIX(res->ai_family)); 00945 rb_ary_push(ary, INT2FIX(res->ai_socktype)); 00946 rb_ary_push(ary, INT2FIX(res->ai_protocol)); 00947 rb_ary_push(base, ary); 00948 } 00949 return base; 00950 } 00951 00952 static VALUE 00953 sock_sockaddr(struct sockaddr *addr, size_t len) 00954 { 00955 char *ptr; 00956 00957 switch (addr->sa_family) { 00958 case AF_INET: 00959 ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr; 00960 len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr); 00961 break; 00962 #ifdef AF_INET6 00963 case AF_INET6: 00964 ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr; 00965 len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr); 00966 break; 00967 #endif 00968 default: 00969 rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family); 00970 break; 00971 } 00972 return rb_str_new(ptr, len); 00973 } 00974 00975 /* 00976 * call-seq: 00977 * Socket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list] 00978 * 00979 * Obtains the host information for _hostname_. 00980 * 00981 * p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"] 00982 * 00983 */ 00984 static VALUE 00985 sock_s_gethostbyname(VALUE obj, VALUE host) 00986 { 00987 rb_secure(3); 00988 return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr); 00989 } 00990 00991 /* 00992 * call-seq: 00993 * Socket.gethostbyaddr(address_string [, address_family]) => hostent 00994 * 00995 * Obtains the host information for _address_. 00996 * 00997 * p Socket.gethostbyaddr([221,186,184,68].pack("CCCC")) 00998 * #=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"] 00999 */ 01000 static VALUE 01001 sock_s_gethostbyaddr(int argc, VALUE *argv) 01002 { 01003 VALUE addr, family; 01004 struct hostent *h; 01005 char **pch; 01006 VALUE ary, names; 01007 int t = AF_INET; 01008 01009 rb_scan_args(argc, argv, "11", &addr, &family); 01010 StringValue(addr); 01011 if (!NIL_P(family)) { 01012 t = rsock_family_arg(family); 01013 } 01014 #ifdef AF_INET6 01015 else if (RSTRING_LEN(addr) == 16) { 01016 t = AF_INET6; 01017 } 01018 #endif 01019 h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_LENINT(addr), t); 01020 if (h == NULL) { 01021 #ifdef HAVE_HSTRERROR 01022 extern int h_errno; 01023 rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno)); 01024 #else 01025 rb_raise(rb_eSocket, "host not found"); 01026 #endif 01027 } 01028 ary = rb_ary_new(); 01029 rb_ary_push(ary, rb_str_new2(h->h_name)); 01030 names = rb_ary_new(); 01031 rb_ary_push(ary, names); 01032 if (h->h_aliases != NULL) { 01033 for (pch = h->h_aliases; *pch; pch++) { 01034 rb_ary_push(names, rb_str_new2(*pch)); 01035 } 01036 } 01037 rb_ary_push(ary, INT2NUM(h->h_addrtype)); 01038 #ifdef h_addr 01039 for (pch = h->h_addr_list; *pch; pch++) { 01040 rb_ary_push(ary, rb_str_new(*pch, h->h_length)); 01041 } 01042 #else 01043 rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length)); 01044 #endif 01045 01046 return ary; 01047 } 01048 01049 /* 01050 * call-seq: 01051 * Socket.getservbyname(service_name) => port_number 01052 * Socket.getservbyname(service_name, protocol_name) => port_number 01053 * 01054 * Obtains the port number for _service_name_. 01055 * 01056 * If _protocol_name_ is not given, "tcp" is assumed. 01057 * 01058 * Socket.getservbyname("smtp") #=> 25 01059 * Socket.getservbyname("shell") #=> 514 01060 * Socket.getservbyname("syslog", "udp") #=> 514 01061 */ 01062 static VALUE 01063 sock_s_getservbyname(int argc, VALUE *argv) 01064 { 01065 VALUE service, proto; 01066 struct servent *sp; 01067 long port; 01068 const char *servicename, *protoname = "tcp"; 01069 01070 rb_scan_args(argc, argv, "11", &service, &proto); 01071 StringValue(service); 01072 if (!NIL_P(proto)) StringValue(proto); 01073 servicename = StringValueCStr(service); 01074 if (!NIL_P(proto)) protoname = StringValueCStr(proto); 01075 sp = getservbyname(servicename, protoname); 01076 if (sp) { 01077 port = ntohs(sp->s_port); 01078 } 01079 else { 01080 char *end; 01081 01082 port = STRTOUL(servicename, &end, 0); 01083 if (*end != '\0') { 01084 rb_raise(rb_eSocket, "no such service %s/%s", servicename, protoname); 01085 } 01086 } 01087 return INT2FIX(port); 01088 } 01089 01090 /* 01091 * call-seq: 01092 * Socket.getservbyport(port [, protocol_name]) => service 01093 * 01094 * Obtains the port number for _port_. 01095 * 01096 * If _protocol_name_ is not given, "tcp" is assumed. 01097 * 01098 * Socket.getservbyport(80) #=> "www" 01099 * Socket.getservbyport(514, "tcp") #=> "shell" 01100 * Socket.getservbyport(514, "udp") #=> "syslog" 01101 * 01102 */ 01103 static VALUE 01104 sock_s_getservbyport(int argc, VALUE *argv) 01105 { 01106 VALUE port, proto; 01107 struct servent *sp; 01108 long portnum; 01109 const char *protoname = "tcp"; 01110 01111 rb_scan_args(argc, argv, "11", &port, &proto); 01112 portnum = NUM2LONG(port); 01113 if (portnum != (uint16_t)portnum) { 01114 const char *s = portnum > 0 ? "big" : "small"; 01115 rb_raise(rb_eRangeError, "integer %ld too %s to convert into `int16_t'", portnum, s); 01116 } 01117 if (!NIL_P(proto)) protoname = StringValueCStr(proto); 01118 01119 sp = getservbyport((int)htons((uint16_t)portnum), protoname); 01120 if (!sp) { 01121 rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname); 01122 } 01123 return rb_tainted_str_new2(sp->s_name); 01124 } 01125 01126 /* 01127 * call-seq: 01128 * Socket.getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags[, reverse_lookup]]]]]) => array 01129 * 01130 * Obtains address information for _nodename_:_servname_. 01131 * 01132 * _family_ should be an address family such as: :INET, :INET6, :UNIX, etc. 01133 * 01134 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc. 01135 * 01136 * _protocol_ should be a protocol defined in the family, 01137 * and defaults to 0 for the family. 01138 * 01139 * _flags_ should be bitwise OR of Socket::AI_* constants. 01140 * 01141 * Socket.getaddrinfo("www.ruby-lang.org", "http", nil, :STREAM) 01142 * #=> [["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68", 2, 1, 6]] # PF_INET/SOCK_STREAM/IPPROTO_TCP 01143 * 01144 * Socket.getaddrinfo("localhost", nil) 01145 * #=> [["AF_INET", 0, "localhost", "127.0.0.1", 2, 1, 6], # PF_INET/SOCK_STREAM/IPPROTO_TCP 01146 * # ["AF_INET", 0, "localhost", "127.0.0.1", 2, 2, 17], # PF_INET/SOCK_DGRAM/IPPROTO_UDP 01147 * # ["AF_INET", 0, "localhost", "127.0.0.1", 2, 3, 0]] # PF_INET/SOCK_RAW/IPPROTO_IP 01148 * 01149 * _reverse_lookup_ directs the form of the third element, and has to 01150 * be one of below. If _reverse_lookup_ is omitted, the default value is +nil+. 01151 * 01152 * +true+, +:hostname+: hostname is obtained from numeric address using reverse lookup, which may take a time. 01153 * +false+, +:numeric+: hostname is same as numeric address. 01154 * +nil+: obey to the current +do_not_reverse_lookup+ flag. 01155 * 01156 * If Addrinfo object is preferred, use Addrinfo.getaddrinfo. 01157 */ 01158 static VALUE 01159 sock_s_getaddrinfo(int argc, VALUE *argv) 01160 { 01161 VALUE host, port, family, socktype, protocol, flags, ret, revlookup; 01162 struct addrinfo hints, *res; 01163 int norevlookup; 01164 01165 rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup); 01166 01167 MEMZERO(&hints, struct addrinfo, 1); 01168 hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family); 01169 01170 if (!NIL_P(socktype)) { 01171 hints.ai_socktype = rsock_socktype_arg(socktype); 01172 } 01173 if (!NIL_P(protocol)) { 01174 hints.ai_protocol = NUM2INT(protocol); 01175 } 01176 if (!NIL_P(flags)) { 01177 hints.ai_flags = NUM2INT(flags); 01178 } 01179 if (NIL_P(revlookup) || !rsock_revlookup_flag(revlookup, &norevlookup)) { 01180 norevlookup = rsock_do_not_reverse_lookup; 01181 } 01182 res = rsock_getaddrinfo(host, port, &hints, 0); 01183 01184 ret = make_addrinfo(res, norevlookup); 01185 freeaddrinfo(res); 01186 return ret; 01187 } 01188 01189 /* 01190 * call-seq: 01191 * Socket.getnameinfo(sockaddr [, flags]) => [hostname, servicename] 01192 * 01193 * Obtains name information for _sockaddr_. 01194 * 01195 * _sockaddr_ should be one of follows. 01196 * - packed sockaddr string such as Socket.sockaddr_in(80, "127.0.0.1") 01197 * - 3-elements array such as ["AF_INET", 80, "127.0.0.1"] 01198 * - 4-elements array such as ["AF_INET", 80, ignored, "127.0.0.1"] 01199 * 01200 * _flags_ should be bitwise OR of Socket::NI_* constants. 01201 * 01202 * Note: 01203 * The last form is compatible with IPSocket#addr and IPSocket#peeraddr. 01204 * 01205 * Socket.getnameinfo(Socket.sockaddr_in(80, "127.0.0.1")) #=> ["localhost", "www"] 01206 * Socket.getnameinfo(["AF_INET", 80, "127.0.0.1"]) #=> ["localhost", "www"] 01207 * Socket.getnameinfo(["AF_INET", 80, "localhost", "127.0.0.1"]) #=> ["localhost", "www"] 01208 * 01209 * If Addrinfo object is preferred, use Addrinfo#getnameinfo. 01210 */ 01211 static VALUE 01212 sock_s_getnameinfo(int argc, VALUE *argv) 01213 { 01214 VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp; 01215 char *hptr, *pptr; 01216 char hbuf[1024], pbuf[1024]; 01217 int fl; 01218 struct addrinfo hints, *res = NULL, *r; 01219 int error; 01220 struct sockaddr_storage ss; 01221 struct sockaddr *sap; 01222 01223 sa = flags = Qnil; 01224 rb_scan_args(argc, argv, "11", &sa, &flags); 01225 01226 fl = 0; 01227 if (!NIL_P(flags)) { 01228 fl = NUM2INT(flags); 01229 } 01230 tmp = rb_check_sockaddr_string_type(sa); 01231 if (!NIL_P(tmp)) { 01232 sa = tmp; 01233 if (sizeof(ss) < (size_t)RSTRING_LEN(sa)) { 01234 rb_raise(rb_eTypeError, "sockaddr length too big"); 01235 } 01236 memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa)); 01237 if ((size_t)RSTRING_LEN(sa) != SS_LEN(&ss)) { 01238 rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); 01239 } 01240 sap = (struct sockaddr*)&ss; 01241 goto call_nameinfo; 01242 } 01243 tmp = rb_check_array_type(sa); 01244 if (!NIL_P(tmp)) { 01245 sa = tmp; 01246 MEMZERO(&hints, struct addrinfo, 1); 01247 if (RARRAY_LEN(sa) == 3) { 01248 af = RARRAY_PTR(sa)[0]; 01249 port = RARRAY_PTR(sa)[1]; 01250 host = RARRAY_PTR(sa)[2]; 01251 } 01252 else if (RARRAY_LEN(sa) >= 4) { 01253 af = RARRAY_PTR(sa)[0]; 01254 port = RARRAY_PTR(sa)[1]; 01255 host = RARRAY_PTR(sa)[3]; 01256 if (NIL_P(host)) { 01257 host = RARRAY_PTR(sa)[2]; 01258 } 01259 else { 01260 /* 01261 * 4th element holds numeric form, don't resolve. 01262 * see rsock_ipaddr(). 01263 */ 01264 #ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */ 01265 hints.ai_flags |= AI_NUMERICHOST; 01266 #endif 01267 } 01268 } 01269 else { 01270 rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given", 01271 RARRAY_LEN(sa)); 01272 } 01273 /* host */ 01274 if (NIL_P(host)) { 01275 hptr = NULL; 01276 } 01277 else { 01278 strncpy(hbuf, StringValuePtr(host), sizeof(hbuf)); 01279 hbuf[sizeof(hbuf) - 1] = '\0'; 01280 hptr = hbuf; 01281 } 01282 /* port */ 01283 if (NIL_P(port)) { 01284 strcpy(pbuf, "0"); 01285 pptr = NULL; 01286 } 01287 else if (FIXNUM_P(port)) { 01288 snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port)); 01289 pptr = pbuf; 01290 } 01291 else { 01292 strncpy(pbuf, StringValuePtr(port), sizeof(pbuf)); 01293 pbuf[sizeof(pbuf) - 1] = '\0'; 01294 pptr = pbuf; 01295 } 01296 hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM; 01297 /* af */ 01298 hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af); 01299 error = rb_getaddrinfo(hptr, pptr, &hints, &res); 01300 if (error) goto error_exit_addr; 01301 sap = res->ai_addr; 01302 } 01303 else { 01304 rb_raise(rb_eTypeError, "expecting String or Array"); 01305 } 01306 01307 call_nameinfo: 01308 error = rb_getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf), 01309 pbuf, sizeof(pbuf), fl); 01310 if (error) goto error_exit_name; 01311 if (res) { 01312 for (r = res->ai_next; r; r = r->ai_next) { 01313 char hbuf2[1024], pbuf2[1024]; 01314 01315 sap = r->ai_addr; 01316 error = rb_getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2), 01317 pbuf2, sizeof(pbuf2), fl); 01318 if (error) goto error_exit_name; 01319 if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) { 01320 freeaddrinfo(res); 01321 rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename"); 01322 } 01323 } 01324 freeaddrinfo(res); 01325 } 01326 return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf)); 01327 01328 error_exit_addr: 01329 if (res) freeaddrinfo(res); 01330 rsock_raise_socket_error("getaddrinfo", error); 01331 01332 error_exit_name: 01333 if (res) freeaddrinfo(res); 01334 rsock_raise_socket_error("getnameinfo", error); 01335 01336 UNREACHABLE; 01337 } 01338 01339 /* 01340 * call-seq: 01341 * Socket.sockaddr_in(port, host) => sockaddr 01342 * Socket.pack_sockaddr_in(port, host) => sockaddr 01343 * 01344 * Packs _port_ and _host_ as an AF_INET/AF_INET6 sockaddr string. 01345 * 01346 * Socket.sockaddr_in(80, "127.0.0.1") 01347 * #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" 01348 * 01349 * Socket.sockaddr_in(80, "::1") 01350 * #=> "\n\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00" 01351 * 01352 */ 01353 static VALUE 01354 sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host) 01355 { 01356 struct addrinfo *res = rsock_addrinfo(host, port, 0, 0); 01357 VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen); 01358 01359 freeaddrinfo(res); 01360 OBJ_INFECT(addr, port); 01361 OBJ_INFECT(addr, host); 01362 01363 return addr; 01364 } 01365 01366 /* 01367 * call-seq: 01368 * Socket.unpack_sockaddr_in(sockaddr) => [port, ip_address] 01369 * 01370 * Unpacks _sockaddr_ into port and ip_address. 01371 * 01372 * _sockaddr_ should be a string or an addrinfo for AF_INET/AF_INET6. 01373 * 01374 * sockaddr = Socket.sockaddr_in(80, "127.0.0.1") 01375 * p sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" 01376 * p Socket.unpack_sockaddr_in(sockaddr) #=> [80, "127.0.0.1"] 01377 * 01378 */ 01379 static VALUE 01380 sock_s_unpack_sockaddr_in(VALUE self, VALUE addr) 01381 { 01382 struct sockaddr_in * sockaddr; 01383 VALUE host; 01384 01385 sockaddr = (struct sockaddr_in*)SockAddrStringValuePtr(addr); 01386 if (RSTRING_LEN(addr) < 01387 (char*)&((struct sockaddr *)sockaddr)->sa_family + 01388 sizeof(((struct sockaddr *)sockaddr)->sa_family) - 01389 (char*)sockaddr) 01390 rb_raise(rb_eArgError, "too short sockaddr"); 01391 if (((struct sockaddr *)sockaddr)->sa_family != AF_INET 01392 #ifdef INET6 01393 && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6 01394 #endif 01395 ) { 01396 #ifdef INET6 01397 rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr"); 01398 #else 01399 rb_raise(rb_eArgError, "not an AF_INET sockaddr"); 01400 #endif 01401 } 01402 host = rsock_make_ipaddr((struct sockaddr*)sockaddr); 01403 OBJ_INFECT(host, addr); 01404 return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host); 01405 } 01406 01407 #ifdef HAVE_SYS_UN_H 01408 01409 /* 01410 * call-seq: 01411 * Socket.sockaddr_un(path) => sockaddr 01412 * Socket.pack_sockaddr_un(path) => sockaddr 01413 * 01414 * Packs _path_ as an AF_UNIX sockaddr string. 01415 * 01416 * Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..." 01417 * 01418 */ 01419 static VALUE 01420 sock_s_pack_sockaddr_un(VALUE self, VALUE path) 01421 { 01422 struct sockaddr_un sockaddr; 01423 VALUE addr; 01424 01425 StringValue(path); 01426 MEMZERO(&sockaddr, struct sockaddr_un, 1); 01427 sockaddr.sun_family = AF_UNIX; 01428 if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) { 01429 rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)", 01430 (size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path)); 01431 } 01432 memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path)); 01433 addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path)); 01434 OBJ_INFECT(addr, path); 01435 01436 return addr; 01437 } 01438 01439 /* 01440 * call-seq: 01441 * Socket.unpack_sockaddr_un(sockaddr) => path 01442 * 01443 * Unpacks _sockaddr_ into path. 01444 * 01445 * _sockaddr_ should be a string or an addrinfo for AF_UNIX. 01446 * 01447 * sockaddr = Socket.sockaddr_un("/tmp/sock") 01448 * p Socket.unpack_sockaddr_un(sockaddr) #=> "/tmp/sock" 01449 * 01450 */ 01451 static VALUE 01452 sock_s_unpack_sockaddr_un(VALUE self, VALUE addr) 01453 { 01454 struct sockaddr_un * sockaddr; 01455 VALUE path; 01456 01457 sockaddr = (struct sockaddr_un*)SockAddrStringValuePtr(addr); 01458 if (RSTRING_LEN(addr) < 01459 (char*)&((struct sockaddr *)sockaddr)->sa_family + 01460 sizeof(((struct sockaddr *)sockaddr)->sa_family) - 01461 (char*)sockaddr) 01462 rb_raise(rb_eArgError, "too short sockaddr"); 01463 if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) { 01464 rb_raise(rb_eArgError, "not an AF_UNIX sockaddr"); 01465 } 01466 if (sizeof(struct sockaddr_un) < (size_t)RSTRING_LEN(addr)) { 01467 rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d", 01468 RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un)); 01469 } 01470 path = rsock_unixpath_str(sockaddr, RSTRING_LENINT(addr)); 01471 OBJ_INFECT(path, addr); 01472 return path; 01473 } 01474 #endif 01475 01476 #if defined(HAVE_GETIFADDRS) || defined(SIOCGLIFCONF) || defined(SIOCGIFCONF) || defined(_WIN32) 01477 static VALUE 01478 sockaddr_obj(struct sockaddr *addr) 01479 { 01480 socklen_t len; 01481 #if defined(AF_INET6) && defined(__KAME__) 01482 struct sockaddr_in6 addr6; 01483 #endif 01484 01485 if (addr == NULL) 01486 return Qnil; 01487 01488 switch (addr->sa_family) { 01489 case AF_INET: 01490 len = (socklen_t)sizeof(struct sockaddr_in); 01491 break; 01492 01493 #ifdef AF_INET6 01494 case AF_INET6: 01495 len = (socklen_t)sizeof(struct sockaddr_in6); 01496 # ifdef __KAME__ 01497 /* KAME uses the 2nd 16bit word of link local IPv6 address as interface index internally */ 01498 /* http://orange.kame.net/dev/cvsweb.cgi/kame/IMPLEMENTATION */ 01499 /* convert fe80:1::1 to fe80::1%1 */ 01500 memcpy(&addr6, addr, len); 01501 addr = (struct sockaddr *)&addr6; 01502 if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) && 01503 addr6.sin6_scope_id == 0 && 01504 (addr6.sin6_addr.s6_addr[2] || addr6.sin6_addr.s6_addr[3])) { 01505 addr6.sin6_scope_id = (addr6.sin6_addr.s6_addr[2] << 8) | addr6.sin6_addr.s6_addr[3]; 01506 addr6.sin6_addr.s6_addr[2] = 0; 01507 addr6.sin6_addr.s6_addr[3] = 0; 01508 } 01509 # endif 01510 break; 01511 #endif 01512 01513 #ifdef HAVE_SYS_UN_H 01514 case AF_UNIX: 01515 len = (socklen_t)sizeof(struct sockaddr_un); 01516 break; 01517 #endif 01518 01519 default: 01520 len = (socklen_t)sizeof(struct sockaddr_in); 01521 break; 01522 } 01523 #ifdef SA_LEN 01524 if (len < (socklen_t)SA_LEN(addr)) 01525 len = (socklen_t)SA_LEN(addr); 01526 #endif 01527 01528 return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil); 01529 } 01530 #endif 01531 01532 #if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) || defined(_WIN32) 01533 /* 01534 * call-seq: 01535 * Socket.ip_address_list => array 01536 * 01537 * Returns local IP addresses as an array. 01538 * 01539 * The array contains Addrinfo objects. 01540 * 01541 * pp Socket.ip_address_list 01542 * #=> [#<Addrinfo: 127.0.0.1>, 01543 * #<Addrinfo: 192.168.0.128>, 01544 * #<Addrinfo: ::1>, 01545 * ...] 01546 * 01547 */ 01548 static VALUE 01549 socket_s_ip_address_list(VALUE self) 01550 { 01551 #if defined(HAVE_GETIFADDRS) 01552 struct ifaddrs *ifp = NULL; 01553 struct ifaddrs *p; 01554 int ret; 01555 VALUE list; 01556 01557 ret = getifaddrs(&ifp); 01558 if (ret == -1) { 01559 rb_sys_fail("getifaddrs"); 01560 } 01561 01562 list = rb_ary_new(); 01563 for (p = ifp; p; p = p->ifa_next) { 01564 if (p->ifa_addr != NULL && IS_IP_FAMILY(p->ifa_addr->sa_family)) { 01565 rb_ary_push(list, sockaddr_obj(p->ifa_addr)); 01566 } 01567 } 01568 01569 freeifaddrs(ifp); 01570 01571 return list; 01572 #elif defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux) 01573 /* Solaris if_tcp(7P) */ 01574 /* HP-UX has SIOCGLIFCONF too. But it uses different struct */ 01575 int fd = -1; 01576 int ret; 01577 struct lifnum ln; 01578 struct lifconf lc; 01579 char *reason = NULL; 01580 int save_errno; 01581 int i; 01582 VALUE list = Qnil; 01583 01584 lc.lifc_buf = NULL; 01585 01586 fd = socket(AF_INET, SOCK_DGRAM, 0); 01587 if (fd == -1) 01588 rb_sys_fail("socket"); 01589 01590 memset(&ln, 0, sizeof(ln)); 01591 ln.lifn_family = AF_UNSPEC; 01592 01593 ret = ioctl(fd, SIOCGLIFNUM, &ln); 01594 if (ret == -1) { 01595 reason = "SIOCGLIFNUM"; 01596 goto finish; 01597 } 01598 01599 memset(&lc, 0, sizeof(lc)); 01600 lc.lifc_family = AF_UNSPEC; 01601 lc.lifc_flags = 0; 01602 lc.lifc_len = sizeof(struct lifreq) * ln.lifn_count; 01603 lc.lifc_req = xmalloc(lc.lifc_len); 01604 01605 ret = ioctl(fd, SIOCGLIFCONF, &lc); 01606 if (ret == -1) { 01607 reason = "SIOCGLIFCONF"; 01608 goto finish; 01609 } 01610 01611 list = rb_ary_new(); 01612 for (i = 0; i < ln.lifn_count; i++) { 01613 struct lifreq *req = &lc.lifc_req[i]; 01614 if (IS_IP_FAMILY(req->lifr_addr.ss_family)) { 01615 if (req->lifr_addr.ss_family == AF_INET6 && 01616 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_addr) && 01617 ((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id == 0) { 01618 struct lifreq req2; 01619 memcpy(req2.lifr_name, req->lifr_name, LIFNAMSIZ); 01620 ret = ioctl(fd, SIOCGLIFINDEX, &req2); 01621 if (ret == -1) { 01622 reason = "SIOCGLIFINDEX"; 01623 goto finish; 01624 } 01625 ((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id = req2.lifr_index; 01626 } 01627 rb_ary_push(list, sockaddr_obj((struct sockaddr *)&req->lifr_addr)); 01628 } 01629 } 01630 01631 finish: 01632 save_errno = errno; 01633 if (lc.lifc_buf != NULL) 01634 xfree(lc.lifc_req); 01635 if (fd != -1) 01636 close(fd); 01637 errno = save_errno; 01638 01639 if (reason) 01640 rb_sys_fail(reason); 01641 return list; 01642 01643 #elif defined(SIOCGIFCONF) 01644 int fd = -1; 01645 int ret; 01646 #define EXTRA_SPACE (sizeof(struct ifconf) + sizeof(struct sockaddr_storage)) 01647 char initbuf[4096+EXTRA_SPACE]; 01648 char *buf = initbuf; 01649 int bufsize; 01650 struct ifconf conf; 01651 struct ifreq *req; 01652 VALUE list = Qnil; 01653 const char *reason = NULL; 01654 int save_errno; 01655 01656 fd = socket(AF_INET, SOCK_DGRAM, 0); 01657 if (fd == -1) 01658 rb_sys_fail("socket"); 01659 01660 bufsize = sizeof(initbuf); 01661 buf = initbuf; 01662 01663 retry: 01664 conf.ifc_len = bufsize; 01665 conf.ifc_req = (struct ifreq *)buf; 01666 01667 /* fprintf(stderr, "bufsize: %d\n", bufsize); */ 01668 01669 ret = ioctl(fd, SIOCGIFCONF, &conf); 01670 if (ret == -1) { 01671 reason = "SIOCGIFCONF"; 01672 goto finish; 01673 } 01674 01675 /* fprintf(stderr, "conf.ifc_len: %d\n", conf.ifc_len); */ 01676 01677 if (bufsize - EXTRA_SPACE < conf.ifc_len) { 01678 if (bufsize < conf.ifc_len) { 01679 /* NetBSD returns required size for all interfaces. */ 01680 bufsize = conf.ifc_len + EXTRA_SPACE; 01681 } 01682 else { 01683 bufsize = bufsize << 1; 01684 } 01685 if (buf == initbuf) 01686 buf = NULL; 01687 buf = xrealloc(buf, bufsize); 01688 goto retry; 01689 } 01690 01691 close(fd); 01692 fd = -1; 01693 01694 list = rb_ary_new(); 01695 req = conf.ifc_req; 01696 while ((char*)req < (char*)conf.ifc_req + conf.ifc_len) { 01697 struct sockaddr *addr = &req->ifr_addr; 01698 if (IS_IP_FAMILY(addr->sa_family)) { 01699 rb_ary_push(list, sockaddr_obj(addr)); 01700 } 01701 #ifdef HAVE_SA_LEN 01702 # ifndef _SIZEOF_ADDR_IFREQ 01703 # define _SIZEOF_ADDR_IFREQ(r) \ 01704 (sizeof(struct ifreq) + \ 01705 (sizeof(struct sockaddr) < (r).ifr_addr.sa_len ? \ 01706 (r).ifr_addr.sa_len - sizeof(struct sockaddr) : \ 01707 0)) 01708 # endif 01709 req = (struct ifreq *)((char*)req + _SIZEOF_ADDR_IFREQ(*req)); 01710 #else 01711 req = (struct ifreq *)((char*)req + sizeof(struct ifreq)); 01712 #endif 01713 } 01714 01715 finish: 01716 01717 save_errno = errno; 01718 if (buf != initbuf) 01719 xfree(buf); 01720 if (fd != -1) 01721 close(fd); 01722 errno = save_errno; 01723 01724 if (reason) 01725 rb_sys_fail(reason); 01726 return list; 01727 01728 #undef EXTRA_SPACE 01729 #elif defined(_WIN32) 01730 typedef struct ip_adapter_unicast_address_st { 01731 unsigned LONG_LONG dummy0; 01732 struct ip_adapter_unicast_address_st *Next; 01733 struct { 01734 struct sockaddr *lpSockaddr; 01735 int iSockaddrLength; 01736 } Address; 01737 int dummy1; 01738 int dummy2; 01739 int dummy3; 01740 long dummy4; 01741 long dummy5; 01742 long dummy6; 01743 } ip_adapter_unicast_address_t; 01744 typedef struct ip_adapter_anycast_address_st { 01745 unsigned LONG_LONG dummy0; 01746 struct ip_adapter_anycast_address_st *Next; 01747 struct { 01748 struct sockaddr *lpSockaddr; 01749 int iSockaddrLength; 01750 } Address; 01751 } ip_adapter_anycast_address_t; 01752 typedef struct ip_adapter_addresses_st { 01753 unsigned LONG_LONG dummy0; 01754 struct ip_adapter_addresses_st *Next; 01755 void *dummy1; 01756 ip_adapter_unicast_address_t *FirstUnicastAddress; 01757 ip_adapter_anycast_address_t *FirstAnycastAddress; 01758 void *dummy2; 01759 void *dummy3; 01760 void *dummy4; 01761 void *dummy5; 01762 void *dummy6; 01763 BYTE dummy7[8]; 01764 DWORD dummy8; 01765 DWORD dummy9; 01766 DWORD dummy10; 01767 DWORD IfType; 01768 int OperStatus; 01769 DWORD dummy12; 01770 DWORD dummy13[16]; 01771 void *dummy14; 01772 } ip_adapter_addresses_t; 01773 typedef ULONG (WINAPI *GetAdaptersAddresses_t)(ULONG, ULONG, PVOID, ip_adapter_addresses_t *, PULONG); 01774 HMODULE h; 01775 GetAdaptersAddresses_t pGetAdaptersAddresses; 01776 ULONG len; 01777 DWORD ret; 01778 ip_adapter_addresses_t *adapters; 01779 VALUE list; 01780 01781 h = LoadLibrary("iphlpapi.dll"); 01782 if (!h) 01783 rb_notimplement(); 01784 pGetAdaptersAddresses = (GetAdaptersAddresses_t)GetProcAddress(h, "GetAdaptersAddresses"); 01785 if (!pGetAdaptersAddresses) { 01786 FreeLibrary(h); 01787 rb_notimplement(); 01788 } 01789 01790 ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &len); 01791 if (ret != ERROR_SUCCESS && ret != ERROR_BUFFER_OVERFLOW) { 01792 errno = rb_w32_map_errno(ret); 01793 FreeLibrary(h); 01794 rb_sys_fail("GetAdaptersAddresses"); 01795 } 01796 adapters = (ip_adapter_addresses_t *)ALLOCA_N(BYTE, len); 01797 ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &len); 01798 if (ret != ERROR_SUCCESS) { 01799 errno = rb_w32_map_errno(ret); 01800 FreeLibrary(h); 01801 rb_sys_fail("GetAdaptersAddresses"); 01802 } 01803 01804 list = rb_ary_new(); 01805 for (; adapters; adapters = adapters->Next) { 01806 ip_adapter_unicast_address_t *uni; 01807 ip_adapter_anycast_address_t *any; 01808 if (adapters->OperStatus != 1) /* 1 means IfOperStatusUp */ 01809 continue; 01810 for (uni = adapters->FirstUnicastAddress; uni; uni = uni->Next) { 01811 #ifndef INET6 01812 if (uni->Address.lpSockaddr->sa_family == AF_INET) 01813 #else 01814 if (IS_IP_FAMILY(uni->Address.lpSockaddr->sa_family)) 01815 #endif 01816 rb_ary_push(list, sockaddr_obj(uni->Address.lpSockaddr)); 01817 } 01818 for (any = adapters->FirstAnycastAddress; any; any = any->Next) { 01819 #ifndef INET6 01820 if (any->Address.lpSockaddr->sa_family == AF_INET) 01821 #else 01822 if (IS_IP_FAMILY(any->Address.lpSockaddr->sa_family)) 01823 #endif 01824 rb_ary_push(list, sockaddr_obj(any->Address.lpSockaddr)); 01825 } 01826 } 01827 01828 FreeLibrary(h); 01829 return list; 01830 #endif 01831 } 01832 #else 01833 #define socket_s_ip_address_list rb_f_notimplement 01834 #endif 01835 01836 void 01837 Init_socket() 01838 { 01839 rsock_init_basicsocket(); 01840 01841 /* 01842 * Document-class: Socket < BasicSocket 01843 * 01844 * Class +Socket+ provides access to the underlying operating system 01845 * socket implementations. It can be used to provide more operating system 01846 * specific functionality than the protocol-specific socket classes. 01847 * 01848 * The constants defined under Socket::Constants are also defined under 01849 * Socket. For example, Socket::AF_INET is usable as well as 01850 * Socket::Constants::AF_INET. See Socket::Constants for the list of 01851 * constants. 01852 * 01853 * === What's a socket? 01854 * 01855 * Sockets are endpoints of a bidirectionnal communication channel. 01856 * Sockets can communicate within a process, between processes on the same 01857 * machine or between different machines. There are many types of socket: 01858 * TCPSocket, UDPSocket or UNIXSocket for example. 01859 * 01860 * Sockets have their own vocabulary: 01861 * 01862 * *domain:* 01863 * The family of protocols: 01864 * * Socket::PF_INET 01865 * * Socket::PF_INET6 01866 * * Socket::PF_UNIX 01867 * * etc. 01868 * 01869 * *type:* 01870 * The type of communications between the two endpoints, typically 01871 * * Socket::SOCK_STREAM 01872 * * Socket::SOCK_DGRAM. 01873 * 01874 * *protocol:* 01875 * Typically _zero_. 01876 * This may be used to identify a variant of a protocol. 01877 * 01878 * *hostname:* 01879 * The identifier of a network interface: 01880 * * a string (hostname, IPv4 or IPv6 adress or +broadcast+ 01881 * which specifies a broadcast address) 01882 * * a zero-length string which specifies INADDR_ANY 01883 * * an integer (interpreted as binary address in host byte order). 01884 * 01885 * === Quick start 01886 * 01887 * Many of the classes, such as TCPSocket, UDPSocket or UNIXSocket, 01888 * ease the use of sockets comparatively to the equivalent C programming interface. 01889 * 01890 * Let's create an internet socket using the IPv4 protocol in a C-like manner: 01891 * 01892 * s = Socket.new Socket::AF_INET, Socket::SOCK_STREAM 01893 * s.connect Socket.pack_sockaddr_in(80, 'example.com') 01894 * 01895 * You could also use the TCPSocket class: 01896 * 01897 * s = TCPSocket.new 'example.com', 80 01898 * 01899 * A simple server might look like this: 01900 * 01901 * require 'socket' 01902 * 01903 * server = TCPServer.new 2000 # Server bound to port 2000 01904 * 01905 * loop do 01906 * client = server.accept # Wait for a client to connect 01907 * client.puts "Hello !" 01908 * client.puts "Time is #{Time.now}" 01909 * client.close 01910 * end 01911 * 01912 * A simple client may look like this: 01913 * 01914 * require 'socket' 01915 * 01916 * s = TCPSocket.new 'localhost', 2000 01917 * 01918 * while line = s.gets # Read lines from socket 01919 * puts line # and print them 01920 * end 01921 * 01922 * s.close # close socket when done 01923 * 01924 * === Exception Handling 01925 * 01926 * Ruby's Socket implementation raises exceptions based on the error 01927 * generated by the system dependent implementation. This is why the 01928 * methods are documented in a way that isolate Unix-based system 01929 * exceptions from Windows based exceptions. If more information on a 01930 * particular exception is needed, please refer to the Unix manual pages or 01931 * the Windows WinSock reference. 01932 * 01933 * === Convenience methods 01934 * 01935 * Although the general way to create socket is Socket.new, 01936 * there are several methods of socket creation for most cases. 01937 * 01938 * TCP client socket:: 01939 * Socket.tcp, TCPSocket.open 01940 * TCP server socket:: 01941 * Socket.tcp_server_loop, TCPServer.open 01942 * UNIX client socket:: 01943 * Socket.unix, UNIXSocket.open 01944 * UNIX server socket:: 01945 * Socket.unix_server_loop, UNIXServer.open 01946 * 01947 * === Documentation by 01948 * 01949 * * Zach Dennis 01950 * * Sam Roberts 01951 * * <em>Programming Ruby</em> from The Pragmatic Bookshelf. 01952 * 01953 * Much material in this documentation is taken with permission from 01954 * <em>Programming Ruby</em> from The Pragmatic Bookshelf. 01955 */ 01956 rb_cSocket = rb_define_class("Socket", rb_cBasicSocket); 01957 01958 rsock_init_socket_init(); 01959 01960 rb_define_method(rb_cSocket, "initialize", sock_initialize, -1); 01961 rb_define_method(rb_cSocket, "connect", sock_connect, 1); 01962 rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, 1); 01963 rb_define_method(rb_cSocket, "bind", sock_bind, 1); 01964 rb_define_method(rb_cSocket, "listen", rsock_sock_listen, 1); 01965 rb_define_method(rb_cSocket, "accept", sock_accept, 0); 01966 rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, 0); 01967 rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0); 01968 01969 rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1); 01970 rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1); 01971 01972 rb_define_singleton_method(rb_cSocket, "socketpair", rsock_sock_s_socketpair, -1); 01973 rb_define_singleton_method(rb_cSocket, "pair", rsock_sock_s_socketpair, -1); 01974 rb_define_singleton_method(rb_cSocket, "gethostname", sock_gethostname, 0); 01975 rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1); 01976 rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1); 01977 rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyname, -1); 01978 rb_define_singleton_method(rb_cSocket, "getservbyport", sock_s_getservbyport, -1); 01979 rb_define_singleton_method(rb_cSocket, "getaddrinfo", sock_s_getaddrinfo, -1); 01980 rb_define_singleton_method(rb_cSocket, "getnameinfo", sock_s_getnameinfo, -1); 01981 rb_define_singleton_method(rb_cSocket, "sockaddr_in", sock_s_pack_sockaddr_in, 2); 01982 rb_define_singleton_method(rb_cSocket, "pack_sockaddr_in", sock_s_pack_sockaddr_in, 2); 01983 rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_in", sock_s_unpack_sockaddr_in, 1); 01984 #ifdef HAVE_SYS_UN_H 01985 rb_define_singleton_method(rb_cSocket, "sockaddr_un", sock_s_pack_sockaddr_un, 1); 01986 rb_define_singleton_method(rb_cSocket, "pack_sockaddr_un", sock_s_pack_sockaddr_un, 1); 01987 rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_un", sock_s_unpack_sockaddr_un, 1); 01988 #endif 01989 01990 rb_define_singleton_method(rb_cSocket, "ip_address_list", socket_s_ip_address_list, 0); 01991 } 01992