Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/socket/udpsocket.c

Go to the documentation of this file.

    00001 /************************************************
    00002
    00003   udpsocket.c -
    00004
    00005   created at: Thu Mar 31 12:21:29 JST 1994
    00006
    00007   Copyright (C) 1993-2007 Yukihiro Matsumoto
    00008
    00009 ************************************************/
    00010
    00011 #include "rubysocket.h"
    00012
    00013 /*
    00014  * call-seq:
    00015  *   UDPSocket.new([address_family]) => socket
    00016  *
    00017  * Creates a new UDPSocket object.
    00018  *
    00019  * _address_family_ should be an integer, a string or a symbol:
    00020  * Socket::AF_INET, "AF_INET", :INET, etc.
    00021  *
    00022  *   UDPSocket.new                   #=> #<UDPSocket:fd 3>
    00023  *   UDPSocket.new(Socket::AF_INET6) #=> #<UDPSocket:fd 4>
    00024  *
    00025  */
    00026 static VALUE
    00027 udp_init(int argc, VALUE *argv, VALUE sock)
    00028 {
    00029     VALUE arg;
    00030     int family = AF_INET;
    00031     int fd;
    00032
    00033     rb_secure(3);
    00034     if (rb_scan_args(argc, argv, "01", &arg) == 1) {
    00035         family = rsock_family_arg(arg);
    00036     }
    00037     fd = rsock_socket(family, SOCK_DGRAM, 0);
    00038     if (fd < 0) {
    00039         rb_sys_fail("socket(2) - udp");
    00040     }
    00041
    00042     return rsock_init_sock(sock, fd);
    00043 }
    00044
    00045 struct udp_arg
    00046 {
    00047     struct addrinfo *res;
    00048     int fd;
    00049 };
    00050
    00051 static VALUE
    00052 udp_connect_internal(struct udp_arg *arg)
    00053 {
    00054     int fd = arg->fd;
    00055     struct addrinfo *res;
    00056
    00057     for (res = arg->res; res; res = res->ai_next) {
    00058         if (rsock_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) {
    00059             return Qtrue;
    00060         }
    00061     }
    00062     return Qfalse;
    00063 }
    00064
    00065 VALUE rsock_freeaddrinfo(struct addrinfo *addr);
    00066
    00067 /*
    00068  * call-seq:
    00069  *   udpsocket.connect(host, port) => 0
    00070  *
    00071  * Connects _udpsocket_ to _host_:_port_.
    00072  *
    00073  * This makes possible to send without destination address.
    00074  *
    00075  *   u1 = UDPSocket.new
    00076  *   u1.bind("127.0.0.1", 4913)
    00077  *   u2 = UDPSocket.new
    00078  *   u2.connect("127.0.0.1", 4913)
    00079  *   u2.send "uuuu", 0
    00080  *   p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
    00081  *
    00082  */
    00083 static VALUE
    00084 udp_connect(VALUE sock, VALUE host, VALUE port)
    00085 {
    00086     rb_io_t *fptr;
    00087     struct udp_arg arg;
    00088     VALUE ret;
    00089
    00090     rb_secure(3);
    00091     arg.res = rsock_addrinfo(host, port, SOCK_DGRAM, 0);
    00092     GetOpenFile(sock, fptr);
    00093     arg.fd = fptr->fd;
    00094     ret = rb_ensure(udp_connect_internal, (VALUE)&arg,
    00095                     rsock_freeaddrinfo, (VALUE)arg.res);
    00096     if (!ret) rb_sys_fail("connect(2)");
    00097     return INT2FIX(0);
    00098 }
    00099
    00100 /*
    00101  * call-seq:
    00102  *   udpsocket.bind(host, port) #=> 0
    00103  *
    00104  * Binds _udpsocket_ to _host_:_port_.
    00105  *
    00106  *   u1 = UDPSocket.new
    00107  *   u1.bind("127.0.0.1", 4913)
    00108  *   u1.send "message-to-self", 0, "127.0.0.1", 4913
    00109  *   p u1.recvfrom(10) #=> ["message-to", ["AF_INET", 4913, "localhost", "127.0.0.1"]]
    00110  *
    00111  */
    00112 static VALUE
    00113 udp_bind(VALUE sock, VALUE host, VALUE port)
    00114 {
    00115     rb_io_t *fptr;
    00116     struct addrinfo *res0, *res;
    00117
    00118     rb_secure(3);
    00119     res0 = rsock_addrinfo(host, port, SOCK_DGRAM, 0);
    00120     GetOpenFile(sock, fptr);
    00121     for (res = res0; res; res = res->ai_next) {
    00122         if (bind(fptr->fd, res->ai_addr, res->ai_addrlen) < 0) {
    00123             continue;
    00124         }
    00125         freeaddrinfo(res0);
    00126         return INT2FIX(0);
    00127     }
    00128     freeaddrinfo(res0);
    00129     rb_sys_fail("bind(2)");
    00130     return INT2FIX(0);
    00131 }
    00132
    00133 /*
    00134  * call-seq:
    00135  *   udpsocket.send(mesg, flags, host, port)  => numbytes_sent
    00136  *   udpsocket.send(mesg, flags, sockaddr_to) => numbytes_sent
    00137  *   udpsocket.send(mesg, flags)              => numbytes_sent
    00138  *
    00139  * Sends _mesg_ via _udpsocket_.
    00140  *
    00141  * _flags_ should be a bitwise OR of Socket::MSG_* constants.
    00142  *
    00143  *   u1 = UDPSocket.new
    00144  *   u1.bind("127.0.0.1", 4913)
    00145  *
    00146  *   u2 = UDPSocket.new
    00147  *   u2.send "hi", 0, "127.0.0.1", 4913
    00148  *
    00149  *   mesg, addr = u1.recvfrom(10)
    00150  *   u1.send mesg, 0, addr[3], addr[1]
    00151  *
    00152  *   p u2.recv(100) #=> "hi"
    00153  *
    00154  */
    00155 static VALUE
    00156 udp_send(int argc, VALUE *argv, VALUE sock)
    00157 {
    00158     VALUE flags, host, port;
    00159     rb_io_t *fptr;
    00160     int n;
    00161     struct addrinfo *res0, *res;
    00162     struct rsock_send_arg arg;
    00163
    00164     if (argc == 2 || argc == 3) {
    00165         return rsock_bsock_send(argc, argv, sock);
    00166     }
    00167     rb_secure(4);
    00168     rb_scan_args(argc, argv, "4", &arg.mesg, &flags, &host, &port);
    00169
    00170     StringValue(arg.mesg);
    00171     res0 = rsock_addrinfo(host, port, SOCK_DGRAM, 0);
    00172     GetOpenFile(sock, fptr);
    00173     arg.fd = fptr->fd;
    00174     arg.flags = NUM2INT(flags);
    00175     for (res = res0; res; res = res->ai_next) {
    00176       retry:
    00177         arg.to = res->ai_addr;
    00178         arg.tolen = res->ai_addrlen;
    00179         rb_thread_fd_writable(arg.fd);
    00180         n = (int)BLOCKING_REGION(rsock_sendto_blocking, &arg);
    00181         if (n >= 0) {
    00182             freeaddrinfo(res0);
    00183             return INT2FIX(n);
    00184         }
    00185         if (rb_io_wait_writable(fptr->fd)) {
    00186             goto retry;
    00187         }
    00188     }
    00189     freeaddrinfo(res0);
    00190     rb_sys_fail("sendto(2)");
    00191     return INT2FIX(n);
    00192 }
    00193
    00194 /*
    00195  * call-seq:
    00196  *      udpsocket.recvfrom_nonblock(maxlen) => [mesg, sender_inet_addr]
    00197  *      udpsocket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_inet_addr]
    00198  *
    00199  * Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
    00200  * O_NONBLOCK is set for the underlying file descriptor.
    00201  * If _maxlen_ is omitted, its default value is 65536.
    00202  * _flags_ is zero or more of the +MSG_+ options.
    00203  * The first element of the results, _mesg_, is the data received.
    00204  * The second element, _sender_inet_addr_, is an array to represent the sender address.
    00205  *
    00206  * When recvfrom(2) returns 0,
    00207  * Socket#recvfrom_nonblock returns an empty string as data.
    00208  * It means an empty packet.
    00209  *
    00210  * === Parameters
    00211  * * +maxlen+ - the number of bytes to receive from the socket
    00212  * * +flags+ - zero or more of the +MSG_+ options
    00213  *
    00214  * === Example
    00215  *      require 'socket'
    00216  *      s1 = UDPSocket.new
    00217  *      s1.bind("127.0.0.1", 0)
    00218  *      s2 = UDPSocket.new
    00219  *      s2.bind("127.0.0.1", 0)
    00220  *      s2.connect(*s1.addr.values_at(3,1))
    00221  *      s1.connect(*s2.addr.values_at(3,1))
    00222  *      s1.send "aaa", 0
    00223  *      begin # emulate blocking recvfrom
    00224  *        p s2.recvfrom_nonblock(10)  #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
    00225  *      rescue IO::WaitReadable
    00226  *        IO.select([s2])
    00227  *        retry
    00228  *      end
    00229  *
    00230  * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
    00231  * to _recvfrom_nonblock_ fails.
    00232  *
    00233  * UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
    00234  * including Errno::EWOULDBLOCK.
    00235  *
    00236  * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
    00237  * it is extended by IO::WaitReadable.
    00238  * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
    00239  *
    00240  * === See
    00241  * * Socket#recvfrom
    00242  */
    00243 static VALUE
    00244 udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
    00245 {
    00246     return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_IP);
    00247 }
    00248
    00249 /*
    00250  * Document-class: ::UDPSocket < IPSocket
    00251  *
    00252  * UDPSocket represents a UDP/IP socket.
    00253  */
    00254 void
    00255 rsock_init_udpsocket(void)
    00256 {
    00257     rb_cUDPSocket = rb_define_class("UDPSocket", rb_cIPSocket);
    00258     rb_define_method(rb_cUDPSocket, "initialize", udp_init, -1);
    00259     rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
    00260     rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
    00261     rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
    00262     rb_define_method(rb_cUDPSocket, "recvfrom_nonblock", udp_recvfrom_nonblock, -1);
    00263 }
    00264
    00265