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