PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/benchmarks/rdoc/ruby_trunk/ext/socket/socket.c

http://github.com/acangiano/ruby-benchmark-suite
C | 1835 lines | 883 code | 126 blank | 826 comment | 161 complexity | 4ceade1e8a4fa5fd8eb04bf7e12258d0 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, CC-BY-SA-3.0, LGPL-2.0, ISC, LGPL-2.1, GPL-2.0

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_sockaddr]
  476. * socket.recvfrom(maxlen, flags) => [mesg, sender_sockaddr]
  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_sockaddr_, 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_sockaddr = 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_sockaddr]
  586. * socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_sockaddr]
  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_sockaddr_, 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_sockaddr = 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_sockaddr]
  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 a string that contains the +struct+ sockaddr information
  684. * about the caller, _client_sockaddr_.
  685. *
  686. * === Example
  687. * # In one script, start this first
  688. * require 'socket'
  689. * include Socket::Constants
  690. * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
  691. * sockaddr = Socket.sockaddr_in(2200, 'localhost')
  692. * socket.bind(sockaddr)
  693. * socket.listen(5)
  694. * begin # emulate blocking accept
  695. * client_socket, client_sockaddr = socket.accept_nonblock
  696. * rescue IO::WaitReadable, Errno::EINTR
  697. * IO.select([socket])
  698. * retry
  699. * end
  700. * puts "The client said, '#{client_socket.readline.chomp}'"
  701. * client_socket.puts "Hello from script one!"
  702. * socket.close
  703. *
  704. * # In another script, start this second
  705. * require 'socket'
  706. * include Socket::Constants
  707. * socket = Socket.new(AF_INET, SOCK_STREAM, 0)
  708. * sockaddr = Socket.sockaddr_in(2200, 'localhost')
  709. * socket.connect(sockaddr)
  710. * socket.puts "Hello from script 2."
  711. * puts "The server said, '#{socket.readline.chomp}'"
  712. * socket.close
  713. *
  714. * Refer to Socket#accept for the exceptions that may be thrown if the call
  715. * to _accept_nonblock_ fails.
  716. *
  717. * Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
  718. * including Errno::EWOULDBLOCK.
  719. *
  720. * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO,
  721. * it is extended by IO::WaitReadable.
  722. * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
  723. *
  724. * === See
  725. * * Socket#accept
  726. */
  727. static VALUE
  728. sock_accept_nonblock(VALUE sock)
  729. {
  730. rb_io_t *fptr;
  731. VALUE sock2;
  732. struct sockaddr_storage buf;
  733. socklen_t len = sizeof buf;
  734. GetOpenFile(sock, fptr);
  735. sock2 = rsock_s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)&buf, &len);
  736. return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
  737. }
  738. /*
  739. * call-seq:
  740. * socket.sysaccept => [client_socket_fd, client_sockaddr]
  741. *
  742. * Accepts an incoming connection returning an array containing the (integer)
  743. * file descriptor for the incoming connection, _client_socket_fd_,
  744. * and a string that contains the +struct+ sockaddr information
  745. * about the caller, _client_sockaddr_.
  746. *
  747. * === Example
  748. * # In one script, start this first
  749. * require 'socket'
  750. * include Socket::Constants
  751. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  752. * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
  753. * socket.bind( sockaddr )
  754. * socket.listen( 5 )
  755. * client_fd, client_sockaddr = socket.sysaccept
  756. * client_socket = Socket.for_fd( client_fd )
  757. * puts "The client said, '#{client_socket.readline.chomp}'"
  758. * client_socket.puts "Hello from script one!"
  759. * socket.close
  760. *
  761. * # In another script, start this second
  762. * require 'socket'
  763. * include Socket::Constants
  764. * socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
  765. * sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
  766. * socket.connect( sockaddr )
  767. * socket.puts "Hello from script 2."
  768. * puts "The server said, '#{socket.readline.chomp}'"
  769. * socket.close
  770. *
  771. * Refer to Socket#accept for the exceptions that may be thrown if the call
  772. * to _sysaccept_ fails.
  773. *
  774. * === See
  775. * * Socket#accept
  776. */
  777. static VALUE
  778. sock_sysaccept(VALUE sock)
  779. {
  780. rb_io_t *fptr;
  781. VALUE sock2;
  782. struct sockaddr_storage buf;
  783. socklen_t len = sizeof buf;
  784. GetOpenFile(sock, fptr);
  785. sock2 = rsock_s_accept(0,fptr->fd,(struct sockaddr*)&buf,&len);
  786. return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
  787. }
  788. #ifdef HAVE_GETHOSTNAME
  789. /*
  790. * call-seq:
  791. * Socket.gethostname => hostname
  792. *
  793. * Returns the hostname.
  794. *
  795. * Note that it is not guaranteed to be able to convert to IP address using gethostbyname, getaddrinfo, etc.
  796. *
  797. * p Socket.gethostname #=> "hal"
  798. *
  799. */
  800. static VALUE
  801. sock_gethostname(VALUE obj)
  802. {
  803. #ifndef HOST_NAME_MAX
  804. # define HOST_NAME_MAX 1024
  805. #endif
  806. char buf[HOST_NAME_MAX+1];
  807. rb_secure(3);
  808. if (gethostname(buf, (int)sizeof buf - 1) < 0)
  809. rb_sys_fail("gethostname");
  810. buf[sizeof buf - 1] = '\0';
  811. return rb_str_new2(buf);
  812. }
  813. #else
  814. #ifdef HAVE_UNAME
  815. #include <sys/utsname.h>
  816. static VALUE
  817. sock_gethostname(VALUE obj)
  818. {
  819. struct utsname un;
  820. rb_secure(3);
  821. uname(&un);
  822. return rb_str_new2(un.nodename);
  823. }
  824. #else
  825. #define sock_gethostname rb_f_notimplement
  826. #endif
  827. #endif
  828. static VALUE
  829. make_addrinfo(struct addrinfo *res0)
  830. {
  831. VALUE base, ary;
  832. struct addrinfo *res;
  833. if (res0 == NULL) {
  834. rb_raise(rb_eSocket, "host not found");
  835. }
  836. base = rb_ary_new();
  837. for (res = res0; res; res = res->ai_next) {
  838. ary = rsock_ipaddr(res->ai_addr, rsock_do_not_reverse_lookup);
  839. if (res->ai_canonname) {
  840. RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname);
  841. }
  842. rb_ary_push(ary, INT2FIX(res->ai_family));
  843. rb_ary_push(ary, INT2FIX(res->ai_socktype));
  844. rb_ary_push(ary, INT2FIX(res->ai_protocol));
  845. rb_ary_push(base, ary);
  846. }
  847. return base;
  848. }
  849. static VALUE
  850. sock_sockaddr(struct sockaddr *addr, size_t len)
  851. {
  852. char *ptr;
  853. switch (addr->sa_family) {
  854. case AF_INET:
  855. ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr;
  856. len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr);
  857. break;
  858. #ifdef INET6
  859. case AF_INET6:
  860. ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr;
  861. len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr);
  862. break;
  863. #endif
  864. default:
  865. rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family);
  866. break;
  867. }
  868. return rb_str_new(ptr, len);
  869. }
  870. /*
  871. * call-seq:
  872. * Socket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list]
  873. *
  874. * Obtains the host information for _hostname_.
  875. *
  876. * p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"]
  877. *
  878. */
  879. static VALUE
  880. sock_s_gethostbyname(VALUE obj, VALUE host)
  881. {
  882. rb_secure(3);
  883. return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr);
  884. }
  885. /*
  886. * call-seq:
  887. * Socket.gethostbyaddr(address_string [, address_family]) => hostent
  888. *
  889. * Obtains the host information for _address_.
  890. *
  891. * p Socket.gethostbyaddr([221,186,184,68].pack("CCCC"))
  892. * #=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"]
  893. */
  894. static VALUE
  895. sock_s_gethostbyaddr(int argc, VALUE *argv)
  896. {
  897. VALUE addr, family;
  898. struct hostent *h;
  899. struct sockaddr *sa;
  900. char **pch;
  901. VALUE ary, names;
  902. int t = AF_INET;
  903. rb_scan_args(argc, argv, "11", &addr, &family);
  904. sa = (struct sockaddr*)StringValuePtr(addr);
  905. if (!NIL_P(family)) {
  906. t = rsock_family_arg(family);
  907. }
  908. #ifdef INET6
  909. else if (RSTRING_LEN(addr) == 16) {
  910. t = AF_INET6;
  911. }
  912. #endif
  913. h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_LEN(addr), t);
  914. if (h == NULL) {
  915. #ifdef HAVE_HSTRERROR
  916. extern int h_errno;
  917. rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno));
  918. #else
  919. rb_raise(rb_eSocket, "host not found");
  920. #endif
  921. }
  922. ary = rb_ary_new();
  923. rb_ary_push(ary, rb_str_new2(h->h_name));
  924. names = rb_ary_new();
  925. rb_ary_push(ary, names);
  926. if (h->h_aliases != NULL) {
  927. for (pch = h->h_aliases; *pch; pch++) {
  928. rb_ary_push(names, rb_str_new2(*pch));
  929. }
  930. }
  931. rb_ary_push(ary, INT2NUM(h->h_addrtype));
  932. #ifdef h_addr
  933. for (pch = h->h_addr_list; *pch; pch++) {
  934. rb_ary_push(ary, rb_str_new(*pch, h->h_length));
  935. }
  936. #else
  937. rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length));
  938. #endif
  939. return ary;
  940. }
  941. /*
  942. * call-seq:
  943. * Socket.getservbyname(service_name) => port_number
  944. * Socket.getservbyname(service_name, protocol_name) => port_number
  945. *
  946. * Obtains the port number for _service_name_.
  947. *
  948. * If _protocol_name_ is not given, "tcp" is assumed.
  949. *
  950. * Socket.getservbyname("smtp") #=> 25
  951. * Socket.getservbyname("shell") #=> 514
  952. * Socket.getservbyname("syslog", "udp") #=> 514
  953. */
  954. static VALUE
  955. sock_s_getservbyname(int argc, VALUE *argv)
  956. {
  957. VALUE service, proto;
  958. struct servent *sp;
  959. int port;
  960. const char *servicename, *protoname = "tcp";
  961. rb_scan_args(argc, argv, "11", &service, &proto);
  962. StringValue(service);
  963. if (!NIL_P(proto)) StringValue(proto);
  964. servicename = StringValueCStr(service);
  965. if (!NIL_P(proto)) protoname = StringValueCStr(proto);
  966. sp = getservbyname(servicename, protoname);
  967. if (sp) {
  968. port = ntohs(sp->s_port);
  969. }
  970. else {
  971. char *end;
  972. port = STRTOUL(servicename, &end, 0);
  973. if (*end != '\0') {
  974. rb_raise(rb_eSocket, "no such service %s/%s", servicename, protoname);
  975. }
  976. }
  977. return INT2FIX(port);
  978. }
  979. /*
  980. * call-seq:
  981. * Socket.getservbyport(port [, protocol_name]) => service
  982. *
  983. * Obtains the port number for _port_.
  984. *
  985. * If _protocol_name_ is not given, "tcp" is assumed.
  986. *
  987. * Socket.getservbyport(80) #=> "www"
  988. * Socket.getservbyport(514, "tcp") #=> "shell"
  989. * Socket.getservbyport(514, "udp") #=> "syslog"
  990. *
  991. */
  992. static VALUE
  993. sock_s_getservbyport(int argc, VALUE *argv)
  994. {
  995. VALUE port, proto;
  996. struct servent *sp;
  997. long portnum;
  998. const char *protoname = "tcp";
  999. rb_scan_args(argc, argv, "11", &port, &proto);
  1000. portnum = NUM2LONG(port);
  1001. if (portnum != (uint16_t)portnum) {
  1002. const char *s = portnum > 0 ? "big" : "small";
  1003. rb_raise(rb_eRangeError, "integer %ld too %s to convert into `int16_t'", portnum, s);
  1004. }
  1005. if (!NIL_P(proto)) protoname = StringValueCStr(proto);
  1006. sp = getservbyport((int)htons((uint16_t)portnum), protoname);
  1007. if (!sp) {
  1008. rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname);
  1009. }
  1010. return rb_tainted_str_new2(sp->s_name);
  1011. }
  1012. /*
  1013. * call-seq:
  1014. * Socket.getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags]]]]) => array
  1015. *
  1016. * Obtains address information for _nodename_:_servname_.
  1017. *
  1018. * _family_ should be an address family such as: :INET, :INET6, :UNIX, etc.
  1019. *
  1020. * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
  1021. *
  1022. * _protocol_ should be a protocol defined in the family.
  1023. * 0 is default protocol for the family.
  1024. *
  1025. * _flags_ should be bitwise OR of Socket::AI_* constants.
  1026. *
  1027. * Socket.getaddrinfo("www.ruby-lang.org", "http", nil, :STREAM)
  1028. * #=> [["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68", 2, 1, 6]] # PF_INET/SOCK_STREAM/IPPROTO_TCP
  1029. *
  1030. * Socket.getaddrinfo("localhost", nil)
  1031. * #=> [["AF_INET", 0, "localhost", "127.0.0.1", 2, 1, 6], # PF_INET/SOCK_STREAM/IPPROTO_TCP
  1032. * # ["AF_INET", 0, "localhost", "127.0.0.1", 2, 2, 17], # PF_INET/SOCK_DGRAM/IPPROTO_UDP
  1033. * # ["AF_INET", 0, "localhost", "127.0.0.1", 2, 3, 0]] # PF_INET/SOCK_RAW/IPPROTO_IP
  1034. *
  1035. */
  1036. static VALUE
  1037. sock_s_getaddrinfo(int argc, VALUE *argv)
  1038. {
  1039. VALUE host, port, family, socktype, protocol, flags, ret;
  1040. struct addrinfo hints, *res;
  1041. rb_scan_args(argc, argv, "24", &host, &port, &family, &socktype, &protocol, &flags);
  1042. MEMZERO(&hints, struct addrinfo, 1);
  1043. hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
  1044. if (!NIL_P(socktype)) {
  1045. hints.ai_socktype = rsock_socktype_arg(socktype);
  1046. }
  1047. if (!NIL_P(protocol)) {
  1048. hints.ai_protocol = NUM2INT(protocol);
  1049. }
  1050. if (!NIL_P(flags)) {
  1051. hints.ai_flags = NUM2INT(flags);
  1052. }
  1053. res = rsock_getaddrinfo(host, port, &hints, 0);
  1054. ret = make_addrinfo(res);
  1055. freeaddrinfo(res);
  1056. return ret;
  1057. }
  1058. /*
  1059. * call-seq:
  1060. * Socket.getnameinfo(sockaddr [, flags]) => [hostname, servicename]
  1061. *
  1062. * Obtains name information for _sockaddr_.
  1063. *
  1064. * _sockaddr_ should be one of follows.
  1065. * - packed sockaddr string such as Socket.sockaddr_in(80, "127.0.0.1")
  1066. * - 3-elements array such as ["AF_INET", 80, "127.0.0.1"]
  1067. * - 4-elements array such as ["AF_INET", 80, ignored, "127.0.0.1"]
  1068. *
  1069. * _flags_ should be bitwise OR of Socket::NI_* constants.
  1070. *
  1071. * Note that the last form is compatible with IPSocket#{addr,peeraddr}.
  1072. *
  1073. * Socket.getnameinfo(Socket.sockaddr_in(80, "127.0.0.1")) #=> ["localhost", "www"]
  1074. * Socket.getnameinfo(["AF_INET", 80, "127.0.0.1"]) #=> ["localhost", "www"]
  1075. * Socket.getnameinfo(["AF_INET", 80, "localhost", "127.0.0.1"]) #=> ["localhost", "www"]
  1076. */
  1077. static VALUE
  1078. sock_s_getnameinfo(int argc, VALUE *argv)
  1079. {
  1080. VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp;
  1081. char *hptr, *pptr;
  1082. char hbuf[1024], pbuf[1024];
  1083. int fl;
  1084. struct addrinfo hints, *res = NULL, *r;
  1085. int error;
  1086. struct sockaddr_storage ss;
  1087. struct sockaddr *sap;
  1088. sa = flags = Qnil;
  1089. rb_scan_args(argc, argv, "11", &sa, &flags);
  1090. fl = 0;
  1091. if (!NIL_P(flags)) {
  1092. fl = NUM2INT(flags);
  1093. }
  1094. tmp = rb_check_sockaddr_string_type(sa);
  1095. if (!NIL_P(tmp)) {
  1096. sa = tmp;
  1097. if (sizeof(ss) < (size_t)RSTRING_LEN(sa)) {
  1098. rb_raise(rb_eTypeError, "sockaddr length too big");
  1099. }
  1100. memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa));
  1101. if ((size_t)RSTRING_LEN(sa) != SS_LEN(&ss)) {
  1102. rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
  1103. }
  1104. sap = (struct sockaddr*)&ss;
  1105. goto call_nameinfo;
  1106. }
  1107. tmp = rb_check_array_type(sa);
  1108. if (!NIL_P(tmp)) {
  1109. sa = tmp;
  1110. MEMZERO(&hints, struct addrinfo, 1);
  1111. if (RARRAY_LEN(sa) == 3) {
  1112. af = RARRAY_PTR(sa)[0];
  1113. port = RARRAY_PTR(sa)[1];
  1114. host = RARRAY_PTR(sa)[2];
  1115. }
  1116. else if (RARRAY_LEN(sa) >= 4) {
  1117. af = RARRAY_PTR(sa)[0];
  1118. port = RARRAY_PTR(sa)[1];
  1119. host = RARRAY_PTR(sa)[3];
  1120. if (NIL_P(host)) {
  1121. host = RARRAY_PTR(sa)[2];
  1122. }
  1123. else {
  1124. /*
  1125. * 4th element holds numeric form, don't resolve.
  1126. * see rsock_ipaddr().
  1127. */
  1128. #ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */
  1129. hints.ai_flags |= AI_NUMERICHOST;
  1130. #endif
  1131. }
  1132. }
  1133. else {
  1134. rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given",
  1135. RARRAY_LEN(sa));
  1136. }
  1137. /* host */
  1138. if (NIL_P(host)) {
  1139. hptr = NULL;
  1140. }
  1141. else {
  1142. strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
  1143. hbuf[sizeof(hbuf) - 1] = '\0';
  1144. hptr = hbuf;
  1145. }
  1146. /* port */
  1147. if (NIL_P(port)) {
  1148. strcpy(pbuf, "0");
  1149. pptr = NULL;
  1150. }
  1151. else if (FIXNUM_P(port)) {
  1152. snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port));
  1153. pptr = pbuf;
  1154. }
  1155. else {
  1156. strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
  1157. pbuf[sizeof(pbuf) - 1] = '\0';
  1158. pptr = pbuf;
  1159. }
  1160. hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
  1161. /* af */
  1162. hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
  1163. error = rb_getaddrinfo(hptr, pptr, &hints, &res);
  1164. if (error) goto error_exit_addr;
  1165. sap = res->ai_addr;
  1166. }
  1167. else {
  1168. rb_raise(rb_eTypeError, "expecting String or Array");
  1169. }
  1170. call_nameinfo:
  1171. error = rb_getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf),
  1172. pbuf, sizeof(pbuf), fl);
  1173. if (error) goto error_exit_name;
  1174. if (res) {
  1175. for (r = res->ai_next; r; r = r->ai_next) {
  1176. char hbuf2[1024], pbuf2[1024];
  1177. sap = r->ai_addr;
  1178. error = rb_getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2),
  1179. pbuf2, sizeof(pbuf2), fl);
  1180. if (error) goto error_exit_name;
  1181. if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) {
  1182. freeaddrinfo(res);
  1183. rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename");
  1184. }
  1185. }
  1186. freeaddrinfo(res);
  1187. }
  1188. return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
  1189. error_exit_addr:
  1190. if (res) freeaddrinfo(res);
  1191. rsock_raise_socket_error("getaddrinfo", error);
  1192. error_exit_name:
  1193. if (res) freeaddrinfo(res);
  1194. rsock_raise_socket_error("getnameinfo", error);
  1195. }
  1196. /*
  1197. * call-seq:
  1198. * Socket.sockaddr_in(port, host) => sockaddr
  1199. * Socket.pack_sockaddr_in(port, host) => sockaddr
  1200. *
  1201. * Packs _port_ and _host_ as an AF_INET/AF_INET6 sockaddr string.
  1202. *
  1203. * Socket.sockaddr_in(80, "127.0.0.1")
  1204. * #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
  1205. *
  1206. * Socket.sockaddr_in(80, "::1")
  1207. * #=> "\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"
  1208. *
  1209. */
  1210. static VALUE
  1211. sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
  1212. {
  1213. struct addrinfo *res = rsock_addrinfo(host, port, 0, 0);
  1214. VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen);
  1215. freeaddrinfo(res);
  1216. OBJ_INFECT(addr, port);
  1217. OBJ_INFECT(addr, host);
  1218. return addr;
  1219. }
  1220. /*
  1221. * call-seq:
  1222. * Socket.unpack_sockaddr_in(sockaddr) => [port, ip_address]
  1223. *
  1224. * Unpacks _sockaddr_ into port and ip_address.
  1225. *
  1226. * _sockaddr_ should be a string or an addrinfo for AF_INET/AF_INET6.
  1227. *
  1228. * sockaddr = Socket.sockaddr_in(80, "127.0.0.1")
  1229. * p sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
  1230. * p Socket.unpack_sockaddr_in(sockaddr) #=> [80, "127.0.0.1"]
  1231. *
  1232. */
  1233. static VALUE
  1234. sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
  1235. {
  1236. struct sockaddr_in * sockaddr;
  1237. VALUE host;
  1238. sockaddr = (struct sockaddr_in*)SockAddrStringValuePtr(addr);
  1239. if (RSTRING_LEN(addr) <
  1240. (char*)&((struct sockaddr *)sockaddr)->sa_family +
  1241. sizeof(((struct sockaddr *)sockaddr)->sa_family) -
  1242. (char*)sockaddr)
  1243. rb_raise(rb_eArgError, "too short sockaddr");
  1244. if (((struct sockaddr *)sockaddr)->sa_family != AF_INET
  1245. #ifdef INET6
  1246. && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6
  1247. #endif
  1248. ) {
  1249. #ifdef INET6
  1250. rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr");
  1251. #else
  1252. rb_raise(rb_eArgError, "not an AF_INET sockaddr");
  1253. #endif
  1254. }
  1255. host = rsock_make_ipaddr((struct sockaddr*)sockaddr);
  1256. OBJ_INFECT(host, addr);
  1257. return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
  1258. }
  1259. #ifdef HAVE_SYS_UN_H
  1260. /*
  1261. * call-seq:
  1262. * Socket.sockaddr_un(path) => sockaddr
  1263. * Socket.pack_sockaddr_un(path) => sockaddr
  1264. *
  1265. * Packs _path_ as an AF_UNIX sockaddr string.
  1266. *
  1267. * Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
  1268. *
  1269. */
  1270. static VALUE
  1271. sock_s_pack_sockaddr_un(VALUE self, VALUE path)
  1272. {
  1273. struct sockaddr_un sockaddr;
  1274. char *sun_path;
  1275. VALUE addr;
  1276. MEMZERO(&sockaddr, struct sockaddr_un, 1);
  1277. sockaddr.sun_family = AF_UNIX;
  1278. sun_path = StringValueCStr(path);
  1279. if (sizeof(sockaddr.sun_path) <= strlen(sun_path)) {
  1280. rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)",
  1281. (int)sizeof(sockaddr.sun_path)-1);
  1282. }
  1283. strncpy(sockaddr.sun_path, sun_path, sizeof(sockaddr.sun_path)-1);
  1284. addr = rb_str_new((char*)&sockaddr, sizeof(sockaddr));
  1285. OBJ_INFECT(addr, path);
  1286. return addr;
  1287. }
  1288. /*
  1289. * call-seq:
  1290. * Socket.unpack_sockaddr_un(sockaddr) => path
  1291. *
  1292. * Unpacks _sockaddr_ into path.
  1293. *
  1294. * _sockaddr_ should be a string or an addrinfo for AF_UNIX.
  1295. *
  1296. * sockaddr = Socket.sockaddr_un("/tmp/sock")
  1297. * p Socket.unpack_sockaddr_un(sockaddr) #=> "/tmp/sock"
  1298. *
  1299. */
  1300. static VALUE
  1301. sock_s_unpack_sockaddr_un(VALUE self, VALUE addr)
  1302. {
  1303. struct sockaddr_un * sockaddr;
  1304. const char *sun_path;
  1305. VALUE path;
  1306. sockaddr = (struct sockaddr_un*)SockAddrStringValuePtr(addr);
  1307. if (RSTRING_LEN(addr) <
  1308. (char*)&((struct sockaddr *)sockaddr)->sa_family +
  1309. sizeof(((struct sockaddr *)sockaddr)->sa_family) -
  1310. (char*)sockaddr)
  1311. rb_raise(rb_eArgError, "too short sockaddr");
  1312. if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) {
  1313. rb_raise(rb_eArgError, "not an AF_UNIX sockaddr");
  1314. }
  1315. if (sizeof(struct sockaddr_un) < (size_t)RSTRING_LEN(addr)) {
  1316. rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d",
  1317. RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un));
  1318. }
  1319. sun_path = rsock_unixpath(sockaddr, RSTRING_LEN(addr));
  1320. if (sizeof(struct sockaddr_un) == RSTRING_LEN(addr) &&
  1321. sun_path == sockaddr->sun_path &&
  1322. sun_path + strlen(sun_path) == RSTRING_PTR(addr) + RSTRING_LEN(addr)) {
  1323. rb_raise(rb_eArgError, "sockaddr_un.sun_path not NUL terminated");
  1324. }
  1325. path = rb_str_new2(sun_path);
  1326. OBJ_INFECT(path, addr);
  1327. return path;
  1328. }
  1329. #endif
  1330. #if defined(HAVE_GETIFADDRS) || defined(SIOCGLIFCONF) || defined(SIOCGIFCONF) || defined(_WIN32)
  1331. static VALUE
  1332. sockaddr_obj(struct sockaddr *addr)
  1333. {
  1334. socklen_t len;
  1335. #if defined(AF_INET6) && defined(__KAME__)
  1336. struct sockaddr_in6 addr6;
  1337. #endif
  1338. if (addr == NULL)
  1339. return Qnil;
  1340. switch (addr->sa_family) {
  1341. case AF_INET:
  1342. len = sizeof(struct sockaddr_in);
  1343. break;
  1344. #ifdef AF_INET6
  1345. case AF_INET6:
  1346. len = sizeof(struct sockaddr_in6);
  1347. # ifdef __KAME__
  1348. /* KAME uses the 2nd 16bit word of link local IPv6 address as interface index internally */
  1349. /* http://orange.kame.net/dev/cvsweb.cgi/kame/IMPLEMENTATION */
  1350. /* convert fe80:1::1 to fe80::1%1 */
  1351. memcpy(&addr6, addr, len);
  1352. addr = (struct sockaddr *)&addr6;
  1353. if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) &&
  1354. addr6.sin6_scope_id == 0 &&
  1355. (addr6.sin6_addr.s6_addr[2] || addr6.sin6_addr.s6_addr[3])) {
  1356. addr6.sin6_scope_id = (addr6.sin6_addr.s6_addr[2] << 8) | addr6.sin6_addr.s6_addr[3];
  1357. addr6.sin6_addr.s6_addr[2] = 0;
  1358. addr6.sin6_addr.s6_addr[3] = 0;
  1359. }
  1360. # endif
  1361. break;
  1362. #endif
  1363. #ifdef HAVE_SYS_UN_H
  1364. case AF_UNIX:
  1365. len = sizeof(struct sockaddr_un);
  1366. break;
  1367. #endif
  1368. default:
  1369. len = sizeof(struct sockaddr_in);
  1370. break;
  1371. }
  1372. #ifdef SA_LEN
  1373. if (len < (socklen_t)SA_LEN(addr))
  1374. len = SA_LEN(addr);
  1375. #endif
  1376. return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil);
  1377. }
  1378. #endif
  1379. #if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) || defined(_WIN32)
  1380. /*
  1381. * call-seq:
  1382. * Socket.ip_address_list => array
  1383. *
  1384. * Returns local IP addresses as an array.
  1385. *
  1386. * The array contains Addrinfo objects.
  1387. *
  1388. * pp Socket.ip_address_list
  1389. * #=> [#<Addrinfo: 127.0.0.1>,
  1390. * #<Addrinfo: 192.168.0.128>,
  1391. * #<Addrinfo: ::1>,
  1392. * ...]
  1393. *
  1394. */
  1395. static VALUE
  1396. socket_s_ip_address_list(VALUE self)
  1397. {
  1398. #if defined(HAVE_GETIFADDRS)
  1399. struct ifaddrs *ifp = NULL;
  1400. struct ifaddrs *p;
  1401. int ret;
  1402. VALUE list;
  1403. ret = getifaddrs(&ifp);
  1404. if (ret == -1) {
  1405. rb_sys_fail("getifaddrs");
  1406. }
  1407. list = rb_ary_new();
  1408. for (p = ifp; p; p = p->ifa_next) {
  1409. if (p->ifa_addr != NULL && IS_IP_FAMILY(p->ifa_addr->sa_family)) {
  1410. rb_ary_push(list, sockaddr_obj(p->ifa_addr));
  1411. }
  1412. }
  1413. freeifaddrs(ifp);
  1414. return list;
  1415. #elif defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)
  1416. /* Solaris if_tcp(7P) */
  1417. /* HP-UX has SIOCGLIFCONF too. But it uses different struct */
  1418. int fd = -1;
  1419. int ret;
  1420. struct lifnum ln;
  1421. struct lifconf lc;
  1422. char *reason = NULL;
  1423. int save_errno;
  1424. int i;
  1425. VALUE list = Qnil;
  1426. lc.lifc_buf = NULL;
  1427. fd = socket(AF_INET, SOCK_DGRAM, 0);
  1428. if (fd == -1)
  1429. rb_sys_fail("socket");
  1430. memset(&ln, 0, sizeof(ln));
  1431. ln.lifn_family = AF_UNSPEC;
  1432. ret = ioctl(fd, SIOCGLIFNUM, &ln);
  1433. if (ret == -1) {
  1434. reason = "SIOCGLIFNUM"

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