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