1/************************************************ 2 3 socket.c - 4 5 created at: Thu Mar 31 12:21:29 JST 1994 6 7 Copyright (C) 1993-2007 Yukihiro Matsumoto 8 9************************************************/ 10 11#include "rubysocket.h" 12 13static void 14setup_domain_and_type(VALUE domain, int *dv, VALUE type, int *tv) 15{ 16 *dv = rsock_family_arg(domain); 17 *tv = rsock_socktype_arg(type); 18} 19 20/* 21 * call-seq: 22 * Socket.new(domain, socktype [, protocol]) => socket 23 * 24 * Creates a new socket object. 25 * 26 * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc. 27 * 28 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc. 29 * 30 * _protocol_ is optional and should be a protocol defined in the domain. 31 * If protocol is not given, 0 is used internally. 32 * 33 * Socket.new(:INET, :STREAM) # TCP socket 34 * Socket.new(:INET, :DGRAM) # UDP socket 35 * Socket.new(:UNIX, :STREAM) # UNIX stream socket 36 * Socket.new(:UNIX, :DGRAM) # UNIX datagram socket 37 */ 38static VALUE 39sock_initialize(int argc, VALUE *argv, VALUE sock) 40{ 41 VALUE domain, type, protocol; 42 int fd; 43 int d, t; 44 45 rb_scan_args(argc, argv, "21", &domain, &type, &protocol); 46 if (NIL_P(protocol)) 47 protocol = INT2FIX(0); 48 49 rb_secure(3); 50 setup_domain_and_type(domain, &d, type, &t); 51 fd = rsock_socket(d, t, NUM2INT(protocol)); 52 if (fd < 0) rb_sys_fail("socket(2)"); 53 54 return rsock_init_sock(sock, fd); 55} 56 57#if defined HAVE_SOCKETPAIR 58static VALUE 59io_call_close(VALUE io) 60{ 61 return rb_funcall(io, rb_intern("close"), 0, 0); 62} 63 64static VALUE 65io_close(VALUE io) 66{ 67 return rb_rescue(io_call_close, io, 0, 0); 68} 69 70static VALUE 71pair_yield(VALUE pair) 72{ 73 return rb_ensure(rb_yield, pair, io_close, rb_ary_entry(pair, 1)); 74} 75#endif 76 77#if defined HAVE_SOCKETPAIR 78 79static int 80rsock_socketpair0(int domain, int type, int protocol, int sv[2]) 81{ 82 int ret; 83 84#ifdef SOCK_CLOEXEC 85 static int try_sock_cloexec = 1; 86 if (try_sock_cloexec) { 87 ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv); 88 if (ret == -1 && errno == EINVAL) { 89 /* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */ 90 ret = socketpair(domain, type, protocol, sv); 91 if (ret != -1) { 92 /* The reason of EINVAL may be other than SOCK_CLOEXEC. 93 * So disable SOCK_CLOEXEC only if socketpair() succeeds without SOCK_CLOEXEC. 94 * Ex. Socket.pair(:UNIX, 0xff) fails with EINVAL. 95 */ 96 try_sock_cloexec = 0; 97 } 98 } 99 } 100 else { 101 ret = socketpair(domain, type, protocol, sv); 102 } 103#else 104 ret = socketpair(domain, type, protocol, sv); 105#endif 106 107 if (ret == -1) { 108 return -1; 109 } 110 111 rb_fd_fix_cloexec(sv[0]); 112 rb_fd_fix_cloexec(sv[1]); 113 114 return ret; 115} 116 117static int 118rsock_socketpair(int domain, int type, int protocol, int sv[2]) 119{ 120 int ret; 121 122 ret = rsock_socketpair0(domain, type, protocol, sv); 123 if (ret < 0 && (errno == EMFILE || errno == ENFILE)) { 124 rb_gc(); 125 ret = rsock_socketpair0(domain, type, protocol, sv); 126 } 127 128 return ret; 129} 130 131/* 132 * call-seq: 133 * Socket.pair(domain, type, protocol) => [socket1, socket2] 134 * Socket.socketpair(domain, type, protocol) => [socket1, socket2] 135 * 136 * Creates a pair of sockets connected each other. 137 * 138 * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc. 139 * 140 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc. 141 * 142 * _protocol_ should be a protocol defined in the domain, 143 * defaults to 0 for the domain. 144 * 145 * s1, s2 = Socket.pair(:UNIX, :DGRAM, 0) 146 * s1.send "a", 0 147 * s1.send "b", 0 148 * p s2.recv(10) #=> "a" 149 * p s2.recv(10) #=> "b" 150 * 151 */ 152VALUE 153rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass) 154{ 155 VALUE domain, type, protocol; 156 int d, t, p, sp[2]; 157 int ret; 158 VALUE s1, s2, r; 159 160 rb_scan_args(argc, argv, "21", &domain, &type, &protocol); 161 if (NIL_P(protocol)) 162 protocol = INT2FIX(0); 163 164 setup_domain_and_type(domain, &d, type, &t); 165 p = NUM2INT(protocol); 166 ret = rsock_socketpair(d, t, p, sp); 167 if (ret < 0) { 168 rb_sys_fail("socketpair(2)"); 169 } 170 rb_fd_fix_cloexec(sp[0]); 171 rb_fd_fix_cloexec(sp[1]); 172 173 s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]); 174 s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]); 175 r = rb_assoc_new(s1, s2); 176 if (rb_block_given_p()) { 177 return rb_ensure(pair_yield, r, io_close, s1); 178 } 179 return r; 180} 181#else 182#define rsock_sock_s_socketpair rb_f_notimplement 183#endif 184 185/* 186 * call-seq: 187 * socket.connect(remote_sockaddr) => 0 188 * 189 * Requests a connection to be made on the given +remote_sockaddr+. Returns 0 if 190 * successful, otherwise an exception is raised. 191 * 192 * === Parameter 193 * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object 194 * 195 * === Example: 196 * # Pull down Google's web page 197 * require 'socket' 198 * include Socket::Constants 199 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 200 * sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' ) 201 * socket.connect( sockaddr ) 202 * socket.write( "GET / HTTP/1.0\r\n\r\n" ) 203 * results = socket.read 204 * 205 * === Unix-based Exceptions 206 * On unix-based systems the following system exceptions may be raised if 207 * the call to _connect_ fails: 208 * * Errno::EACCES - search permission is denied for a component of the prefix 209 * path or write access to the +socket+ is denied 210 * * Errno::EADDRINUSE - the _sockaddr_ is already in use 211 * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the 212 * local machine 213 * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for 214 * the address family of the specified +socket+ 215 * * Errno::EALREADY - a connection is already in progress for the specified 216 * socket 217 * * Errno::EBADF - the +socket+ is not a valid file descriptor 218 * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections 219 * refused the connection request 220 * * Errno::ECONNRESET - the remote host reset the connection request 221 * * Errno::EFAULT - the _sockaddr_ cannot be accessed 222 * * Errno::EHOSTUNREACH - the destination host cannot be reached (probably 223 * because the host is down or a remote router cannot reach it) 224 * * Errno::EINPROGRESS - the O_NONBLOCK is set for the +socket+ and the 225 * connection cannot be immediately established; the connection will be 226 * established asynchronously 227 * * Errno::EINTR - the attempt to establish the connection was interrupted by 228 * delivery of a signal that was caught; the connection will be established 229 * asynchronously 230 * * Errno::EISCONN - the specified +socket+ is already connected 231 * * Errno::EINVAL - the address length used for the _sockaddr_ is not a valid 232 * length for the address family or there is an invalid family in _sockaddr_ 233 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded 234 * PATH_MAX 235 * * Errno::ENETDOWN - the local interface used to reach the destination is down 236 * * Errno::ENETUNREACH - no route to the network is present 237 * * Errno::ENOBUFS - no buffer space is available 238 * * Errno::ENOSR - there were insufficient STREAMS resources available to 239 * complete the operation 240 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket 241 * * Errno::EOPNOTSUPP - the calling +socket+ is listening and cannot be connected 242 * * Errno::EPROTOTYPE - the _sockaddr_ has a different type than the socket 243 * bound to the specified peer address 244 * * Errno::ETIMEDOUT - the attempt to connect time out before a connection 245 * was made. 246 * 247 * On unix-based systems if the address family of the calling +socket+ is 248 * AF_UNIX the follow exceptions may be raised if the call to _connect_ 249 * fails: 250 * * Errno::EIO - an i/o error occurred while reading from or writing to the 251 * file system 252 * * Errno::ELOOP - too many symbolic links were encountered in translating 253 * the pathname in _sockaddr_ 254 * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX 255 * characters, or an entire pathname exceeded PATH_MAX characters 256 * * Errno::ENOENT - a component of the pathname does not name an existing file 257 * or the pathname is an empty string 258 * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_ 259 * is not a directory 260 * 261 * === Windows Exceptions 262 * On Windows systems the following system exceptions may be raised if 263 * the call to _connect_ fails: 264 * * Errno::ENETDOWN - the network is down 265 * * Errno::EADDRINUSE - the socket's local address is already in use 266 * * Errno::EINTR - the socket was cancelled 267 * * Errno::EINPROGRESS - a blocking socket is in progress or the service provider 268 * is still processing a callback function. Or a nonblocking connect call is 269 * in progress on the +socket+. 270 * * Errno::EALREADY - see Errno::EINVAL 271 * * Errno::EADDRNOTAVAIL - the remote address is not a valid address, such as 272 * ADDR_ANY TODO check ADDRANY TO INADDR_ANY 273 * * Errno::EAFNOSUPPORT - addresses in the specified family cannot be used with 274 * with this +socket+ 275 * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections 276 * refused the connection request 277 * * Errno::EFAULT - the socket's internal address or address length parameter 278 * is too small or is not a valid part of the user space address 279 * * Errno::EINVAL - the +socket+ is a listening socket 280 * * Errno::EISCONN - the +socket+ is already connected 281 * * Errno::ENETUNREACH - the network cannot be reached from this host at this time 282 * * Errno::EHOSTUNREACH - no route to the network is present 283 * * Errno::ENOBUFS - no buffer space is available 284 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket 285 * * Errno::ETIMEDOUT - the attempt to connect time out before a connection 286 * was made. 287 * * Errno::EWOULDBLOCK - the socket is marked as nonblocking and the 288 * connection cannot be completed immediately 289 * * Errno::EACCES - the attempt to connect the datagram socket to the 290 * broadcast address failed 291 * 292 * === See 293 * * connect manual pages on unix-based systems 294 * * connect function in Microsoft's Winsock functions reference 295 */ 296static VALUE 297sock_connect(VALUE sock, VALUE addr) 298{ 299 rb_io_t *fptr; 300 int fd, n; 301 302 SockAddrStringValue(addr); 303 addr = rb_str_new4(addr); 304 GetOpenFile(sock, fptr); 305 fd = fptr->fd; 306 n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr), 0); 307 if (n < 0) { 308 rb_sys_fail("connect(2)"); 309 } 310 311 return INT2FIX(n); 312} 313 314/* 315 * call-seq: 316 * socket.connect_nonblock(remote_sockaddr) => 0 317 * 318 * Requests a connection to be made on the given +remote_sockaddr+ after 319 * O_NONBLOCK is set for the underlying file descriptor. 320 * Returns 0 if successful, otherwise an exception is raised. 321 * 322 * === Parameter 323 * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object 324 * 325 * === Example: 326 * # Pull down Google's web page 327 * require 'socket' 328 * include Socket::Constants 329 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 330 * sockaddr = Socket.sockaddr_in(80, 'www.google.com') 331 * begin # emulate blocking connect 332 * socket.connect_nonblock(sockaddr) 333 * rescue IO::WaitWritable 334 * IO.select(nil, [socket]) # wait 3-way handshake completion 335 * begin 336 * socket.connect_nonblock(sockaddr) # check connection failure 337 * rescue Errno::EISCONN 338 * end 339 * end 340 * socket.write("GET / HTTP/1.0\r\n\r\n") 341 * results = socket.read 342 * 343 * Refer to Socket#connect for the exceptions that may be thrown if the call 344 * to _connect_nonblock_ fails. 345 * 346 * Socket#connect_nonblock may raise any error corresponding to connect(2) failure, 347 * including Errno::EINPROGRESS. 348 * 349 * If the exception is Errno::EINPROGRESS, 350 * it is extended by IO::WaitWritable. 351 * So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock. 352 * 353 * === See 354 * * Socket#connect 355 */ 356static VALUE 357sock_connect_nonblock(VALUE sock, VALUE addr) 358{ 359 rb_io_t *fptr; 360 int n; 361 362 SockAddrStringValue(addr); 363 addr = rb_str_new4(addr); 364 GetOpenFile(sock, fptr); 365 rb_io_set_nonblock(fptr); 366 n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr)); 367 if (n < 0) { 368 if (errno == EINPROGRESS) 369 rb_mod_sys_fail(rb_mWaitWritable, "connect(2) would block"); 370 rb_sys_fail("connect(2)"); 371 } 372 373 return INT2FIX(n); 374} 375 376/* 377 * call-seq: 378 * socket.bind(local_sockaddr) => 0 379 * 380 * Binds to the given local address. 381 * 382 * === Parameter 383 * * +local_sockaddr+ - the +struct+ sockaddr contained in a string or an Addrinfo object 384 * 385 * === Example 386 * require 'socket' 387 * 388 * # use Addrinfo 389 * socket = Socket.new(:INET, :STREAM, 0) 390 * socket.bind(Addrinfo.tcp("127.0.0.1", 2222)) 391 * p socket.local_address #=> #<Addrinfo: 127.0.0.1:2222 TCP> 392 * 393 * # use struct sockaddr 394 * include Socket::Constants 395 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 396 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 397 * socket.bind( sockaddr ) 398 * 399 * === Unix-based Exceptions 400 * On unix-based based systems the following system exceptions may be raised if 401 * the call to _bind_ fails: 402 * * Errno::EACCES - the specified _sockaddr_ is protected and the current 403 * user does not have permission to bind to it 404 * * Errno::EADDRINUSE - the specified _sockaddr_ is already in use 405 * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the 406 * local machine 407 * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for 408 * the family of the calling +socket+ 409 * * Errno::EBADF - the _sockaddr_ specified is not a valid file descriptor 410 * * Errno::EFAULT - the _sockaddr_ argument cannot be accessed 411 * * Errno::EINVAL - the +socket+ is already bound to an address, and the 412 * protocol does not support binding to the new _sockaddr_ or the +socket+ 413 * has been shut down. 414 * * Errno::EINVAL - the address length is not a valid length for the address 415 * family 416 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded 417 * PATH_MAX 418 * * Errno::ENOBUFS - no buffer space is available 419 * * Errno::ENOSR - there were insufficient STREAMS resources available to 420 * complete the operation 421 * * Errno::ENOTSOCK - the +socket+ does not refer to a socket 422 * * Errno::EOPNOTSUPP - the socket type of the +socket+ does not support 423 * binding to an address 424 * 425 * On unix-based based systems if the address family of the calling +socket+ is 426 * Socket::AF_UNIX the follow exceptions may be raised if the call to _bind_ 427 * fails: 428 * * Errno::EACCES - search permission is denied for a component of the prefix 429 * path or write access to the +socket+ is denied 430 * * Errno::EDESTADDRREQ - the _sockaddr_ argument is a null pointer 431 * * Errno::EISDIR - same as Errno::EDESTADDRREQ 432 * * Errno::EIO - an i/o error occurred 433 * * Errno::ELOOP - too many symbolic links were encountered in translating 434 * the pathname in _sockaddr_ 435 * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX 436 * characters, or an entire pathname exceeded PATH_MAX characters 437 * * Errno::ENOENT - a component of the pathname does not name an existing file 438 * or the pathname is an empty string 439 * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_ 440 * is not a directory 441 * * Errno::EROFS - the name would reside on a read only filesystem 442 * 443 * === Windows Exceptions 444 * On Windows systems the following system exceptions may be raised if 445 * the call to _bind_ fails: 446 * * Errno::ENETDOWN-- the network is down 447 * * Errno::EACCES - the attempt to connect the datagram socket to the 448 * broadcast address failed 449 * * Errno::EADDRINUSE - the socket's local address is already in use 450 * * Errno::EADDRNOTAVAIL - the specified address is not a valid address for this 451 * computer 452 * * Errno::EFAULT - the socket's internal address or address length parameter 453 * is too small or is not a valid part of the user space addressed 454 * * Errno::EINVAL - the +socket+ is already bound to an address 455 * * Errno::ENOBUFS - no buffer space is available 456 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket 457 * 458 * === See 459 * * bind manual pages on unix-based systems 460 * * bind function in Microsoft's Winsock functions reference 461 */ 462static VALUE 463sock_bind(VALUE sock, VALUE addr) 464{ 465 rb_io_t *fptr; 466 467 SockAddrStringValue(addr); 468 GetOpenFile(sock, fptr); 469 if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr)) < 0) 470 rb_sys_fail("bind(2)"); 471 472 return INT2FIX(0); 473} 474 475/* 476 * call-seq: 477 * socket.listen( int ) => 0 478 * 479 * Listens for connections, using the specified +int+ as the backlog. A call 480 * to _listen_ only applies if the +socket+ is of type SOCK_STREAM or 481 * SOCK_SEQPACKET. 482 * 483 * === Parameter 484 * * +backlog+ - the maximum length of the queue for pending connections. 485 * 486 * === Example 1 487 * require 'socket' 488 * include Socket::Constants 489 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 490 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 491 * socket.bind( sockaddr ) 492 * socket.listen( 5 ) 493 * 494 * === Example 2 (listening on an arbitrary port, unix-based systems only): 495 * require 'socket' 496 * include Socket::Constants 497 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 498 * socket.listen( 1 ) 499 * 500 * === Unix-based Exceptions 501 * On unix based systems the above will work because a new +sockaddr+ struct 502 * is created on the address ADDR_ANY, for an arbitrary port number as handed 503 * off by the kernel. It will not work on Windows, because Windows requires that 504 * the +socket+ is bound by calling _bind_ before it can _listen_. 505 * 506 * If the _backlog_ amount exceeds the implementation-dependent maximum 507 * queue length, the implementation's maximum queue length will be used. 508 * 509 * On unix-based based systems the following system exceptions may be raised if the 510 * call to _listen_ fails: 511 * * Errno::EBADF - the _socket_ argument is not a valid file descriptor 512 * * Errno::EDESTADDRREQ - the _socket_ is not bound to a local address, and 513 * the protocol does not support listening on an unbound socket 514 * * Errno::EINVAL - the _socket_ is already connected 515 * * Errno::ENOTSOCK - the _socket_ argument does not refer to a socket 516 * * Errno::EOPNOTSUPP - the _socket_ protocol does not support listen 517 * * Errno::EACCES - the calling process does not have appropriate privileges 518 * * Errno::EINVAL - the _socket_ has been shut down 519 * * Errno::ENOBUFS - insufficient resources are available in the system to 520 * complete the call 521 * 522 * === Windows Exceptions 523 * On Windows systems the following system exceptions may be raised if 524 * the call to _listen_ fails: 525 * * Errno::ENETDOWN - the network is down 526 * * Errno::EADDRINUSE - the socket's local address is already in use. This 527 * usually occurs during the execution of _bind_ but could be delayed 528 * if the call to _bind_ was to a partially wildcard address (involving 529 * ADDR_ANY) and if a specific address needs to be committed at the 530 * time of the call to _listen_ 531 * * Errno::EINPROGRESS - a Windows Sockets 1.1 call is in progress or the 532 * service provider is still processing a callback function 533 * * Errno::EINVAL - the +socket+ has not been bound with a call to _bind_. 534 * * Errno::EISCONN - the +socket+ is already connected 535 * * Errno::EMFILE - no more socket descriptors are available 536 * * Errno::ENOBUFS - no buffer space is available 537 * * Errno::ENOTSOC - +socket+ is not a socket 538 * * Errno::EOPNOTSUPP - the referenced +socket+ is not a type that supports 539 * the _listen_ method 540 * 541 * === See 542 * * listen manual pages on unix-based systems 543 * * listen function in Microsoft's Winsock functions reference 544 */ 545VALUE 546rsock_sock_listen(VALUE sock, VALUE log) 547{ 548 rb_io_t *fptr; 549 int backlog; 550 551 rb_secure(4); 552 backlog = NUM2INT(log); 553 GetOpenFile(sock, fptr); 554 if (listen(fptr->fd, backlog) < 0) 555 rb_sys_fail("listen(2)"); 556 557 return INT2FIX(0); 558} 559 560/* 561 * call-seq: 562 * socket.recvfrom(maxlen) => [mesg, sender_addrinfo] 563 * socket.recvfrom(maxlen, flags) => [mesg, sender_addrinfo] 564 * 565 * Receives up to _maxlen_ bytes from +socket+. _flags_ is zero or more 566 * of the +MSG_+ options. The first element of the results, _mesg_, is the data 567 * received. The second element, _sender_addrinfo_, contains protocol-specific 568 * address information of the sender. 569 * 570 * === Parameters 571 * * +maxlen+ - the maximum number of bytes to receive from the socket 572 * * +flags+ - zero or more of the +MSG_+ options 573 * 574 * === Example 575 * # In one file, start this first 576 * require 'socket' 577 * include Socket::Constants 578 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 579 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 580 * socket.bind( sockaddr ) 581 * socket.listen( 5 ) 582 * client, client_addrinfo = socket.accept 583 * data = client.recvfrom( 20 )[0].chomp 584 * puts "I only received 20 bytes '#{data}'" 585 * sleep 1 586 * socket.close 587 * 588 * # In another file, start this second 589 * require 'socket' 590 * include Socket::Constants 591 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 592 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 593 * socket.connect( sockaddr ) 594 * socket.puts "Watch this get cut short!" 595 * socket.close 596 * 597 * === Unix-based Exceptions 598 * On unix-based based systems the following system exceptions may be raised if the 599 * call to _recvfrom_ fails: 600 * * Errno::EAGAIN - the +socket+ file descriptor is marked as O_NONBLOCK and no 601 * data is waiting to be received; or MSG_OOB is set and no out-of-band data 602 * is available and either the +socket+ file descriptor is marked as 603 * O_NONBLOCK or the +socket+ does not support blocking to wait for 604 * out-of-band-data 605 * * Errno::EWOULDBLOCK - see Errno::EAGAIN 606 * * Errno::EBADF - the +socket+ is not a valid file descriptor 607 * * Errno::ECONNRESET - a connection was forcibly closed by a peer 608 * * Errno::EFAULT - the socket's internal buffer, address or address length 609 * cannot be accessed or written 610 * * Errno::EINTR - a signal interrupted _recvfrom_ before any data was available 611 * * Errno::EINVAL - the MSG_OOB flag is set and no out-of-band data is available 612 * * Errno::EIO - an i/o error occurred while reading from or writing to the 613 * filesystem 614 * * Errno::ENOBUFS - insufficient resources were available in the system to 615 * perform the operation 616 * * Errno::ENOMEM - insufficient memory was available to fulfill the request 617 * * Errno::ENOSR - there were insufficient STREAMS resources available to 618 * complete the operation 619 * * Errno::ENOTCONN - a receive is attempted on a connection-mode socket that 620 * is not connected 621 * * Errno::ENOTSOCK - the +socket+ does not refer to a socket 622 * * Errno::EOPNOTSUPP - the specified flags are not supported for this socket type 623 * * Errno::ETIMEDOUT - the connection timed out during connection establishment 624 * or due to a transmission timeout on an active connection 625 * 626 * === Windows Exceptions 627 * On Windows systems the following system exceptions may be raised if 628 * the call to _recvfrom_ fails: 629 * * Errno::ENETDOWN - the network is down 630 * * Errno::EFAULT - the internal buffer and from parameters on +socket+ are not 631 * part of the user address space, or the internal fromlen parameter is 632 * too small to accommodate the peer address 633 * * Errno::EINTR - the (blocking) call was cancelled by an internal call to 634 * the WinSock function WSACancelBlockingCall 635 * * Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or 636 * the service provider is still processing a callback function 637 * * Errno::EINVAL - +socket+ has not been bound with a call to _bind_, or an 638 * unknown flag was specified, or MSG_OOB was specified for a socket with 639 * SO_OOBINLINE enabled, or (for byte stream-style sockets only) the internal 640 * len parameter on +socket+ was zero or negative 641 * * Errno::EISCONN - +socket+ is already connected. The call to _recvfrom_ is 642 * not permitted with a connected socket on a socket that is connection 643 * oriented or connectionless. 644 * * Errno::ENETRESET - the connection has been broken due to the keep-alive 645 * activity detecting a failure while the operation was in progress. 646 * * Errno::EOPNOTSUPP - MSG_OOB was specified, but +socket+ is not stream-style 647 * such as type SOCK_STREAM. OOB data is not supported in the communication 648 * domain associated with +socket+, or +socket+ is unidirectional and 649 * supports only send operations 650 * * Errno::ESHUTDOWN - +socket+ has been shutdown. It is not possible to 651 * call _recvfrom_ on a socket after _shutdown_ has been invoked. 652 * * Errno::EWOULDBLOCK - +socket+ is marked as nonblocking and a call to 653 * _recvfrom_ would block. 654 * * Errno::EMSGSIZE - the message was too large to fit into the specified buffer 655 * and was truncated. 656 * * Errno::ETIMEDOUT - the connection has been dropped, because of a network 657 * failure or because the system on the other end went down without 658 * notice 659 * * Errno::ECONNRESET - the virtual circuit was reset by the remote side 660 * executing a hard or abortive close. The application should close the 661 * socket; it is no longer usable. On a UDP-datagram socket this error 662 * indicates a previous send operation resulted in an ICMP Port Unreachable 663 * message. 664 */ 665static VALUE 666sock_recvfrom(int argc, VALUE *argv, VALUE sock) 667{ 668 return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET); 669} 670 671/* 672 * call-seq: 673 * socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo] 674 * socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo] 675 * 676 * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after 677 * O_NONBLOCK is set for the underlying file descriptor. 678 * _flags_ is zero or more of the +MSG_+ options. 679 * The first element of the results, _mesg_, is the data received. 680 * The second element, _sender_addrinfo_, contains protocol-specific address 681 * information of the sender. 682 * 683 * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns 684 * an empty string as data. 685 * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc. 686 * 687 * === Parameters 688 * * +maxlen+ - the maximum number of bytes to receive from the socket 689 * * +flags+ - zero or more of the +MSG_+ options 690 * 691 * === Example 692 * # In one file, start this first 693 * require 'socket' 694 * include Socket::Constants 695 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 696 * sockaddr = Socket.sockaddr_in(2200, 'localhost') 697 * socket.bind(sockaddr) 698 * socket.listen(5) 699 * client, client_addrinfo = socket.accept 700 * begin # emulate blocking recvfrom 701 * pair = client.recvfrom_nonblock(20) 702 * rescue IO::WaitReadable 703 * IO.select([client]) 704 * retry 705 * end 706 * data = pair[0].chomp 707 * puts "I only received 20 bytes '#{data}'" 708 * sleep 1 709 * socket.close 710 * 711 * # In another file, start this second 712 * require 'socket' 713 * include Socket::Constants 714 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 715 * sockaddr = Socket.sockaddr_in(2200, 'localhost') 716 * socket.connect(sockaddr) 717 * socket.puts "Watch this get cut short!" 718 * socket.close 719 * 720 * Refer to Socket#recvfrom for the exceptions that may be thrown if the call 721 * to _recvfrom_nonblock_ fails. 722 * 723 * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure, 724 * including Errno::EWOULDBLOCK. 725 * 726 * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN, 727 * it is extended by IO::WaitReadable. 728 * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock. 729 * 730 * === See 731 * * Socket#recvfrom 732 */ 733static VALUE 734sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock) 735{ 736 return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET); 737} 738 739/* 740 * call-seq: 741 * socket.accept => [client_socket, client_addrinfo] 742 * 743 * Accepts a next connection. 744 * Returns a new Socket object and Addrinfo object. 745 * 746 * serv = Socket.new(:INET, :STREAM, 0) 747 * serv.listen(5) 748 * c = Socket.new(:INET, :STREAM, 0) 749 * c.connect(serv.connect_address) 750 * p serv.accept #=> [#<Socket:fd 6>, #<Addrinfo: 127.0.0.1:48555 TCP>] 751 * 752 */ 753static VALUE 754sock_accept(VALUE sock) 755{ 756 rb_io_t *fptr; 757 VALUE sock2; 758 struct sockaddr_storage buf; 759 socklen_t len = (socklen_t)sizeof buf; 760 761 GetOpenFile(sock, fptr); 762 sock2 = rsock_s_accept(rb_cSocket,fptr->fd,(struct sockaddr*)&buf,&len); 763 764 return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len)); 765} 766 767/* 768 * call-seq: 769 * socket.accept_nonblock => [client_socket, client_addrinfo] 770 * 771 * Accepts an incoming connection using accept(2) after 772 * O_NONBLOCK is set for the underlying file descriptor. 773 * It returns an array containing the accepted socket 774 * for the incoming connection, _client_socket_, 775 * and an Addrinfo, _client_addrinfo_. 776 * 777 * === Example 778 * # In one script, start this first 779 * require 'socket' 780 * include Socket::Constants 781 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 782 * sockaddr = Socket.sockaddr_in(2200, 'localhost') 783 * socket.bind(sockaddr) 784 * socket.listen(5) 785 * begin # emulate blocking accept 786 * client_socket, client_addrinfo = socket.accept_nonblock 787 * rescue IO::WaitReadable, Errno::EINTR 788 * IO.select([socket]) 789 * retry 790 * end 791 * puts "The client said, '#{client_socket.readline.chomp}'" 792 * client_socket.puts "Hello from script one!" 793 * socket.close 794 * 795 * # In another script, start this second 796 * require 'socket' 797 * include Socket::Constants 798 * socket = Socket.new(AF_INET, SOCK_STREAM, 0) 799 * sockaddr = Socket.sockaddr_in(2200, 'localhost') 800 * socket.connect(sockaddr) 801 * socket.puts "Hello from script 2." 802 * puts "The server said, '#{socket.readline.chomp}'" 803 * socket.close 804 * 805 * Refer to Socket#accept for the exceptions that may be thrown if the call 806 * to _accept_nonblock_ fails. 807 * 808 * Socket#accept_nonblock may raise any error corresponding to accept(2) failure, 809 * including Errno::EWOULDBLOCK. 810 * 811 * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO, 812 * it is extended by IO::WaitReadable. 813 * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock. 814 * 815 * === See 816 * * Socket#accept 817 */ 818static VALUE 819sock_accept_nonblock(VALUE sock) 820{ 821 rb_io_t *fptr; 822 VALUE sock2; 823 struct sockaddr_storage buf; 824 socklen_t len = (socklen_t)sizeof buf; 825 826 GetOpenFile(sock, fptr); 827 sock2 = rsock_s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)&buf, &len); 828 return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len)); 829} 830 831/* 832 * call-seq: 833 * socket.sysaccept => [client_socket_fd, client_addrinfo] 834 * 835 * Accepts an incoming connection returning an array containing the (integer) 836 * file descriptor for the incoming connection, _client_socket_fd_, 837 * and an Addrinfo, _client_addrinfo_. 838 * 839 * === Example 840 * # In one script, start this first 841 * require 'socket' 842 * include Socket::Constants 843 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 844 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 845 * socket.bind( sockaddr ) 846 * socket.listen( 5 ) 847 * client_fd, client_addrinfo = socket.sysaccept 848 * client_socket = Socket.for_fd( client_fd ) 849 * puts "The client said, '#{client_socket.readline.chomp}'" 850 * client_socket.puts "Hello from script one!" 851 * socket.close 852 * 853 * # In another script, start this second 854 * require 'socket' 855 * include Socket::Constants 856 * socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) 857 * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) 858 * socket.connect( sockaddr ) 859 * socket.puts "Hello from script 2." 860 * puts "The server said, '#{socket.readline.chomp}'" 861 * socket.close 862 * 863 * Refer to Socket#accept for the exceptions that may be thrown if the call 864 * to _sysaccept_ fails. 865 * 866 * === See 867 * * Socket#accept 868 */ 869static VALUE 870sock_sysaccept(VALUE sock) 871{ 872 rb_io_t *fptr; 873 VALUE sock2; 874 struct sockaddr_storage buf; 875 socklen_t len = (socklen_t)sizeof buf; 876 877 GetOpenFile(sock, fptr); 878 sock2 = rsock_s_accept(0,fptr->fd,(struct sockaddr*)&buf,&len); 879 880 return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len)); 881} 882 883#ifdef HAVE_GETHOSTNAME 884/* 885 * call-seq: 886 * Socket.gethostname => hostname 887 * 888 * Returns the hostname. 889 * 890 * p Socket.gethostname #=> "hal" 891 * 892 * Note that it is not guaranteed to be able to convert to IP address using gethostbyname, getaddrinfo, etc. 893 * If you need local IP address, use Socket.ip_address_list. 894 */ 895static VALUE 896sock_gethostname(VALUE obj) 897{ 898#ifndef HOST_NAME_MAX 899# define HOST_NAME_MAX 1024 900#endif 901 char buf[HOST_NAME_MAX+1]; 902 903 rb_secure(3); 904 if (gethostname(buf, (int)sizeof buf - 1) < 0) 905 rb_sys_fail("gethostname"); 906 907 buf[sizeof buf - 1] = '\0'; 908 return rb_str_new2(buf); 909} 910#else 911#ifdef HAVE_UNAME 912 913#include <sys/utsname.h> 914 915static VALUE 916sock_gethostname(VALUE obj) 917{ 918 struct utsname un; 919 920 rb_secure(3); 921 uname(&un); 922 return rb_str_new2(un.nodename); 923} 924#else 925#define sock_gethostname rb_f_notimplement 926#endif 927#endif 928 929static VALUE 930make_addrinfo(struct addrinfo *res0, int norevlookup) 931{ 932 VALUE base, ary; 933 struct addrinfo *res; 934 935 if (res0 == NULL) { 936 rb_raise(rb_eSocket, "host not found"); 937 } 938 base = rb_ary_new(); 939 for (res = res0; res; res = res->ai_next) { 940 ary = rsock_ipaddr(res->ai_addr, norevlookup); 941 if (res->ai_canonname) { 942 RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname); 943 } 944 rb_ary_push(ary, INT2FIX(res->ai_family)); 945 rb_ary_push(ary, INT2FIX(res->ai_socktype)); 946 rb_ary_push(ary, INT2FIX(res->ai_protocol)); 947 rb_ary_push(base, ary); 948 } 949 return base; 950} 951 952static VALUE 953sock_sockaddr(struct sockaddr *addr, size_t len) 954{ 955 char *ptr; 956 957 switch (addr->sa_family) { 958 case AF_INET: 959 ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr; 960 len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr); 961 break; 962#ifdef AF_INET6 963 case AF_INET6: 964 ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr; 965 len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr); 966 break; 967#endif 968 default: 969 rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family); 970 break; 971 } 972 return rb_str_new(ptr, len); 973} 974 975/* 976 * call-seq: 977 * Socket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list] 978 * 979 * Obtains the host information for _hostname_. 980 * 981 * p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"] 982 * 983 */ 984static VALUE 985sock_s_gethostbyname(VALUE obj, VALUE host) 986{ 987 rb_secure(3); 988 return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr); 989} 990 991/* 992 * call-seq: 993 * Socket.gethostbyaddr(address_string [, address_family]) => hostent 994 * 995 * Obtains the host information for _address_. 996 * 997 * p Socket.gethostbyaddr([221,186,184,68].pack("CCCC")) 998 * #=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"] 999 */ 1000static VALUE 1001sock_s_gethostbyaddr(int argc, VALUE *argv) 1002{ 1003 VALUE addr, family; 1004 struct hostent *h; 1005 char **pch; 1006 VALUE ary, names; 1007 int t = AF_INET; 1008 1009 rb_scan_args(argc, argv, "11", &addr, &family); 1010 StringValue(addr); 1011 if (!NIL_P(family)) { 1012 t = rsock_family_arg(family); 1013 } 1014#ifdef AF_INET6 1015 else if (RSTRING_LEN(addr) == 16) { 1016 t = AF_INET6; 1017 } 1018#endif 1019 h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_LENINT(addr), t); 1020 if (h == NULL) { 1021#ifdef HAVE_HSTRERROR 1022 extern int h_errno; 1023 rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno)); 1024#else 1025 rb_raise(rb_eSocket, "host not found"); 1026#endif 1027 } 1028 ary = rb_ary_new(); 1029 rb_ary_push(ary, rb_str_new2(h->h_name)); 1030 names = rb_ary_new(); 1031 rb_ary_push(ary, names); 1032 if (h->h_aliases != NULL) { 1033 for (pch = h->h_aliases; *pch; pch++) { 1034 rb_ary_push(names, rb_str_new2(*pch)); 1035 } 1036 } 1037 rb_ary_push(ary, INT2NUM(h->h_addrtype)); 1038#ifdef h_addr 1039 for (pch = h->h_addr_list; *pch; pch++) { 1040 rb_ary_push(ary, rb_str_new(*pch, h->h_length)); 1041 } 1042#else 1043 rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length)); 1044#endif 1045 1046 return ary; 1047} 1048 1049/* 1050 * call-seq: 1051 * Socket.getservbyname(service_name) => port_number 1052 * Socket.getservbyname(service_name, protocol_name) => port_number 1053 * 1054 * Obtains the port number for _service_name_. 1055 * 1056 * If _protocol_name_ is not given, "tcp" is assumed. 1057 * 1058 * Socket.getservbyname("smtp") #=> 25 1059 * Socket.getservbyname("shell") #=> 514 1060 * Socket.getservbyname("syslog", "udp") #=> 514 1061 */ 1062static VALUE 1063sock_s_getservbyname(int argc, VALUE *argv) 1064{ 1065 VALUE service, proto; 1066 struct servent *sp; 1067 long port; 1068 const char *servicename, *protoname = "tcp"; 1069 1070 rb_scan_args(argc, argv, "11", &service, &proto); 1071 StringValue(service); 1072 if (!NIL_P(proto)) StringValue(proto); 1073 servicename = StringValueCStr(service); 1074 if (!NIL_P(proto)) protoname = StringValueCStr(proto); 1075 sp = getservbyname(servicename, protoname); 1076 if (sp) { 1077 port = ntohs(sp->s_port); 1078 } 1079 else { 1080 char *end; 1081 1082 port = STRTOUL(servicename, &end, 0); 1083 if (*end != '\0') { 1084 rb_raise(rb_eSocket, "no such service %s/%s", servicename, protoname); 1085 } 1086 } 1087 return INT2FIX(port); 1088} 1089 1090/* 1091 * call-seq: 1092 * Socket.getservbyport(port [, protocol_name]) => service 1093 * 1094 * Obtains the port number for _port_. 1095 * 1096 * If _protocol_name_ is not given, "tcp" is assumed. 1097 * 1098 * Socket.getservbyport(80) #=> "www" 1099 * Socket.getservbyport(514, "tcp") #=> "shell" 1100 * Socket.getservbyport(514, "udp") #=> "syslog" 1101 * 1102 */ 1103static VALUE 1104sock_s_getservbyport(int argc, VALUE *argv) 1105{ 1106 VALUE port, proto; 1107 struct servent *sp; 1108 long portnum; 1109 const char *protoname = "tcp"; 1110 1111 rb_scan_args(argc, argv, "11", &port, &proto); 1112 portnum = NUM2LONG(port); 1113 if (portnum != (uint16_t)portnum) { 1114 const char *s = portnum > 0 ? "big" : "small"; 1115 rb_raise(rb_eRangeError, "integer %ld too %s to convert into `int16_t'", portnum, s); 1116 } 1117 if (!NIL_P(proto)) protoname = StringValueCStr(proto); 1118 1119 sp = getservbyport((int)htons((uint16_t)portnum), protoname); 1120 if (!sp) { 1121 rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname); 1122 } 1123 return rb_tainted_str_new2(sp->s_name); 1124} 1125 1126/* 1127 * call-seq: 1128 * Socket.getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags[, reverse_lookup]]]]]) => array 1129 * 1130 * Obtains address information for _nodename_:_servname_. 1131 * 1132 * _family_ should be an address family such as: :INET, :INET6, :UNIX, etc. 1133 * 1134 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc. 1135 * 1136 * _protocol_ should be a protocol defined in the family, 1137 * and defaults to 0 for the family. 1138 * 1139 * _flags_ should be bitwise OR of Socket::AI_* constants. 1140 * 1141 * Socket.getaddrinfo("www.ruby-lang.org", "http", nil, :STREAM) 1142 * #=> [["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68", 2, 1, 6]] # PF_INET/SOCK_STREAM/IPPROTO_TCP 1143 * 1144 * Socket.getaddrinfo("localhost", nil) 1145 * #=> [["AF_INET", 0, "localhost", "127.0.0.1", 2, 1, 6], # PF_INET/SOCK_STREAM/IPPROTO_TCP 1146 * # ["AF_INET", 0, "localhost", "127.0.0.1", 2, 2, 17], # PF_INET/SOCK_DGRAM/IPPROTO_UDP 1147 * # ["AF_INET", 0, "localhost", "127.0.0.1", 2, 3, 0]] # PF_INET/SOCK_RAW/IPPROTO_IP 1148 * 1149 * _reverse_lookup_ directs the form of the third element, and has to 1150 * be one of below. If _reverse_lookup_ is omitted, the default value is +nil+. 1151 * 1152 * +true+, +:hostname+: hostname is obtained from numeric address using reverse lookup, which may take a time. 1153 * +false+, +:numeric+: hostname is same as numeric address. 1154 * +nil+: obey to the current +do_not_reverse_lookup+ flag. 1155 * 1156 * If Addrinfo object is preferred, use Addrinfo.getaddrinfo. 1157 */ 1158static VALUE 1159sock_s_getaddrinfo(int argc, VALUE *argv) 1160{ 1161 VALUE host, port, family, socktype, protocol, flags, ret, revlookup; 1162 struct addrinfo hints, *res; 1163 int norevlookup; 1164 1165 rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup); 1166 1167 MEMZERO(&hints, struct addrinfo, 1); 1168 hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family); 1169 1170 if (!NIL_P(socktype)) { 1171 hints.ai_socktype = rsock_socktype_arg(socktype); 1172 } 1173 if (!NIL_P(protocol)) { 1174 hints.ai_protocol = NUM2INT(protocol); 1175 } 1176 if (!NIL_P(flags)) { 1177 hints.ai_flags = NUM2INT(flags); 1178 } 1179 if (NIL_P(revlookup) || !rsock_revlookup_flag(revlookup, &norevlookup)) { 1180 norevlookup = rsock_do_not_reverse_lookup; 1181 } 1182 res = rsock_getaddrinfo(host, port, &hints, 0); 1183 1184 ret = make_addrinfo(res, norevlookup); 1185 freeaddrinfo(res); 1186 return ret; 1187} 1188 1189/* 1190 * call-seq: 1191 * Socket.getnameinfo(sockaddr [, flags]) => [hostname, servicename] 1192 * 1193 * Obtains name information for _sockaddr_. 1194 * 1195 * _sockaddr_ should be one of follows. 1196 * - packed sockaddr string such as Socket.sockaddr_in(80, "127.0.0.1") 1197 * - 3-elements array such as ["AF_INET", 80, "127.0.0.1"] 1198 * - 4-elements array such as ["AF_INET", 80, ignored, "127.0.0.1"] 1199 * 1200 * _flags_ should be bitwise OR of Socket::NI_* constants. 1201 * 1202 * Note: 1203 * The last form is compatible with IPSocket#addr and IPSocket#peeraddr. 1204 * 1205 * Socket.getnameinfo(Socket.sockaddr_in(80, "127.0.0.1")) #=> ["localhost", "www"] 1206 * Socket.getnameinfo(["AF_INET", 80, "127.0.0.1"]) #=> ["localhost", "www"] 1207 * Socket.getnameinfo(["AF_INET", 80, "localhost", "127.0.0.1"]) #=> ["localhost", "www"] 1208 * 1209 * If Addrinfo object is preferred, use Addrinfo#getnameinfo. 1210 */ 1211static VALUE 1212sock_s_getnameinfo(int argc, VALUE *argv) 1213{ 1214 VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp; 1215 char *hptr, *pptr; 1216 char hbuf[1024], pbuf[1024]; 1217 int fl; 1218 struct addrinfo hints, *res = NULL, *r; 1219 int error; 1220 struct sockaddr_storage ss; 1221 struct sockaddr *sap; 1222 1223 sa = flags = Qnil; 1224 rb_scan_args(argc, argv, "11", &sa, &flags); 1225 1226 fl = 0; 1227 if (!NIL_P(flags)) { 1228 fl = NUM2INT(flags); 1229 } 1230 tmp = rb_check_sockaddr_string_type(sa); 1231 if (!NIL_P(tmp)) { 1232 sa = tmp; 1233 if (sizeof(ss) < (size_t)RSTRING_LEN(sa)) { 1234 rb_raise(rb_eTypeError, "sockaddr length too big"); 1235 } 1236 memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa)); 1237 if ((size_t)RSTRING_LEN(sa) != SS_LEN(&ss)) { 1238 rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); 1239 } 1240 sap = (struct sockaddr*)&ss; 1241 goto call_nameinfo; 1242 } 1243 tmp = rb_check_array_type(sa); 1244 if (!NIL_P(tmp)) { 1245 sa = tmp; 1246 MEMZERO(&hints, struct addrinfo, 1); 1247 if (RARRAY_LEN(sa) == 3) { 1248 af = RARRAY_PTR(sa)[0]; 1249 port = RARRAY_PTR(sa)[1]; 1250 host = RARRAY_PTR(sa)[2]; 1251 } 1252 else if (RARRAY_LEN(sa) >= 4) { 1253 af = RARRAY_PTR(sa)[0]; 1254 port = RARRAY_PTR(sa)[1]; 1255 host = RARRAY_PTR(sa)[3]; 1256 if (NIL_P(host)) { 1257 host = RARRAY_PTR(sa)[2]; 1258 } 1259 else { 1260 /* 1261 * 4th element holds numeric form, don't resolve. 1262 * see rsock_ipaddr(). 1263 */ 1264#ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */ 1265 hints.ai_flags |= AI_NUMERICHOST; 1266#endif 1267 } 1268 } 1269 else { 1270 rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given", 1271 RARRAY_LEN(sa)); 1272 } 1273 /* host */ 1274 if (NIL_P(host)) { 1275 hptr = NULL; 1276 } 1277 else { 1278 strncpy(hbuf, StringValuePtr(host), sizeof(hbuf)); 1279 hbuf[sizeof(hbuf) - 1] = '\0'; 1280 hptr = hbuf; 1281 } 1282 /* port */ 1283 if (NIL_P(port)) { 1284 strcpy(pbuf, "0"); 1285 pptr = NULL; 1286 } 1287 else if (FIXNUM_P(port)) { 1288 snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port)); 1289 pptr = pbuf; 1290 } 1291 else { 1292 strncpy(pbuf, StringValuePtr(port), sizeof(pbuf)); 1293 pbuf[sizeof(pbuf) - 1] = '\0'; 1294 pptr = pbuf; 1295 } 1296 hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM; 1297 /* af */ 1298 hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af); 1299 error = rb_getaddrinfo(hptr, pptr, &hints, &res); 1300 if (error) goto error_exit_addr; 1301 sap = res->ai_addr; 1302 } 1303 else { 1304 rb_raise(rb_eTypeError, "expecting String or Array"); 1305 } 1306 1307 call_nameinfo: 1308 error = rb_getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf), 1309 pbuf, sizeof(pbuf), fl); 1310 if (error) goto error_exit_name; 1311 if (res) { 1312 for (r = res->ai_next; r; r = r->ai_next) { 1313 char hbuf2[1024], pbuf2[1024]; 1314 1315 sap = r->ai_addr; 1316 error = rb_getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2), 1317 pbuf2, sizeof(pbuf2), fl); 1318 if (error) goto error_exit_name; 1319 if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) { 1320 freeaddrinfo(res); 1321 rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename"); 1322 } 1323 } 1324 freeaddrinfo(res); 1325 } 1326 return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf)); 1327 1328 error_exit_addr: 1329 if (res) freeaddrinfo(res); 1330 rsock_raise_socket_error("getaddrinfo", error); 1331 1332 error_exit_name: 1333 if (res) freeaddrinfo(res); 1334 rsock_raise_socket_error("getnameinfo", error); 1335 1336 UNREACHABLE; 1337} 1338 1339/* 1340 * call-seq: 1341 * Socket.sockaddr_in(port, host) => sockaddr 1342 * Socket.pack_sockaddr_in(port, host) => sockaddr 1343 * 1344 * Packs _port_ and _host_ as an AF_INET/AF_INET6 sockaddr string. 1345 * 1346 * Socket.sockaddr_in(80, "127.0.0.1") 1347 * #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" 1348 * 1349 * Socket.sockaddr_in(80, "::1") 1350 * #=> "\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" 1351 * 1352 */ 1353static VALUE 1354sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host) 1355{ 1356 struct addrinfo *res = rsock_addrinfo(host, port, 0, 0); 1357 VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen); 1358 1359 freeaddrinfo(res); 1360 OBJ_INFECT(addr, port); 1361 OBJ_INFECT(addr, host); 1362 1363 return addr; 1364} 1365 1366/* 1367 * call-seq: 1368 * Socket.unpack_sockaddr_in(sockaddr) => [port, ip_address] 1369 * 1370 * Unpacks _sockaddr_ into port and ip_address. 1371 * 1372 * _sockaddr_ should be a string or an addrinfo for AF_INET/AF_INET6. 1373 * 1374 * sockaddr = Socket.sockaddr_in(80, "127.0.0.1") 1375 * p sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" 1376 * p Socket.unpack_sockaddr_in(sockaddr) #=> [80, "127.0.0.1"] 1377 * 1378 */ 1379static VALUE 1380sock_s_unpack_sockaddr_in(VALUE self, VALUE addr) 1381{ 1382 struct sockaddr_in * sockaddr; 1383 VALUE host; 1384 1385 sockaddr = (struct sockaddr_in*)SockAddrStringValuePtr(addr); 1386 if (RSTRING_LEN(addr) < 1387 (char*)&((struct sockaddr *)sockaddr)->sa_family + 1388 sizeof(((struct sockaddr *)sockaddr)->sa_family) - 1389 (char*)sockaddr) 1390 rb_raise(rb_eArgError, "too short sockaddr"); 1391 if (((struct sockaddr *)sockaddr)->sa_family != AF_INET 1392#ifdef INET6 1393 && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6 1394#endif 1395 ) { 1396#ifdef INET6 1397 rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr"); 1398#else 1399 rb_raise(rb_eArgError, "not an AF_INET sockaddr"); 1400#endif 1401 } 1402 host = rsock_make_ipaddr((struct sockaddr*)sockaddr); 1403 OBJ_INFECT(host, addr); 1404 return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host); 1405} 1406 1407#ifdef HAVE_SYS_UN_H 1408 1409/* 1410 * call-seq: 1411 * Socket.sockaddr_un(path) => sockaddr 1412 * Socket.pack_sockaddr_un(path) => sockaddr 1413 * 1414 * Packs _path_ as an AF_UNIX sockaddr string. 1415 * 1416 * Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..." 1417 * 1418 */ 1419static VALUE 1420sock_s_pack_sockaddr_un(VALUE self, VALUE path) 1421{ 1422 struct sockaddr_un sockaddr; 1423 VALUE addr; 1424 1425 StringValue(path); 1426 MEMZERO(&sockaddr, struct sockaddr_un, 1); 1427 sockaddr.sun_family = AF_UNIX; 1428 if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) { 1429 rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)", 1430 (size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path)); 1431 } 1432 memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path)); 1433 addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path)); 1434 OBJ_INFECT(addr, path); 1435 1436 return addr; 1437} 1438 1439/* 1440 * call-seq: 1441 * Socket.unpack_sockaddr_un(sockaddr) => path 1442 * 1443 * Unpacks _sockaddr_ into path. 1444 * 1445 * _sockaddr_ should be a string or an addrinfo for AF_UNIX. 1446 * 1447 * sockaddr = Socket.sockaddr_un("/tmp/sock") 1448 * p Socket.unpack_sockaddr_un(sockaddr) #=> "/tmp/sock" 1449 * 1450 */ 1451static VALUE 1452sock_s_unpack_sockaddr_un(VALUE self, VALUE addr) 1453{ 1454 struct sockaddr_un * sockaddr; 1455 VALUE path; 1456 1457 sockaddr = (struct sockaddr_un*)SockAddrStringValuePtr(addr); 1458 if (RSTRING_LEN(addr) < 1459 (char*)&((struct sockaddr *)sockaddr)->sa_family + 1460 sizeof(((struct sockaddr *)sockaddr)->sa_family) - 1461 (char*)sockaddr) 1462 rb_raise(rb_eArgError, "too short sockaddr"); 1463 if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) { 1464 rb_raise(rb_eArgError, "not an AF_UNIX sockaddr"); 1465 } 1466 if (sizeof(struct sockaddr_un) < (size_t)RSTRING_LEN(addr)) { 1467 rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d", 1468 RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un)); 1469 } 1470 path = rsock_unixpath_str(sockaddr, RSTRING_LENINT(addr)); 1471 OBJ_INFECT(path, addr); 1472 return path; 1473} 1474#endif 1475 1476#if defined(HAVE_GETIFADDRS) || defined(SIOCGLIFCONF) || defined(SIOCGIFCONF) || defined(_WIN32) 1477static VALUE 1478sockaddr_obj(struct sockaddr *addr) 1479{ 1480 socklen_t len; 1481#if defined(AF_INET6) && defined(__KAME__) 1482 struct sockaddr_in6 addr6; 1483#endif 1484 1485 if (addr == NULL) 1486 return Qnil; 1487 1488 switch (addr->sa_family) { 1489 case AF_INET: 1490 len = (socklen_t)sizeof(struct sockaddr_in); 1491 break; 1492 1493#ifdef AF_INET6 1494 case AF_INET6: 1495 len = (socklen_t)sizeof(struct sockaddr_in6); 1496# ifdef __KAME__ 1497 /* KAME uses the 2nd 16bit word of link local IPv6 address as interface index internally */ 1498 /* http://orange.kame.net/dev/cvsweb.cgi/kame/IMPLEMENTATION */ 1499 /* convert fe80:1::1 to fe80::1%1 */ 1500 memcpy(&addr6, addr, len); 1501 addr = (struct sockaddr *)&addr6; 1502 if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) && 1503 addr6.sin6_scope_id == 0 && 1504 (addr6.sin6_addr.s6_addr[2] || addr6.sin6_addr.s6_addr[3])) { 1505 addr6.sin6_scope_id = (addr6.sin6_addr.s6_addr[2] << 8) | addr6.sin6_addr.s6_addr[3]; 1506 addr6.sin6_addr.s6_addr[2] = 0; 1507 addr6.sin6_addr.s6_addr[3] = 0; 1508 } 1509# endif 1510 break; 1511#endif 1512 1513#ifdef HAVE_SYS_UN_H 1514 case AF_UNIX: 1515 len = (socklen_t)sizeof(struct sockaddr_un); 1516 break; 1517#endif 1518 1519 default: 1520 len = (socklen_t)sizeof(struct sockaddr_in); 1521 break; 1522 } 1523#ifdef SA_LEN 1524 if (len < (socklen_t)SA_LEN(addr)) 1525 len = (socklen_t)SA_LEN(addr); 1526#endif 1527 1528 return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil); 1529} 1530#endif 1531 1532#if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) || defined(_WIN32) 1533/* 1534 * call-seq: 1535 * Socket.ip_address_list => array 1536 * 1537 * Returns local IP addresses as an array. 1538 * 1539 * The array contains Addrinfo objects. 1540 * 1541 * pp Socket.ip_address_list 1542 * #=> [#<Addrinfo: 127.0.0.1>, 1543 * #<Addrinfo: 192.168.0.128>, 1544 * #<Addrinfo: ::1>, 1545 * ...] 1546 * 1547 */ 1548static VALUE 1549socket_s_ip_address_list(VALUE self) 1550{ 1551#if defined(HAVE_GETIFADDRS) 1552 struct ifaddrs *ifp = NULL; 1553 struct ifaddrs *p; 1554 int ret; 1555 VALUE list; 1556 1557 ret = getifaddrs(&ifp); 1558 if (ret == -1) { 1559 rb_sys_fail("getifaddrs"); 1560 } 1561 1562 list = rb_ary_new(); 1563 for (p = ifp; p; p = p->ifa_next) { 1564 if (p->ifa_addr != NULL && IS_IP_FAMILY(p->ifa_addr->sa_family)) { 1565 rb_ary_push(list, sockaddr_obj(p->ifa_addr)); 1566 } 1567 } 1568 1569 freeifaddrs(ifp); 1570 1571 return list; 1572#elif defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux) 1573 /* Solaris if_tcp(7P) */ 1574 /* HP-UX has SIOCGLIFCONF too. But it uses different struct */ 1575 int fd = -1; 1576 int ret; 1577 struct lifnum ln; 1578 struct lifconf lc; 1579 char *reason = NULL; 1580 int save_errno; 1581 int i; 1582 VALUE list = Qnil; 1583 1584 lc.lifc_buf = NULL; 1585 1586 fd = socket(AF_INET, SOCK_DGRAM, 0); 1587 if (fd == -1) 1588 rb_sys_fail("socket"); 1589 1590 memset(&ln, 0, sizeof(ln)); 1591 ln.lifn_family = AF_UNSPEC; 1592 1593 ret = ioctl(fd, SIOCGLIFNUM, &ln); 1594 if (ret == -1) { 1595 reason = "SIOCGLIFNUM"; 1596 goto finish; 1597 } 1598 1599 memset(&lc, 0, sizeof(lc)); 1600 lc.lifc_family = AF_UNSPEC; 1601 lc.lifc_flags = 0; 1602 lc.lifc_len = sizeof(struct lifreq) * ln.lifn_count; 1603 lc.lifc_req = xmalloc(lc.lifc_len); 1604 1605 ret = ioctl(fd, SIOCGLIFCONF, &lc); 1606 if (ret == -1) { 1607 reason = "SIOCGLIFCONF"; 1608 goto finish; 1609 } 1610 1611 list = rb_ary_new(); 1612 for (i = 0; i < ln.lifn_count; i++) { 1613 struct lifreq *req = &lc.lifc_req[i]; 1614 if (IS_IP_FAMILY(req->lifr_addr.ss_family)) { 1615 if (req->lifr_addr.ss_family == AF_INET6 && 1616 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_addr) && 1617 ((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id == 0) { 1618 struct lifreq req2; 1619 memcpy(req2.lifr_name, req->lifr_name, LIFNAMSIZ); 1620 ret = ioctl(fd, SIOCGLIFINDEX, &req2); 1621 if (ret == -1) { 1622 reason = "SIOCGLIFINDEX"; 1623 goto finish; 1624 } 1625 ((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id = req2.lifr_index; 1626 } 1627 rb_ary_push(list, sockaddr_obj((struct sockaddr *)&req->lifr_addr)); 1628 } 1629 } 1630 1631 finish: 1632 save_errno = errno; 1633 if (lc.lifc_buf != NULL) 1634 xfree(lc.lifc_req); 1635 if (fd != -1) 1636 close(fd); 1637 errno = save_errno; 1638 1639 if (reason) 1640 rb_sys_fail(reason); 1641 return list; 1642 1643#elif defined(SIOCGIFCONF) 1644 int fd = -1; 1645 int ret; 1646#define EXTRA_SPACE (sizeof(struct ifconf) + sizeof(struct sockaddr_storage)) 1647 char initbuf[4096+EXTRA_SPACE]; 1648 char *buf = initbuf; 1649 int bufsize; 1650 struct ifconf conf; 1651 struct ifreq *req; 1652 VALUE list = Qnil; 1653 const char *reason = NULL; 1654 int save_errno; 1655 1656 fd = socket(AF_INET, SOCK_DGRAM, 0); 1657 if (fd == -1) 1658 rb_sys_fail("socket"); 1659 1660 bufsize = sizeof(initbuf); 1661 buf = initbuf; 1662 1663 retry: 1664 conf.ifc_len = bufsize; 1665 conf.ifc_req = (struct ifreq *)buf; 1666 1667 /* fprintf(stderr, "bufsize: %d\n", bufsize); */ 1668 1669 ret = ioctl(fd, SIOCGIFCONF, &conf); 1670 if (ret == -1) { 1671 reason = "SIOCGIFCONF"; 1672 goto finish; 1673 } 1674 1675 /* fprintf(stderr, "conf.ifc_len: %d\n", conf.ifc_len); */ 1676 1677 if (bufsize - EXTRA_SPACE < conf.ifc_len) { 1678 if (bufsize < conf.ifc_len) { 1679 /* NetBSD returns required size for all interfaces. */ 1680 bufsize = conf.ifc_len + EXTRA_SPACE; 1681 } 1682 else { 1683 bufsize = bufsize << 1; 1684 } 1685 if (buf == initbuf) 1686 buf = NULL; 1687 buf = xrealloc(buf, bufsize); 1688 goto retry; 1689 } 1690 1691 close(fd); 1692 fd = -1; 1693 1694 list = rb_ary_new(); 1695 req = conf.ifc_req; 1696 while ((char*)req < (char*)conf.ifc_req + conf.ifc_len) { 1697 struct sockaddr *addr = &req->ifr_addr; 1698 if (IS_IP_FAMILY(addr->sa_family)) { 1699 rb_ary_push(list, sockaddr_obj(addr)); 1700 } 1701#ifdef HAVE_SA_LEN 1702# ifndef _SIZEOF_ADDR_IFREQ 1703# define _SIZEOF_ADDR_IFREQ(r) \ 1704 (sizeof(struct ifreq) + \ 1705 (sizeof(struct sockaddr) < (r).ifr_addr.sa_len ? \ 1706 (r).ifr_addr.sa_len - sizeof(struct sockaddr) : \ 1707 0)) 1708# endif 1709 req = (struct ifreq *)((char*)req + _SIZEOF_ADDR_IFREQ(*req)); 1710#else 1711 req = (struct ifreq *)((char*)req + sizeof(struct ifreq)); 1712#endif 1713 } 1714 1715 finish: 1716 1717 save_errno = errno; 1718 if (buf != initbuf) 1719 xfree(buf); 1720 if (fd != -1) 1721 close(fd); 1722 errno = save_errno; 1723 1724 if (reason) 1725 rb_sys_fail(reason); 1726 return list; 1727 1728#undef EXTRA_SPACE 1729#elif defined(_WIN32) 1730 typedef struct ip_adapter_unicast_address_st { 1731 unsigned LONG_LONG dummy0; 1732 struct ip_adapter_unicast_address_st *Next; 1733 struct { 1734 struct sockaddr *lpSockaddr; 1735 int iSockaddrLength; 1736 } Address; 1737 int dummy1; 1738 int dummy2; 1739 int dummy3; 1740 long dummy4; 1741 long dummy5; 1742 long dummy6; 1743 } ip_adapter_unicast_address_t; 1744 typedef struct ip_adapter_anycast_address_st { 1745 unsigned LONG_LONG dummy0; 1746 struct ip_adapter_anycast_address_st *Next; 1747 struct { 1748 struct sockaddr *lpSockaddr; 1749 int iSockaddrLength; 1750 } Address; 1751 } ip_adapter_anycast_address_t; 1752 typedef struct ip_adapter_addresses_st { 1753 unsigned LONG_LONG dummy0; 1754 struct ip_adapter_addresses_st *Next; 1755 void *dummy1; 1756 ip_adapter_unicast_address_t *FirstUnicastAddress; 1757 ip_adapter_anycast_address_t *FirstAnycastAddress; 1758 void *dummy2; 1759 void *dummy3; 1760 void *dummy4; 1761 void *dummy5; 1762 void *dummy6; 1763 BYTE dummy7[8]; 1764 DWORD dummy8; 1765 DWORD dummy9; 1766 DWORD dummy10; 1767 DWORD IfType; 1768 int OperStatus; 1769 DWORD dummy12; 1770 DWORD dummy13[16]; 1771 void *dummy14; 1772 } ip_adapter_addresses_t; 1773 typedef ULONG (WINAPI *GetAdaptersAddresses_t)(ULONG, ULONG, PVOID, ip_adapter_addresses_t *, PULONG); 1774 HMODULE h; 1775 GetAdaptersAddresses_t pGetAdaptersAddresses; 1776 ULONG len; 1777 DWORD ret; 1778 ip_adapter_addresses_t *adapters; 1779 VALUE list; 1780 1781 h = LoadLibrary("iphlpapi.dll"); 1782 if (!h) 1783 rb_notimplement(); 1784 pGetAdaptersAddresses = (GetAdaptersAddresses_t)GetProcAddress(h, "GetAdaptersAddresses"); 1785 if (!pGetAdaptersAddresses) { 1786 FreeLibrary(h); 1787 rb_notimplement(); 1788 } 1789 1790 ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &len); 1791 if (ret != ERROR_SUCCESS && ret != ERROR_BUFFER_OVERFLOW) { 1792 errno = rb_w32_map_errno(ret); 1793 FreeLibrary(h); 1794 rb_sys_fail("GetAdaptersAddresses"); 1795 } 1796 adapters = (ip_adapter_addresses_t *)ALLOCA_N(BYTE, len); 1797 ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &len); 1798 if (ret != ERROR_SUCCESS) { 1799 errno = rb_w32_map_errno(ret); 1800 FreeLibrary(h); 1801 rb_sys_fail("GetAdaptersAddresses"); 1802 } 1803 1804 list = rb_ary_new(); 1805 for (; adapters; adapters = adapters->Next) { 1806 ip_adapter_unicast_address_t *uni; 1807 ip_adapter_anycast_address_t *any; 1808 if (adapters->OperStatus != 1) /* 1 means IfOperStatusUp */ 1809 continue; 1810 for (uni = adapters->FirstUnicastAddress; uni; uni = uni->Next) { 1811#ifndef INET6 1812 if (uni->Address.lpSockaddr->sa_family == AF_INET) 1813#else 1814 if (IS_IP_FAMILY(uni->Address.lpSockaddr->sa_family)) 1815#endif 1816 rb_ary_push(list, sockaddr_obj(uni->Address.lpSockaddr)); 1817 } 1818 for (any = adapters->FirstAnycastAddress; any; any = any->Next) { 1819#ifndef INET6 1820 if (any->Address.lpSockaddr->sa_family == AF_INET) 1821#else 1822 if (IS_IP_FAMILY(any->Address.lpSockaddr->sa_family)) 1823#endif 1824 rb_ary_push(list, sockaddr_obj(any->Address.lpSockaddr)); 1825 } 1826 } 1827 1828 FreeLibrary(h); 1829 return list; 1830#endif 1831} 1832#else 1833#define socket_s_ip_address_list rb_f_notimplement 1834#endif 1835 1836void 1837Init_socket() 1838{ 1839 rsock_init_basicsocket(); 1840 1841 /* 1842 * Document-class: Socket < BasicSocket 1843 * 1844 * Class +Socket+ provides access to the underlying operating system 1845 * socket implementations. It can be used to provide more operating system 1846 * specific functionality than the protocol-specific socket classes. 1847 * 1848 * The constants defined under Socket::Constants are also defined under 1849 * Socket. For example, Socket::AF_INET is usable as well as 1850 * Socket::Constants::AF_INET. See Socket::Constants for the list of 1851 * constants. 1852 * 1853 * === What's a socket? 1854 * 1855 * Sockets are endpoints of a bidirectionnal communication channel. 1856 * Sockets can communicate within a process, between processes on the same 1857 * machine or between different machines. There are many types of socket: 1858 * TCPSocket, UDPSocket or UNIXSocket for example. 1859 * 1860 * Sockets have their own vocabulary: 1861 * 1862 * *domain:* 1863 * The family of protocols: 1864 * * Socket::PF_INET 1865 * * Socket::PF_INET6 1866 * * Socket::PF_UNIX 1867 * * etc. 1868 * 1869 * *type:* 1870 * The type of communications between the two endpoints, typically 1871 * * Socket::SOCK_STREAM 1872 * * Socket::SOCK_DGRAM. 1873 * 1874 * *protocol:* 1875 * Typically _zero_. 1876 * This may be used to identify a variant of a protocol. 1877 * 1878 * *hostname:* 1879 * The identifier of a network interface: 1880 * * a string (hostname, IPv4 or IPv6 adress or +broadcast+ 1881 * which specifies a broadcast address) 1882 * * a zero-length string which specifies INADDR_ANY 1883 * * an integer (interpreted as binary address in host byte order). 1884 * 1885 * === Quick start 1886 * 1887 * Many of the classes, such as TCPSocket, UDPSocket or UNIXSocket, 1888 * ease the use of sockets comparatively to the equivalent C programming interface. 1889 * 1890 * Let's create an internet socket using the IPv4 protocol in a C-like manner: 1891 * 1892 * s = Socket.new Socket::AF_INET, Socket::SOCK_STREAM 1893 * s.connect Socket.pack_sockaddr_in(80, 'example.com') 1894 * 1895 * You could also use the TCPSocket class: 1896 * 1897 * s = TCPSocket.new 'example.com', 80 1898 * 1899 * A simple server might look like this: 1900 * 1901 * require 'socket' 1902 * 1903 * server = TCPServer.new 2000 # Server bound to port 2000 1904 * 1905 * loop do 1906 * client = server.accept # Wait for a client to connect 1907 * client.puts "Hello !" 1908 * client.puts "Time is #{Time.now}" 1909 * client.close 1910 * end 1911 * 1912 * A simple client may look like this: 1913 * 1914 * require 'socket' 1915 * 1916 * s = TCPSocket.new 'localhost', 2000 1917 * 1918 * while line = s.gets # Read lines from socket 1919 * puts line # and print them 1920 * end 1921 * 1922 * s.close # close socket when done 1923 * 1924 * === Exception Handling 1925 * 1926 * Ruby's Socket implementation raises exceptions based on the error 1927 * generated by the system dependent implementation. This is why the 1928 * methods are documented in a way that isolate Unix-based system 1929 * exceptions from Windows based exceptions. If more information on a 1930 * particular exception is needed, please refer to the Unix manual pages or 1931 * the Windows WinSock reference. 1932 * 1933 * === Convenience methods 1934 * 1935 * Although the general way to create socket is Socket.new, 1936 * there are several methods of socket creation for most cases. 1937 * 1938 * TCP client socket:: 1939 * Socket.tcp, TCPSocket.open 1940 * TCP server socket:: 1941 * Socket.tcp_server_loop, TCPServer.open 1942 * UNIX client socket:: 1943 * Socket.unix, UNIXSocket.open 1944 * UNIX server socket:: 1945 * Socket.unix_server_loop, UNIXServer.open 1946 * 1947 * === Documentation by 1948 * 1949 * * Zach Dennis 1950 * * Sam Roberts 1951 * * <em>Programming Ruby</em> from The Pragmatic Bookshelf. 1952 * 1953 * Much material in this documentation is taken with permission from 1954 * <em>Programming Ruby</em> from The Pragmatic Bookshelf. 1955 */ 1956 rb_cSocket = rb_define_class("Socket", rb_cBasicSocket); 1957 1958 rsock_init_socket_init(); 1959 1960 rb_define_method(rb_cSocket, "initialize", sock_initialize, -1); 1961 rb_define_method(rb_cSocket, "connect", sock_connect, 1); 1962 rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, 1); 1963 rb_define_method(rb_cSocket, "bind", sock_bind, 1); 1964 rb_define_method(rb_cSocket, "listen", rsock_sock_listen, 1); 1965 rb_define_method(rb_cSocket, "accept", sock_accept, 0); 1966 rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, 0); 1967 rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0); 1968 1969 rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1); 1970 rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1); 1971 1972 rb_define_singleton_method(rb_cSocket, "socketpair", rsock_sock_s_socketpair, -1); 1973 rb_define_singleton_method(rb_cSocket, "pair", rsock_sock_s_socketpair, -1); 1974 rb_define_singleton_method(rb_cSocket, "gethostname", sock_gethostname, 0); 1975 rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1); 1976 rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1); 1977 rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyname, -1); 1978 rb_define_singleton_method(rb_cSocket, "getservbyport", sock_s_getservbyport, -1); 1979 rb_define_singleton_method(rb_cSocket, "getaddrinfo", sock_s_getaddrinfo, -1); 1980 rb_define_singleton_method(rb_cSocket, "getnameinfo", sock_s_getnameinfo, -1); 1981 rb_define_singleton_method(rb_cSocket, "sockaddr_in", sock_s_pack_sockaddr_in, 2); 1982 rb_define_singleton_method(rb_cSocket, "pack_sockaddr_in", sock_s_pack_sockaddr_in, 2); 1983 rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_in", sock_s_unpack_sockaddr_in, 1); 1984#ifdef HAVE_SYS_UN_H 1985 rb_define_singleton_method(rb_cSocket, "sockaddr_un", sock_s_pack_sockaddr_un, 1); 1986 rb_define_singleton_method(rb_cSocket, "pack_sockaddr_un", sock_s_pack_sockaddr_un, 1); 1987 rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_un", sock_s_unpack_sockaddr_un, 1); 1988#endif 1989 1990 rb_define_singleton_method(rb_cSocket, "ip_address_list", socket_s_ip_address_list, 0); 1991} 1992