PageRenderTime 71ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 1ms

/components/ruby-2.1.0/ext/socket/socket.c

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

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