PageRenderTime 69ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/socket/socket.c

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

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