/* * call-seq: * ipsocket.peeraddr([reverse_lookup]) => [address_family, port, hostname, numeric_address] * * Returns the remote address as an array which contains * address_family, port, hostname and numeric_address. * It is defined for connection oriented socket such as TCPSocket. * * If +reverse_lookup+ is +true+ or +:hostname+, * hostname is obtained from numeric_address using reverse lookup. * Or if it is +false+, or +:numeric+, * hostname is same as numeric_address. * Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+. * See +Socket.getaddrinfo+ also. * * TCPSocket.open("www.ruby-lang.org", 80) {|sock| * p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"] * p sock.peeraddr(true) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"] * p sock.peeraddr(false) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"] * p sock.peeraddr(:hostname) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"] * p sock.peeraddr(:numeric) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"] * } * */ static VALUE ip_peeraddr(int argc, VALUE *argv, VALUE sock) { rb_io_t *fptr; struct sockaddr_storage addr; socklen_t len = (socklen_t)sizeof addr; int norevlookup; GetOpenFile(sock, fptr); if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup)) norevlookup = fptr->mode & FMODE_NOREVLOOKUP; if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0) rb_sys_fail("getpeername(2)"); return rsock_ipaddr((struct sockaddr*)&addr, len, norevlookup); }
VALUE rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from) { rb_io_t *fptr; VALUE str; union_sockaddr buf; socklen_t alen = (socklen_t)sizeof buf; VALUE len, flg; long buflen; long slen; int fd, flags; VALUE addr = Qnil; socklen_t len0; rb_scan_args(argc, argv, "11", &len, &flg); if (flg == Qnil) flags = 0; else flags = NUM2INT(flg); buflen = NUM2INT(len); #ifdef MSG_DONTWAIT /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom. It is not portable, though. */ flags |= MSG_DONTWAIT; #endif GetOpenFile(sock, fptr); if (rb_io_read_pending(fptr)) { rb_raise(rb_eIOError, "recvfrom for buffered IO"); } fd = fptr->fd; str = rb_tainted_str_new(0, buflen); rb_io_check_closed(fptr); rb_io_set_nonblock(fptr); len0 = alen; slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, &buf.addr, &alen); if (slen != -1 && len0 < alen) alen = len0; if (slen < 0) { switch (errno) { case EAGAIN: #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block"); } rb_sys_fail("recvfrom(2)"); } if (slen < RSTRING_LEN(str)) { rb_str_set_len(str, slen); } rb_obj_taint(str); switch (from) { case RECV_RECV: return str; case RECV_IP: if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */ addr = rsock_ipaddr(&buf.addr, alen, fptr->mode & FMODE_NOREVLOOKUP); break; case RECV_SOCKET: addr = rsock_io_socket_addrinfo(sock, &buf.addr, alen); break; default: rb_bug("rsock_s_recvfrom_nonblock called with bad value"); } return rb_assoc_new(str, addr); }
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from) { rb_io_t *fptr; VALUE str, klass; struct recvfrom_arg arg; VALUE len, flg; long buflen; long slen; rb_scan_args(argc, argv, "11", &len, &flg); if (flg == Qnil) arg.flags = 0; else arg.flags = NUM2INT(flg); buflen = NUM2INT(len); GetOpenFile(sock, fptr); if (rb_io_read_pending(fptr)) { rb_raise(rb_eIOError, "recv for buffered IO"); } arg.fd = fptr->fd; arg.alen = (socklen_t)sizeof(arg.buf); arg.str = str = rb_tainted_str_new(0, buflen); klass = RBASIC(str)->klass; rb_obj_hide(str); while (rb_io_check_closed(fptr), rsock_maybe_wait_fd(arg.fd), (slen = BLOCKING_REGION_FD(recvfrom_blocking, &arg)) < 0) { if (!rb_io_wait_readable(fptr->fd)) { rb_sys_fail("recvfrom(2)"); } if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) { rb_raise(rb_eRuntimeError, "buffer string modified"); } } rb_obj_reveal(str, klass); if (slen < RSTRING_LEN(str)) { rb_str_set_len(str, slen); } rb_obj_taint(str); switch (from) { case RECV_RECV: return str; case RECV_IP: #if 0 if (arg.alen != sizeof(struct sockaddr_in)) { rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); } #endif if (arg.alen && arg.alen != sizeof(arg.buf)) /* OSX doesn't return a from result for connection-oriented sockets */ return rb_assoc_new(str, rsock_ipaddr(&arg.buf.addr, arg.alen, fptr->mode & FMODE_NOREVLOOKUP)); else return rb_assoc_new(str, Qnil); #ifdef HAVE_SYS_UN_H case RECV_UNIX: return rb_assoc_new(str, rsock_unixaddr(&arg.buf.un, arg.alen)); #endif case RECV_SOCKET: return rb_assoc_new(str, rsock_io_socket_addrinfo(sock, &arg.buf.addr, arg.alen)); default: rb_bug("rsock_s_recvfrom called with bad value"); } }