PageRenderTime 66ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/socket/socket.c

https://github.com/fizx/ruby
C | 1844 lines | 887 code | 126 blank | 831 comment | 163 complexity | 29600a8e4802948b882fd1a85f814533 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0, GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /************************************************
  2. socket.c -
  3. created at: Thu Mar 31 12:21:29 JST 1994
  4. Copyright (C) 1993-2007 Yukihiro Matsumoto
  5. ************************************************/
  6. #include "rubysocket.h"
  7. static void
  8. setup_domain_and_type(VALUE domain, int *dv, VALUE type, int *tv)
  9. {
  10. *dv = rsock_family_arg(domain);
  11. *tv = rsock_socktype_arg(type);
  12. }
  13. /*
  14. * call-seq:
  15. * Socket.new(domain, socktype [, protocol]) => socket
  16. *
  17. * Creates a new socket object.
  18. *
  19. * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc.
  20. *
  21. * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
  22. *
  23. * _protocol_ should be a protocol defined in the domain.
  24. * This is optional.
  25. * If it is not given, 0 is used internally.
  26. *
  27. * Socket.new(:INET, :STREAM) # TCP socket
  28. * Socket.new(:INET, :DGRAM) # UDP socket
  29. * Socket.new(:UNIX, :STREAM) # UNIX stream socket
  30. * Socket.new(:UNIX, :DGRAM) # UNIX datagram socket
  31. */
  32. static VALUE
  33. sock_initialize(int argc, VALUE *argv, VALUE sock)
  34. {
  35. VALUE domain, type, protocol;
  36. int fd;
  37. int d, t;
  38. rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
  39. if (NIL_P(protocol))
  40. protocol = INT2FIX(0);
  41. rb_secure(3);
  42. setup_domain_and_type(domain, &d, type, &t);
  43. fd = rsock_socket(d, t, NUM2INT(protocol));
  44. if (fd < 0) rb_sys_fail("socket(2)");
  45. return rsock_init_sock(sock, fd);
  46. }
  47. #if defined HAVE_SOCKETPAIR
  48. static VALUE
  49. io_call_close(VALUE io)
  50. {
  51. return rb_funcall(io, rb_intern("close"), 0, 0);
  52. }
  53. static VALUE
  54. io_close(VALUE io)
  55. {
  56. return rb_rescue(io_call_close, io, 0, 0);
  57. }
  58. static VALUE
  59. pair_yield(VALUE pair)
  60. {
  61. return rb_ensure(rb_yield, pair, io_close, rb_ary_entry(pair, 1));
  62. }
  63. #endif
  64. #if defined HAVE_SOCKETPAIR
  65. /*
  66. * call-seq:
  67. * Socket.pair(domain, type, protocol) => [socket1, socket2]
  68. * Socket.socketpair(domain, type, protocol) => [socket1, socket2]
  69. *
  70. * Creates a pair of sockets connected each other.
  71. *
  72. * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc.
  73. *
  74. * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
  75. *
  76. * _protocol_ should be a protocol defined in the domain.
  77. * 0 is default protocol for the domain.
  78. *
  79. * s1, s2 = Socket.pair(:UNIX, :DGRAM, 0)
  80. * s1.send "a", 0
  81. * s1.send "b", 0
  82. * p s2.recv(10) #=> "a"
  83. * p s2.recv(10) #=> "b"
  84. *
  85. */
  86. VALUE
  87. rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
  88. {
  89. VALUE domain, type, protocol;
  90. int d, t, p, sp[2];
  91. int ret;
  92. VALUE s1, s2, r;
  93. rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
  94. if (NIL_P(protocol))
  95. protocol = INT2FIX(0);
  96. setup_domain_and_type(domain, &d, type, &t);
  97. p = NUM2INT(protocol);
  98. ret = socketpair(d, t, p, sp);
  99. if (ret < 0 && (errno == EMFILE || errno == ENFILE)) {
  100. rb_gc();
  101. ret = socketpair(d, t, p, sp);
  102. }
  103. if (ret < 0) {
  104. rb_sys_fail("socketpair(2)");
  105. }
  106. s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
  107. s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
  108. r = rb_assoc_new(s1, s2);
  109. if (rb_block_given_p()) {
  110. return rb_ensure(pair_yield, r, io_close, s1);
  111. }
  112. return r;
  113. }
  114. #else
  115. #define rsock_sock_s_socketpair rb_f_notimplement
  116. #endif
  117. /*
  118. * call-seq:
  119. * socket.connect(server_sockaddr) => 0
  120. *
  121. * Requests a connection to be made on the given +server_sockaddr+. Returns 0 if
  122. * successful, otherwise an exception is raised.
  123. *
  124. * === Parameter
  125. * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
  126. *
  127. * === Example:
  128. * # Pull down Google's web page
  129. * require 'socket'
  130. * include Socket::Constants
  131. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  132. * sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
  133. * socket.connect( sockaddr )
  134. * socket.write( "GET / HTTP/1.0\r\n\r\n" )
  135. * results = socket.read
  136. *
  137. * === Unix-based Exceptions
  138. * On unix-based systems the following system exceptions may be raised if
  139. * the call to _connect_ fails:
  140. * * Errno::EACCES - search permission is denied for a component of the prefix
  141. * path or write access to the +socket+ is denied
  142. * * Errno::EADDRINUSE - the _sockaddr_ is already in use
  143. * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the
  144. * local machine
  145. * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for
  146. * the address family of the specified +socket+
  147. * * Errno::EALREADY - a connection is already in progress for the specified
  148. * socket
  149. * * Errno::EBADF - the +socket+ is not a valid file descriptor
  150. * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections
  151. * refused the connection request
  152. * * Errno::ECONNRESET - the remote host reset the connection request
  153. * * Errno::EFAULT - the _sockaddr_ cannot be accessed
  154. * * Errno::EHOSTUNREACH - the destination host cannot be reached (probably
  155. * because the host is down or a remote router cannot reach it)
  156. * * Errno::EINPROGRESS - the O_NONBLOCK is set for the +socket+ and the
  157. * connection cannot be immediately established; the connection will be
  158. * established asynchronously
  159. * * Errno::EINTR - the attempt to establish the connection was interrupted by
  160. * delivery of a signal that was caught; the connection will be established
  161. * asynchronously
  162. * * Errno::EISCONN - the specified +socket+ is already connected
  163. * * Errno::EINVAL - the address length used for the _sockaddr_ is not a valid
  164. * length for the address family or there is an invalid family in _sockaddr_
  165. * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
  166. * PATH_MAX
  167. * * Errno::ENETDOWN - the local interface used to reach the destination is down
  168. * * Errno::ENETUNREACH - no route to the network is present
  169. * * Errno::ENOBUFS - no buffer space is available
  170. * * Errno::ENOSR - there were insufficient STREAMS resources available to
  171. * complete the operation
  172. * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
  173. * * Errno::EOPNOTSUPP - the calling +socket+ is listening and cannot be connected
  174. * * Errno::EPROTOTYPE - the _sockaddr_ has a different type than the socket
  175. * bound to the specified peer address
  176. * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
  177. * was made.
  178. *
  179. * On unix-based systems if the address family of the calling +socket+ is
  180. * AF_UNIX the follow exceptions may be raised if the call to _connect_
  181. * fails:
  182. * * Errno::EIO - an i/o error occurred while reading from or writing to the
  183. * file system
  184. * * Errno::ELOOP - too many symbolic links were encountered in translating
  185. * the pathname in _sockaddr_
  186. * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX
  187. * characters, or an entire pathname exceeded PATH_MAX characters
  188. * * Errno::ENOENT - a component of the pathname does not name an existing file
  189. * or the pathname is an empty string
  190. * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_
  191. * is not a directory
  192. *
  193. * === Windows Exceptions
  194. * On Windows systems the following system exceptions may be raised if
  195. * the call to _connect_ fails:
  196. * * Errno::ENETDOWN - the network is down
  197. * * Errno::EADDRINUSE - the socket's local address is already in use
  198. * * Errno::EINTR - the socket was cancelled
  199. * * Errno::EINPROGRESS - a blocking socket is in progress or the service provider
  200. * is still processing a callback function. Or a nonblocking connect call is
  201. * in progress on the +socket+.
  202. * * Errno::EALREADY - see Errno::EINVAL
  203. * * Errno::EADDRNOTAVAIL - the remote address is not a valid address, such as
  204. * ADDR_ANY TODO check ADDRANY TO INADDR_ANY
  205. * * Errno::EAFNOSUPPORT - addresses in the specified family cannot be used with
  206. * with this +socket+
  207. * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections
  208. * refused the connection request
  209. * * Errno::EFAULT - the socket's internal address or address length parameter
  210. * is too small or is not a valid part of the user space address
  211. * * Errno::EINVAL - the +socket+ is a listening socket
  212. * * Errno::EISCONN - the +socket+ is already connected
  213. * * Errno::ENETUNREACH - the network cannot be reached from this host at this time
  214. * * Errno::EHOSTUNREACH - no route to the network is present
  215. * * Errno::ENOBUFS - no buffer space is available
  216. * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
  217. * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
  218. * was made.
  219. * * Errno::EWOULDBLOCK - the socket is marked as nonblocking and the
  220. * connection cannot be completed immediately
  221. * * Errno::EACCES - the attempt to connect the datagram socket to the
  222. * broadcast address failed
  223. *
  224. * === See
  225. * * connect manual pages on unix-based systems
  226. * * connect function in Microsoft's Winsock functions reference
  227. */
  228. static VALUE
  229. sock_connect(VALUE sock, VALUE addr)
  230. {
  231. rb_io_t *fptr;
  232. int fd, n;
  233. SockAddrStringValue(addr);
  234. addr = rb_str_new4(addr);
  235. GetOpenFile(sock, fptr);
  236. fd = fptr->fd;
  237. n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LEN(addr), 0);
  238. if (n < 0) {
  239. rb_sys_fail("connect(2)");
  240. }
  241. return INT2FIX(n);
  242. }
  243. /*
  244. * call-seq:
  245. * socket.connect_nonblock(server_sockaddr) => 0
  246. *
  247. * Requests a connection to be made on the given +server_sockaddr+ after
  248. * O_NONBLOCK is set for the underlying file descriptor.
  249. * Returns 0 if successful, otherwise an exception is raised.
  250. *
  251. * === Parameter
  252. * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
  253. *
  254. * === Example:
  255. * # Pull down Google's web page
  256. * require 'socket'
  257. * include Socket::Constants
  258. * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
  259. * sockaddr = Socket.sockaddr_in(80, 'www.google.com')
  260. * begin # emulate blocking connect
  261. * socket.connect_nonblock(sockaddr)
  262. * rescue IO::WaitWritable
  263. * IO.select(nil, [socket]) # wait 3-way handshake completion
  264. * begin
  265. * socket.connect_nonblock(sockaddr) # check connection failure
  266. * rescue Errno::EISCONN
  267. * end
  268. * end
  269. * socket.write("GET / HTTP/1.0\r\n\r\n")
  270. * results = socket.read
  271. *
  272. * Refer to Socket#connect for the exceptions that may be thrown if the call
  273. * to _connect_nonblock_ fails.
  274. *
  275. * Socket#connect_nonblock may raise any error corresponding to connect(2) failure,
  276. * including Errno::EINPROGRESS.
  277. *
  278. * If the exception is Errno::EINPROGRESS,
  279. * it is extended by IO::WaitWritable.
  280. * So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock.
  281. *
  282. * === See
  283. * * Socket#connect
  284. */
  285. static VALUE
  286. sock_connect_nonblock(VALUE sock, VALUE addr)
  287. {
  288. rb_io_t *fptr;
  289. int n;
  290. SockAddrStringValue(addr);
  291. addr = rb_str_new4(addr);
  292. GetOpenFile(sock, fptr);
  293. rb_io_set_nonblock(fptr);
  294. n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LEN(addr));
  295. if (n < 0) {
  296. if (errno == EINPROGRESS)
  297. rb_mod_sys_fail(rb_mWaitWritable, "connect(2) would block");
  298. rb_sys_fail("connect(2)");
  299. }
  300. return INT2FIX(n);
  301. }
  302. /*
  303. * call-seq:
  304. * socket.bind(server_sockaddr) => 0
  305. *
  306. * Binds to the given +struct+ sockaddr.
  307. *
  308. * === Parameter
  309. * * +server_sockaddr+ - the +struct+ sockaddr contained in a string
  310. *
  311. * === Example
  312. * require 'socket'
  313. * include Socket::Constants
  314. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  315. * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
  316. * socket.bind( sockaddr )
  317. *
  318. * === Unix-based Exceptions
  319. * On unix-based based systems the following system exceptions may be raised if
  320. * the call to _bind_ fails:
  321. * * Errno::EACCES - the specified _sockaddr_ is protected and the current
  322. * user does not have permission to bind to it
  323. * * Errno::EADDRINUSE - the specified _sockaddr_ is already in use
  324. * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the
  325. * local machine
  326. * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for
  327. * the family of the calling +socket+
  328. * * Errno::EBADF - the _sockaddr_ specified is not a valid file descriptor
  329. * * Errno::EFAULT - the _sockaddr_ argument cannot be accessed
  330. * * Errno::EINVAL - the +socket+ is already bound to an address, and the
  331. * protocol does not support binding to the new _sockaddr_ or the +socket+
  332. * has been shut down.
  333. * * Errno::EINVAL - the address length is not a valid length for the address
  334. * family
  335. * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
  336. * PATH_MAX
  337. * * Errno::ENOBUFS - no buffer space is available
  338. * * Errno::ENOSR - there were insufficient STREAMS resources available to
  339. * complete the operation
  340. * * Errno::ENOTSOCK - the +socket+ does not refer to a socket
  341. * * Errno::EOPNOTSUPP - the socket type of the +socket+ does not support
  342. * binding to an address
  343. *
  344. * On unix-based based systems if the address family of the calling +socket+ is
  345. * Socket::AF_UNIX the follow exceptions may be raised if the call to _bind_
  346. * fails:
  347. * * Errno::EACCES - search permission is denied for a component of the prefix
  348. * path or write access to the +socket+ is denied
  349. * * Errno::EDESTADDRREQ - the _sockaddr_ argument is a null pointer
  350. * * Errno::EISDIR - same as Errno::EDESTADDRREQ
  351. * * Errno::EIO - an i/o error occurred
  352. * * Errno::ELOOP - too many symbolic links were encountered in translating
  353. * the pathname in _sockaddr_
  354. * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX
  355. * characters, or an entire pathname exceeded PATH_MAX characters
  356. * * Errno::ENOENT - a component of the pathname does not name an existing file
  357. * or the pathname is an empty string
  358. * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_
  359. * is not a directory
  360. * * Errno::EROFS - the name would reside on a read only filesystem
  361. *
  362. * === Windows Exceptions
  363. * On Windows systems the following system exceptions may be raised if
  364. * the call to _bind_ fails:
  365. * * Errno::ENETDOWN-- the network is down
  366. * * Errno::EACCES - the attempt to connect the datagram socket to the
  367. * broadcast address failed
  368. * * Errno::EADDRINUSE - the socket's local address is already in use
  369. * * Errno::EADDRNOTAVAIL - the specified address is not a valid address for this
  370. * computer
  371. * * Errno::EFAULT - the socket's internal address or address length parameter
  372. * is too small or is not a valid part of the user space addressed
  373. * * Errno::EINVAL - the +socket+ is already bound to an address
  374. * * Errno::ENOBUFS - no buffer space is available
  375. * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
  376. *
  377. * === See
  378. * * bind manual pages on unix-based systems
  379. * * bind function in Microsoft's Winsock functions reference
  380. */
  381. static VALUE
  382. sock_bind(VALUE sock, VALUE addr)
  383. {
  384. rb_io_t *fptr;
  385. SockAddrStringValue(addr);
  386. GetOpenFile(sock, fptr);
  387. if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LEN(addr)) < 0)
  388. rb_sys_fail("bind(2)");
  389. return INT2FIX(0);
  390. }
  391. /*
  392. * call-seq:
  393. * socket.listen( int ) => 0
  394. *
  395. * Listens for connections, using the specified +int+ as the backlog. A call
  396. * to _listen_ only applies if the +socket+ is of type SOCK_STREAM or
  397. * SOCK_SEQPACKET.
  398. *
  399. * === Parameter
  400. * * +backlog+ - the maximum length of the queue for pending connections.
  401. *
  402. * === Example 1
  403. * require 'socket'
  404. * include Socket::Constants
  405. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  406. * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
  407. * socket.bind( sockaddr )
  408. * socket.listen( 5 )
  409. *
  410. * === Example 2 (listening on an arbitrary port, unix-based systems only):
  411. * require 'socket'
  412. * include Socket::Constants
  413. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  414. * socket.listen( 1 )
  415. *
  416. * === Unix-based Exceptions
  417. * On unix based systems the above will work because a new +sockaddr+ struct
  418. * is created on the address ADDR_ANY, for an arbitrary port number as handed
  419. * off by the kernel. It will not work on Windows, because Windows requires that
  420. * the +socket+ is bound by calling _bind_ before it can _listen_.
  421. *
  422. * If the _backlog_ amount exceeds the implementation-dependent maximum
  423. * queue length, the implementation's maximum queue length will be used.
  424. *
  425. * On unix-based based systems the following system exceptions may be raised if the
  426. * call to _listen_ fails:
  427. * * Errno::EBADF - the _socket_ argument is not a valid file descriptor
  428. * * Errno::EDESTADDRREQ - the _socket_ is not bound to a local address, and
  429. * the protocol does not support listening on an unbound socket
  430. * * Errno::EINVAL - the _socket_ is already connected
  431. * * Errno::ENOTSOCK - the _socket_ argument does not refer to a socket
  432. * * Errno::EOPNOTSUPP - the _socket_ protocol does not support listen
  433. * * Errno::EACCES - the calling process does not have appropriate privileges
  434. * * Errno::EINVAL - the _socket_ has been shut down
  435. * * Errno::ENOBUFS - insufficient resources are available in the system to
  436. * complete the call
  437. *
  438. * === Windows Exceptions
  439. * On Windows systems the following system exceptions may be raised if
  440. * the call to _listen_ fails:
  441. * * Errno::ENETDOWN - the network is down
  442. * * Errno::EADDRINUSE - the socket's local address is already in use. This
  443. * usually occurs during the execution of _bind_ but could be delayed
  444. * if the call to _bind_ was to a partially wildcard address (involving
  445. * ADDR_ANY) and if a specific address needs to be committed at the
  446. * time of the call to _listen_
  447. * * Errno::EINPROGRESS - a Windows Sockets 1.1 call is in progress or the
  448. * service provider is still processing a callback function
  449. * * Errno::EINVAL - the +socket+ has not been bound with a call to _bind_.
  450. * * Errno::EISCONN - the +socket+ is already connected
  451. * * Errno::EMFILE - no more socket descriptors are available
  452. * * Errno::ENOBUFS - no buffer space is available
  453. * * Errno::ENOTSOC - +socket+ is not a socket
  454. * * Errno::EOPNOTSUPP - the referenced +socket+ is not a type that supports
  455. * the _listen_ method
  456. *
  457. * === See
  458. * * listen manual pages on unix-based systems
  459. * * listen function in Microsoft's Winsock functions reference
  460. */
  461. static VALUE
  462. sock_listen(VALUE sock, VALUE log)
  463. {
  464. rb_io_t *fptr;
  465. int backlog;
  466. rb_secure(4);
  467. backlog = NUM2INT(log);
  468. GetOpenFile(sock, fptr);
  469. if (listen(fptr->fd, backlog) < 0)
  470. rb_sys_fail("listen(2)");
  471. return INT2FIX(0);
  472. }
  473. /*
  474. * call-seq:
  475. * socket.recvfrom(maxlen) => [mesg, sender_addrinfo]
  476. * socket.recvfrom(maxlen, flags) => [mesg, sender_addrinfo]
  477. *
  478. * Receives up to _maxlen_ bytes from +socket+. _flags_ is zero or more
  479. * of the +MSG_+ options. The first element of the results, _mesg_, is the data
  480. * received. The second element, _sender_addrinfo_, contains protocol-specific information
  481. * on the sender.
  482. *
  483. * === Parameters
  484. * * +maxlen+ - the number of bytes to receive from the socket
  485. * * +flags+ - zero or more of the +MSG_+ options
  486. *
  487. * === Example
  488. * # In one file, start this first
  489. * require 'socket'
  490. * include Socket::Constants
  491. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  492. * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
  493. * socket.bind( sockaddr )
  494. * socket.listen( 5 )
  495. * client, client_addrinfo = socket.accept
  496. * data = client.recvfrom( 20 )[0].chomp
  497. * puts "I only received 20 bytes '#{data}'"
  498. * sleep 1
  499. * socket.close
  500. *
  501. * # In another file, start this second
  502. * require 'socket'
  503. * include Socket::Constants
  504. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  505. * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
  506. * socket.connect( sockaddr )
  507. * socket.puts "Watch this get cut short!"
  508. * socket.close
  509. *
  510. * === Unix-based Exceptions
  511. * On unix-based based systems the following system exceptions may be raised if the
  512. * call to _recvfrom_ fails:
  513. * * Errno::EAGAIN - the +socket+ file descriptor is marked as O_NONBLOCK and no
  514. * data is waiting to be received; or MSG_OOB is set and no out-of-band data
  515. * is available and either the +socket+ file descriptor is marked as
  516. * O_NONBLOCK or the +socket+ does not support blocking to wait for
  517. * out-of-band-data
  518. * * Errno::EWOULDBLOCK - see Errno::EAGAIN
  519. * * Errno::EBADF - the +socket+ is not a valid file descriptor
  520. * * Errno::ECONNRESET - a connection was forcibly closed by a peer
  521. * * Errno::EFAULT - the socket's internal buffer, address or address length
  522. * cannot be accessed or written
  523. * * Errno::EINTR - a signal interrupted _recvfrom_ before any data was available
  524. * * Errno::EINVAL - the MSG_OOB flag is set and no out-of-band data is available
  525. * * Errno::EIO - an i/o error occurred while reading from or writing to the
  526. * filesystem
  527. * * Errno::ENOBUFS - insufficient resources were available in the system to
  528. * perform the operation
  529. * * Errno::ENOMEM - insufficient memory was available to fulfill the request
  530. * * Errno::ENOSR - there were insufficient STREAMS resources available to
  531. * complete the operation
  532. * * Errno::ENOTCONN - a receive is attempted on a connection-mode socket that
  533. * is not connected
  534. * * Errno::ENOTSOCK - the +socket+ does not refer to a socket
  535. * * Errno::EOPNOTSUPP - the specified flags are not supported for this socket type
  536. * * Errno::ETIMEDOUT - the connection timed out during connection establishment
  537. * or due to a transmission timeout on an active connection
  538. *
  539. * === Windows Exceptions
  540. * On Windows systems the following system exceptions may be raised if
  541. * the call to _recvfrom_ fails:
  542. * * Errno::ENETDOWN - the network is down
  543. * * Errno::EFAULT - the internal buffer and from parameters on +socket+ are not
  544. * part of the user address space, or the internal fromlen parameter is
  545. * too small to accommodate the peer address
  546. * * Errno::EINTR - the (blocking) call was cancelled by an internal call to
  547. * the WinSock function WSACancelBlockingCall
  548. * * Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or
  549. * the service provider is still processing a callback function
  550. * * Errno::EINVAL - +socket+ has not been bound with a call to _bind_, or an
  551. * unknown flag was specified, or MSG_OOB was specified for a socket with
  552. * SO_OOBINLINE enabled, or (for byte stream-style sockets only) the internal
  553. * len parameter on +socket+ was zero or negative
  554. * * Errno::EISCONN - +socket+ is already connected. The call to _recvfrom_ is
  555. * not permitted with a connected socket on a socket that is connection
  556. * oriented or connectionless.
  557. * * Errno::ENETRESET - the connection has been broken due to the keep-alive
  558. * activity detecting a failure while the operation was in progress.
  559. * * Errno::EOPNOTSUPP - MSG_OOB was specified, but +socket+ is not stream-style
  560. * such as type SOCK_STREAM. OOB data is not supported in the communication
  561. * domain associated with +socket+, or +socket+ is unidirectional and
  562. * supports only send operations
  563. * * Errno::ESHUTDOWN - +socket+ has been shutdown. It is not possible to
  564. * call _recvfrom_ on a socket after _shutdown_ has been invoked.
  565. * * Errno::EWOULDBLOCK - +socket+ is marked as nonblocking and a call to
  566. * _recvfrom_ would block.
  567. * * Errno::EMSGSIZE - the message was too large to fit into the specified buffer
  568. * and was truncated.
  569. * * Errno::ETIMEDOUT - the connection has been dropped, because of a network
  570. * failure or because the system on the other end went down without
  571. * notice
  572. * * Errno::ECONNRESET - the virtual circuit was reset by the remote side
  573. * executing a hard or abortive close. The application should close the
  574. * socket; it is no longer usable. On a UDP-datagram socket this error
  575. * indicates a previous send operation resulted in an ICMP Port Unreachable
  576. * message.
  577. */
  578. static VALUE
  579. sock_recvfrom(int argc, VALUE *argv, VALUE sock)
  580. {
  581. return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
  582. }
  583. /*
  584. * call-seq:
  585. * socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
  586. * socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
  587. *
  588. * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
  589. * O_NONBLOCK is set for the underlying file descriptor.
  590. * _flags_ is zero or more of the +MSG_+ options.
  591. * The first element of the results, _mesg_, is the data received.
  592. * The second element, _sender_addrinfo_, contains protocol-specific information
  593. * on the sender.
  594. *
  595. * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
  596. * an empty string as data.
  597. * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
  598. *
  599. * === Parameters
  600. * * +maxlen+ - the number of bytes to receive from the socket
  601. * * +flags+ - zero or more of the +MSG_+ options
  602. *
  603. * === Example
  604. * # In one file, start this first
  605. * require 'socket'
  606. * include Socket::Constants
  607. * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
  608. * sockaddr = Socket.sockaddr_in(2200, 'localhost')
  609. * socket.bind(sockaddr)
  610. * socket.listen(5)
  611. * client, client_addrinfo = socket.accept
  612. * begin # emulate blocking recvfrom
  613. * pair = client.recvfrom_nonblock(20)
  614. * rescue IO::WaitReadable
  615. * IO.select([client])
  616. * retry
  617. * end
  618. * data = pair[0].chomp
  619. * puts "I only received 20 bytes '#{data}'"
  620. * sleep 1
  621. * socket.close
  622. *
  623. * # In another file, start this second
  624. * require 'socket'
  625. * include Socket::Constants
  626. * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
  627. * sockaddr = Socket.sockaddr_in(2200, 'localhost')
  628. * socket.connect(sockaddr)
  629. * socket.puts "Watch this get cut short!"
  630. * socket.close
  631. *
  632. * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
  633. * to _recvfrom_nonblock_ fails.
  634. *
  635. * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
  636. * including Errno::EWOULDBLOCK.
  637. *
  638. * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
  639. * it is extended by IO::WaitReadable.
  640. * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
  641. *
  642. * === See
  643. * * Socket#recvfrom
  644. */
  645. static VALUE
  646. sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
  647. {
  648. return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
  649. }
  650. /*
  651. * call-seq:
  652. * socket.accept => [client_socket, client_addrinfo]
  653. *
  654. * Accepts a next connection.
  655. * Returns a new Socket object and Addrinfo object.
  656. *
  657. * serv = Socket.new(:INET, :STREAM, 0)
  658. * serv.listen(5)
  659. * c = Socket.new(:INET, :STREAM, 0)
  660. * c.connect(serv.local_address)
  661. * p serv.accept #=> [#<Socket:fd 6>, #<Addrinfo: 127.0.0.1:48555 TCP>]
  662. *
  663. */
  664. static VALUE
  665. sock_accept(VALUE sock)
  666. {
  667. rb_io_t *fptr;
  668. VALUE sock2;
  669. struct sockaddr_storage buf;
  670. socklen_t len = sizeof buf;
  671. GetOpenFile(sock, fptr);
  672. sock2 = rsock_s_accept(rb_cSocket,fptr->fd,(struct sockaddr*)&buf,&len);
  673. return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
  674. }
  675. /*
  676. * call-seq:
  677. * socket.accept_nonblock => [client_socket, client_addrinfo]
  678. *
  679. * Accepts an incoming connection using accept(2) after
  680. * O_NONBLOCK is set for the underlying file descriptor.
  681. * It returns an array containing the accepted socket
  682. * for the incoming connection, _client_socket_,
  683. * and an Addrinfo, _client_addrinfo_.
  684. *
  685. * === Example
  686. * # In one script, start this first
  687. * require 'socket'
  688. * include Socket::Constants
  689. * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
  690. * sockaddr = Socket.sockaddr_in(2200, 'localhost')
  691. * socket.bind(sockaddr)
  692. * socket.listen(5)
  693. * begin # emulate blocking accept
  694. * client_socket, client_addrinfo = socket.accept_nonblock
  695. * rescue IO::WaitReadable, Errno::EINTR
  696. * IO.select([socket])
  697. * retry
  698. * end
  699. * puts "The client said, '#{client_socket.readline.chomp}'"
  700. * client_socket.puts "Hello from script one!"
  701. * socket.close
  702. *
  703. * # In another script, start this second
  704. * require 'socket'
  705. * include Socket::Constants
  706. * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
  707. * sockaddr = Socket.sockaddr_in(2200, 'localhost')
  708. * socket.connect(sockaddr)
  709. * socket.puts "Hello from script 2."
  710. * puts "The server said, '#{socket.readline.chomp}'"
  711. * socket.close
  712. *
  713. * Refer to Socket#accept for the exceptions that may be thrown if the call
  714. * to _accept_nonblock_ fails.
  715. *
  716. * Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
  717. * including Errno::EWOULDBLOCK.
  718. *
  719. * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO,
  720. * it is extended by IO::WaitReadable.
  721. * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
  722. *
  723. * === See
  724. * * Socket#accept
  725. */
  726. static VALUE
  727. sock_accept_nonblock(VALUE sock)
  728. {
  729. rb_io_t *fptr;
  730. VALUE sock2;
  731. struct sockaddr_storage buf;
  732. socklen_t len = sizeof buf;
  733. GetOpenFile(sock, fptr);
  734. sock2 = rsock_s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)&buf, &len);
  735. return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
  736. }
  737. /*
  738. * call-seq:
  739. * socket.sysaccept => [client_socket_fd, client_addrinfo]
  740. *
  741. * Accepts an incoming connection returning an array containing the (integer)
  742. * file descriptor for the incoming connection, _client_socket_fd_,
  743. * and an Addrinfo, _client_addrinfo_.
  744. *
  745. * === Example
  746. * # In one script, start this first
  747. * require 'socket'
  748. * include Socket::Constants
  749. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  750. * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
  751. * socket.bind( sockaddr )
  752. * socket.listen( 5 )
  753. * client_fd, client_addrinfo = socket.sysaccept
  754. * client_socket = Socket.for_fd( client_fd )
  755. * puts "The client said, '#{client_socket.readline.chomp}'"
  756. * client_socket.puts "Hello from script one!"
  757. * socket.close
  758. *
  759. * # In another script, start this second
  760. * require 'socket'
  761. * include Socket::Constants
  762. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  763. * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
  764. * socket.connect( sockaddr )
  765. * socket.puts "Hello from script 2."
  766. * puts "The server said, '#{socket.readline.chomp}'"
  767. * socket.close
  768. *
  769. * Refer to Socket#accept for the exceptions that may be thrown if the call
  770. * to _sysaccept_ fails.
  771. *
  772. * === See
  773. * * Socket#accept
  774. */
  775. static VALUE
  776. sock_sysaccept(VALUE sock)
  777. {
  778. rb_io_t *fptr;
  779. VALUE sock2;
  780. struct sockaddr_storage buf;
  781. socklen_t len = sizeof buf;
  782. GetOpenFile(sock, fptr);
  783. sock2 = rsock_s_accept(0,fptr->fd,(struct sockaddr*)&buf,&len);
  784. return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
  785. }
  786. #ifdef HAVE_GETHOSTNAME
  787. /*
  788. * call-seq:
  789. * Socket.gethostname => hostname
  790. *
  791. * Returns the hostname.
  792. *
  793. * Note that it is not guaranteed to be able to convert to IP address using gethostbyname, getaddrinfo, etc.
  794. *
  795. * p Socket.gethostname #=> "hal"
  796. *
  797. */
  798. static VALUE
  799. sock_gethostname(VALUE obj)
  800. {
  801. #ifndef HOST_NAME_MAX
  802. # define HOST_NAME_MAX 1024
  803. #endif
  804. char buf[HOST_NAME_MAX+1];
  805. rb_secure(3);
  806. if (gethostname(buf, (int)sizeof buf - 1) < 0)
  807. rb_sys_fail("gethostname");
  808. buf[sizeof buf - 1] = '\0';
  809. return rb_str_new2(buf);
  810. }
  811. #else
  812. #ifdef HAVE_UNAME
  813. #include <sys/utsname.h>
  814. static VALUE
  815. sock_gethostname(VALUE obj)
  816. {
  817. struct utsname un;
  818. rb_secure(3);
  819. uname(&un);
  820. return rb_str_new2(un.nodename);
  821. }
  822. #else
  823. #define sock_gethostname rb_f_notimplement
  824. #endif
  825. #endif
  826. static VALUE
  827. make_addrinfo(struct addrinfo *res0, int norevlookup)
  828. {
  829. VALUE base, ary;
  830. struct addrinfo *res;
  831. if (res0 == NULL) {
  832. rb_raise(rb_eSocket, "host not found");
  833. }
  834. base = rb_ary_new();
  835. for (res = res0; res; res = res->ai_next) {
  836. ary = rsock_ipaddr(res->ai_addr, norevlookup);
  837. if (res->ai_canonname) {
  838. RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname);
  839. }
  840. rb_ary_push(ary, INT2FIX(res->ai_family));
  841. rb_ary_push(ary, INT2FIX(res->ai_socktype));
  842. rb_ary_push(ary, INT2FIX(res->ai_protocol));
  843. rb_ary_push(base, ary);
  844. }
  845. return base;
  846. }
  847. static VALUE
  848. sock_sockaddr(struct sockaddr *addr, size_t len)
  849. {
  850. char *ptr;
  851. switch (addr->sa_family) {
  852. case AF_INET:
  853. ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr;
  854. len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr);
  855. break;
  856. #ifdef AF_INET6
  857. case AF_INET6:
  858. ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr;
  859. len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr);
  860. break;
  861. #endif
  862. default:
  863. rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family);
  864. break;
  865. }
  866. return rb_str_new(ptr, len);
  867. }
  868. /*
  869. * call-seq:
  870. * Socket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list]
  871. *
  872. * Obtains the host information for _hostname_.
  873. *
  874. * p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"]
  875. *
  876. */
  877. static VALUE
  878. sock_s_gethostbyname(VALUE obj, VALUE host)
  879. {
  880. rb_secure(3);
  881. return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr);
  882. }
  883. /*
  884. * call-seq:
  885. * Socket.gethostbyaddr(address_string [, address_family]) => hostent
  886. *
  887. * Obtains the host information for _address_.
  888. *
  889. * p Socket.gethostbyaddr([221,186,184,68].pack("CCCC"))
  890. * #=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"]
  891. */
  892. static VALUE
  893. sock_s_gethostbyaddr(int argc, VALUE *argv)
  894. {
  895. VALUE addr, family;
  896. struct hostent *h;
  897. struct sockaddr *sa;
  898. char **pch;
  899. VALUE ary, names;
  900. int t = AF_INET;
  901. rb_scan_args(argc, argv, "11", &addr, &family);
  902. sa = (struct sockaddr*)StringValuePtr(addr);
  903. if (!NIL_P(family)) {
  904. t = rsock_family_arg(family);
  905. }
  906. #ifdef AF_INET6
  907. else if (RSTRING_LEN(addr) == 16) {
  908. t = AF_INET6;
  909. }
  910. #endif
  911. h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_LEN(addr), t);
  912. if (h == NULL) {
  913. #ifdef HAVE_HSTRERROR
  914. extern int h_errno;
  915. rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno));
  916. #else
  917. rb_raise(rb_eSocket, "host not found");
  918. #endif
  919. }
  920. ary = rb_ary_new();
  921. rb_ary_push(ary, rb_str_new2(h->h_name));
  922. names = rb_ary_new();
  923. rb_ary_push(ary, names);
  924. if (h->h_aliases != NULL) {
  925. for (pch = h->h_aliases; *pch; pch++) {
  926. rb_ary_push(names, rb_str_new2(*pch));
  927. }
  928. }
  929. rb_ary_push(ary, INT2NUM(h->h_addrtype));
  930. #ifdef h_addr
  931. for (pch = h->h_addr_list; *pch; pch++) {
  932. rb_ary_push(ary, rb_str_new(*pch, h->h_length));
  933. }
  934. #else
  935. rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length));
  936. #endif
  937. return ary;
  938. }
  939. /*
  940. * call-seq:
  941. * Socket.getservbyname(service_name) => port_number
  942. * Socket.getservbyname(service_name, protocol_name) => port_number
  943. *
  944. * Obtains the port number for _service_name_.
  945. *
  946. * If _protocol_name_ is not given, "tcp" is assumed.
  947. *
  948. * Socket.getservbyname("smtp") #=> 25
  949. * Socket.getservbyname("shell") #=> 514
  950. * Socket.getservbyname("syslog", "udp") #=> 514
  951. */
  952. static VALUE
  953. sock_s_getservbyname(int argc, VALUE *argv)
  954. {
  955. VALUE service, proto;
  956. struct servent *sp;
  957. int port;
  958. const char *servicename, *protoname = "tcp";
  959. rb_scan_args(argc, argv, "11", &service, &proto);
  960. StringValue(service);
  961. if (!NIL_P(proto)) StringValue(proto);
  962. servicename = StringValueCStr(service);
  963. if (!NIL_P(proto)) protoname = StringValueCStr(proto);
  964. sp = getservbyname(servicename, protoname);
  965. if (sp) {
  966. port = ntohs(sp->s_port);
  967. }
  968. else {
  969. char *end;
  970. port = STRTOUL(servicename, &end, 0);
  971. if (*end != '\0') {
  972. rb_raise(rb_eSocket, "no such service %s/%s", servicename, protoname);
  973. }
  974. }
  975. return INT2FIX(port);
  976. }
  977. /*
  978. * call-seq:
  979. * Socket.getservbyport(port [, protocol_name]) => service
  980. *
  981. * Obtains the port number for _port_.
  982. *
  983. * If _protocol_name_ is not given, "tcp" is assumed.
  984. *
  985. * Socket.getservbyport(80) #=> "www"
  986. * Socket.getservbyport(514, "tcp") #=> "shell"
  987. * Socket.getservbyport(514, "udp") #=> "syslog"
  988. *
  989. */
  990. static VALUE
  991. sock_s_getservbyport(int argc, VALUE *argv)
  992. {
  993. VALUE port, proto;
  994. struct servent *sp;
  995. long portnum;
  996. const char *protoname = "tcp";
  997. rb_scan_args(argc, argv, "11", &port, &proto);
  998. portnum = NUM2LONG(port);
  999. if (portnum != (uint16_t)portnum) {
  1000. const char *s = portnum > 0 ? "big" : "small";
  1001. rb_raise(rb_eRangeError, "integer %ld too %s to convert into `int16_t'", portnum, s);
  1002. }
  1003. if (!NIL_P(proto)) protoname = StringValueCStr(proto);
  1004. sp = getservbyport((int)htons((uint16_t)portnum), protoname);
  1005. if (!sp) {
  1006. rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname);
  1007. }
  1008. return rb_tainted_str_new2(sp->s_name);
  1009. }
  1010. /*
  1011. * call-seq:
  1012. * Socket.getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags[, reverse_lookup]]]]]) => array
  1013. *
  1014. * Obtains address information for _nodename_:_servname_.
  1015. *
  1016. * _family_ should be an address family such as: :INET, :INET6, :UNIX, etc.
  1017. *
  1018. * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
  1019. *
  1020. * _protocol_ should be a protocol defined in the family.
  1021. * 0 is default protocol for the family.
  1022. *
  1023. * _flags_ should be bitwise OR of Socket::AI_* constants.
  1024. *
  1025. * Socket.getaddrinfo("www.ruby-lang.org", "http", nil, :STREAM)
  1026. * #=> [["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68", 2, 1, 6]] # PF_INET/SOCK_STREAM/IPPROTO_TCP
  1027. *
  1028. * Socket.getaddrinfo("localhost", nil)
  1029. * #=> [["AF_INET", 0, "localhost", "127.0.0.1", 2, 1, 6], # PF_INET/SOCK_STREAM/IPPROTO_TCP
  1030. * # ["AF_INET", 0, "localhost", "127.0.0.1", 2, 2, 17], # PF_INET/SOCK_DGRAM/IPPROTO_UDP
  1031. * # ["AF_INET", 0, "localhost", "127.0.0.1", 2, 3, 0]] # PF_INET/SOCK_RAW/IPPROTO_IP
  1032. *
  1033. * _reverse_lookup_ directs the form of the third element, and has to
  1034. * be one of below.
  1035. * If it is ommitted, the default value is +nil+.
  1036. *
  1037. * +true+, +:hostname+: hostname is obtained from numeric address using reverse lookup, which may take a time.
  1038. * +false+, +:numeric+: hostname is same as numeric address.
  1039. * +nil+: obey to the current +do_not_reverse_lookup+ flag.
  1040. */
  1041. static VALUE
  1042. sock_s_getaddrinfo(int argc, VALUE *argv)
  1043. {
  1044. VALUE host, port, family, socktype, protocol, flags, ret, revlookup;
  1045. struct addrinfo hints, *res;
  1046. int norevlookup;
  1047. rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup);
  1048. MEMZERO(&hints, struct addrinfo, 1);
  1049. hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
  1050. if (!NIL_P(socktype)) {
  1051. hints.ai_socktype = rsock_socktype_arg(socktype);
  1052. }
  1053. if (!NIL_P(protocol)) {
  1054. hints.ai_protocol = NUM2INT(protocol);
  1055. }
  1056. if (!NIL_P(flags)) {
  1057. hints.ai_flags = NUM2INT(flags);
  1058. }
  1059. if (NIL_P(revlookup) || !rsock_revlookup_flag(revlookup, &norevlookup)) {
  1060. norevlookup = rsock_do_not_reverse_lookup;
  1061. }
  1062. res = rsock_getaddrinfo(host, port, &hints, 0);
  1063. ret = make_addrinfo(res, norevlookup);
  1064. freeaddrinfo(res);
  1065. return ret;
  1066. }
  1067. /*
  1068. * call-seq:
  1069. * Socket.getnameinfo(sockaddr [, flags]) => [hostname, servicename]
  1070. *
  1071. * Obtains name information for _sockaddr_.
  1072. *
  1073. * _sockaddr_ should be one of follows.
  1074. * - packed sockaddr string such as Socket.sockaddr_in(80, "127.0.0.1")
  1075. * - 3-elements array such as ["AF_INET", 80, "127.0.0.1"]
  1076. * - 4-elements array such as ["AF_INET", 80, ignored, "127.0.0.1"]
  1077. *
  1078. * _flags_ should be bitwise OR of Socket::NI_* constants.
  1079. *
  1080. * Note that the last form is compatible with IPSocket#{addr,peeraddr}.
  1081. *
  1082. * Socket.getnameinfo(Socket.sockaddr_in(80, "127.0.0.1")) #=> ["localhost", "www"]
  1083. * Socket.getnameinfo(["AF_INET", 80, "127.0.0.1"]) #=> ["localhost", "www"]
  1084. * Socket.getnameinfo(["AF_INET", 80, "localhost", "127.0.0.1"]) #=> ["localhost", "www"]
  1085. */
  1086. static VALUE
  1087. sock_s_getnameinfo(int argc, VALUE *argv)
  1088. {
  1089. VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp;
  1090. char *hptr, *pptr;
  1091. char hbuf[1024], pbuf[1024];
  1092. int fl;
  1093. struct addrinfo hints, *res = NULL, *r;
  1094. int error;
  1095. struct sockaddr_storage ss;
  1096. struct sockaddr *sap;
  1097. sa = flags = Qnil;
  1098. rb_scan_args(argc, argv, "11", &sa, &flags);
  1099. fl = 0;
  1100. if (!NIL_P(flags)) {
  1101. fl = NUM2INT(flags);
  1102. }
  1103. tmp = rb_check_sockaddr_string_type(sa);
  1104. if (!NIL_P(tmp)) {
  1105. sa = tmp;
  1106. if (sizeof(ss) < (size_t)RSTRING_LEN(sa)) {
  1107. rb_raise(rb_eTypeError, "sockaddr length too big");
  1108. }
  1109. memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa));
  1110. if ((size_t)RSTRING_LEN(sa) != SS_LEN(&ss)) {
  1111. rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
  1112. }
  1113. sap = (struct sockaddr*)&ss;
  1114. goto call_nameinfo;
  1115. }
  1116. tmp = rb_check_array_type(sa);
  1117. if (!NIL_P(tmp)) {
  1118. sa = tmp;
  1119. MEMZERO(&hints, struct addrinfo, 1);
  1120. if (RARRAY_LEN(sa) == 3) {
  1121. af = RARRAY_PTR(sa)[0];
  1122. port = RARRAY_PTR(sa)[1];
  1123. host = RARRAY_PTR(sa)[2];
  1124. }
  1125. else if (RARRAY_LEN(sa) >= 4) {
  1126. af = RARRAY_PTR(sa)[0];
  1127. port = RARRAY_PTR(sa)[1];
  1128. host = RARRAY_PTR(sa)[3];
  1129. if (NIL_P(host)) {
  1130. host = RARRAY_PTR(sa)[2];
  1131. }
  1132. else {
  1133. /*
  1134. * 4th element holds numeric form, don't resolve.
  1135. * see rsock_ipaddr().
  1136. */
  1137. #ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */
  1138. hints.ai_flags |= AI_NUMERICHOST;
  1139. #endif
  1140. }
  1141. }
  1142. else {
  1143. rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given",
  1144. RARRAY_LEN(sa));
  1145. }
  1146. /* host */
  1147. if (NIL_P(host)) {
  1148. hptr = NULL;
  1149. }
  1150. else {
  1151. strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
  1152. hbuf[sizeof(hbuf) - 1] = '\0';
  1153. hptr = hbuf;
  1154. }
  1155. /* port */
  1156. if (NIL_P(port)) {
  1157. strcpy(pbuf, "0");
  1158. pptr = NULL;
  1159. }
  1160. else if (FIXNUM_P(port)) {
  1161. snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port));
  1162. pptr = pbuf;
  1163. }
  1164. else {
  1165. strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
  1166. pbuf[sizeof(pbuf) - 1] = '\0';
  1167. pptr = pbuf;
  1168. }
  1169. hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
  1170. /* af */
  1171. hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
  1172. error = rb_getaddrinfo(hptr, pptr, &hints, &res);
  1173. if (error) goto error_exit_addr;
  1174. sap = res->ai_addr;
  1175. }
  1176. else {
  1177. rb_raise(rb_eTypeError, "expecting String or Array");
  1178. }
  1179. call_nameinfo:
  1180. error = rb_getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf),
  1181. pbuf, sizeof(pbuf), fl);
  1182. if (error) goto error_exit_name;
  1183. if (res) {
  1184. for (r = res->ai_next; r; r = r->ai_next) {
  1185. char hbuf2[1024], pbuf2[1024];
  1186. sap = r->ai_addr;
  1187. error = rb_getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2),
  1188. pbuf2, sizeof(pbuf2), fl);
  1189. if (error) goto error_exit_name;
  1190. if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) {
  1191. freeaddrinfo(res);
  1192. rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename");
  1193. }
  1194. }
  1195. freeaddrinfo(res);
  1196. }
  1197. return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
  1198. error_exit_addr:
  1199. if (res) freeaddrinfo(res);
  1200. rsock_raise_socket_error("getaddrinfo", error);
  1201. error_exit_name:
  1202. if (res) freeaddrinfo(res);
  1203. rsock_raise_socket_error("getnameinfo", error);
  1204. }
  1205. /*
  1206. * call-seq:
  1207. * Socket.sockaddr_in(port, host) => sockaddr
  1208. * Socket.pack_sockaddr_in(port, host) => sockaddr
  1209. *
  1210. * Packs _port_ and _host_ as an AF_INET/AF_INET6 sockaddr string.
  1211. *
  1212. * Socket.sockaddr_in(80, "127.0.0.1")
  1213. * #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
  1214. *
  1215. * Socket.sockaddr_in(80, "::1")
  1216. * #=> "\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"
  1217. *
  1218. */
  1219. static VALUE
  1220. sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
  1221. {
  1222. struct addrinfo *res = rsock_addrinfo(host, port, 0, 0);
  1223. VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen);
  1224. freeaddrinfo(res);
  1225. OBJ_INFECT(addr, port);
  1226. OBJ_INFECT(addr, host);
  1227. return addr;
  1228. }
  1229. /*
  1230. * call-seq:
  1231. * Socket.unpack_sockaddr_in(sockaddr) => [port, ip_address]
  1232. *
  1233. * Unpacks _sockaddr_ into port and ip_address.
  1234. *
  1235. * _sockaddr_ should be a string or an addrinfo for AF_INET/AF_INET6.
  1236. *
  1237. * sockaddr = Socket.sockaddr_in(80, "127.0.0.1")
  1238. * p sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
  1239. * p Socket.unpack_sockaddr_in(sockaddr) #=> [80, "127.0.0.1"]
  1240. *
  1241. */
  1242. static VALUE
  1243. sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
  1244. {
  1245. struct sockaddr_in * sockaddr;
  1246. VALUE host;
  1247. sockaddr = (struct sockaddr_in*)SockAddrStringValuePtr(addr);
  1248. if (RSTRING_LEN(addr) <
  1249. (char*)&((struct sockaddr *)sockaddr)->sa_family +
  1250. sizeof(((struct sockaddr *)sockaddr)->sa_family) -
  1251. (char*)sockaddr)
  1252. rb_raise(rb_eArgError, "too short sockaddr");
  1253. if (((struct sockaddr *)sockaddr)->sa_family != AF_INET
  1254. #ifdef INET6
  1255. && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6
  1256. #endif
  1257. ) {
  1258. #ifdef INET6
  1259. rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr");
  1260. #else
  1261. rb_raise(rb_eArgError, "not an AF_INET sockaddr");
  1262. #endif
  1263. }
  1264. host = rsock_make_ipaddr((struct sockaddr*)sockaddr);
  1265. OBJ_INFECT(host, addr);
  1266. return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
  1267. }
  1268. #ifdef HAVE_SYS_UN_H
  1269. /*
  1270. * call-seq:
  1271. * Socket.sockaddr_un(path) => sockaddr
  1272. * Socket.pack_sockaddr_un(path) => sockaddr
  1273. *
  1274. * Packs _path_ as an AF_UNIX sockaddr string.
  1275. *
  1276. * Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
  1277. *
  1278. */
  1279. static VALUE
  1280. sock_s_pack_sockaddr_un(VALUE self, VALUE path)
  1281. {
  1282. struct sockaddr_un sockaddr;
  1283. char *sun_path;
  1284. VALUE addr;
  1285. MEMZERO(&sockaddr, struct sockaddr_un, 1);
  1286. sockaddr.sun_family = AF_UNIX;
  1287. sun_path = StringValueCStr(path);
  1288. if (sizeof(sockaddr.sun_path) <= strlen(sun_path)) {
  1289. rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)",
  1290. (int)sizeof(sockaddr.sun_path)-1);
  1291. }
  1292. strncpy(sockaddr.sun_path, sun_path, sizeof(sockaddr.sun_path)-1);
  1293. addr = rb_str_new((char*)&sockaddr, sizeof(sockaddr));
  1294. OBJ_INFECT(addr, path);
  1295. return addr;
  1296. }
  1297. /*
  1298. * call-seq:
  1299. * Socket.unpack_sockaddr_un(sockaddr) => path
  1300. *
  1301. * Unpacks _sockaddr_ into path.
  1302. *
  1303. * _sockaddr_ should be a string or an addrinfo for AF_UNIX.
  1304. *
  1305. * sockaddr = Socket.sockaddr_un("/tmp/sock")
  1306. * p Socket.unpack_sockaddr_un(sockaddr) #=> "/tmp/sock"
  1307. *
  1308. */
  1309. static VALUE
  1310. sock_s_unpack_sockaddr_un(VALUE self, VALUE addr)
  1311. {
  1312. struct sockaddr_un * sockaddr;
  1313. const char *sun_path;
  1314. VALUE path;
  1315. sockaddr = (struct sockaddr_un*)SockAddrStringValuePtr(addr);
  1316. if (RSTRING_LEN(addr) <
  1317. (char*)&((struct sockaddr *)sockaddr)->sa_family +
  1318. sizeof(((struct sockaddr *)sockaddr)->sa_family) -
  1319. (char*)sockaddr)
  1320. rb_raise(rb_eArgError, "too short sockaddr");
  1321. if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) {
  1322. rb_raise(rb_eArgError, "not an AF_UNIX sockaddr");
  1323. }
  1324. if (sizeof(struct sockaddr_un) < (size_t)RSTRING_LEN(addr)) {
  1325. rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d",
  1326. RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un));
  1327. }
  1328. sun_path = rsock_unixpath(sockaddr, RSTRING_LEN(addr));
  1329. if (sizeof(struct sockaddr_un) == RSTRING_LEN(addr) &&
  1330. sun_path == sockaddr->sun_path &&
  1331. sun_path + strlen(sun_path) == RSTRING_PTR(addr) + RSTRING_LEN(addr)) {
  1332. rb_raise(rb_eArgError, "sockaddr_un.sun_path not NUL terminated");
  1333. }
  1334. path = rb_str_new2(sun_path);
  1335. OBJ_INFECT(path, addr);
  1336. return path;
  1337. }
  1338. #endif
  1339. #if defined(HAVE_GETIFADDRS) || defined(SIOCGLIFCONF) || defined(SIOCGIFCONF) || defined(_WIN32)
  1340. static VALUE
  1341. sockaddr_obj(struct sockaddr *addr)
  1342. {
  1343. size_t len;
  1344. #if defined(AF_INET6) && defined(__KAME__)
  1345. struct sockaddr_in6 addr6;
  1346. #endif
  1347. if (addr == NULL)
  1348. return Qnil;
  1349. switch (addr->sa_family) {
  1350. case AF_INET:
  1351. len = sizeof(struct sockaddr_in);
  1352. break;
  1353. #ifdef AF_INET6
  1354. case AF_INET6:
  1355. len = sizeof(struct sockaddr_in6);
  1356. # ifdef __KAME__
  1357. /* KAME uses the 2nd 16bit word of link local IPv6 address as interface index internally */
  1358. /* http://orange.kame.net/dev/cvsweb.cgi/kame/IMPLEMENTATION */
  1359. /* convert fe80:1::1 to fe80::1%1 */
  1360. memcpy(&addr6, addr, len);
  1361. addr = (struct sockaddr *)&addr6;
  1362. if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) &&
  1363. addr6.sin6_scope_id == 0 &&
  1364. (addr6.sin6_addr.s6_addr[2] || addr6.sin6_addr.s6_addr[3])) {
  1365. addr6.sin6_scope_id = (addr6.sin6_addr.s6_addr[2] << 8) | addr6.sin6_addr.s6_addr[3];
  1366. addr6.sin6_addr.s6_addr[2] = 0;
  1367. addr6.sin6_addr.s6_addr[3] = 0;
  1368. }
  1369. # endif
  1370. break;
  1371. #endif
  1372. #ifdef HAVE_SYS_UN_H
  1373. case AF_UNIX:
  1374. len = sizeof(struct sockaddr_un);
  1375. break;
  1376. #endif
  1377. default:
  1378. len = sizeof(struct sockaddr_in);
  1379. break;
  1380. }
  1381. #ifdef SA_LEN
  1382. if (len < (socklen_t)SA_LEN(addr))
  1383. len = SA_LEN(addr);
  1384. #endif
  1385. return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil);
  1386. }
  1387. #endif
  1388. #if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) || defined(_WIN32)
  1389. /*
  1390. * call-seq:
  1391. * Socket.ip_address_list => array
  1392. *
  1393. * Returns local IP addresses as an array.
  1394. *
  1395. * The array contains Addrinfo objects.
  1396. *
  1397. * pp Socket.ip_address_list
  1398. * #=> [#<Addrinfo: 127.0.0.1>,
  1399. * #<Addrinfo: 192.168.0.128>,
  1400. * #<Addrinfo: ::1>,
  1401. * ...]
  1402. *
  1403. */
  1404. static VALUE
  1405. socket_s_ip_address_list(VALUE self)
  1406. {
  1407. #if defined(HAVE_GETIFADDRS)
  1408. struct ifaddrs *ifp = NULL;
  1409. struct ifaddrs *p;
  1410. int ret;
  1411. VALUE list;
  1412. ret = getifaddrs(&ifp);
  1413. if (ret == -1) {
  1414. rb_sys_fail("getifaddrs");
  1415. }
  1416. list = rb_ary_new();
  1417. for (p = ifp; p; p = p->ifa_next) {
  1418. if (p->ifa_addr != NULL && IS_IP_FAMILY(p->ifa_addr->sa_family)) {
  1419. rb_ary_push(list, sockaddr_obj(p->ifa_addr));
  1420. }
  1421. }
  1422. freeifaddrs(ifp);
  1423. return list;
  1424. #elif defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)
  1425. /* Solaris if_tcp(7P) */
  1426. /* HP-UX h…

Large files files are truncated, but you can click here to view the full file