Ruby 1.9.3p327(2012-11-10revision37606)
ext/socket/tcpserver.c
Go to the documentation of this file.
00001 /************************************************
00002 
00003   tcpserver.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  *   TCPServer.new([hostname,] port)                    => tcpserver
00016  *
00017  * Creates a new server socket bound to _port_.
00018  *
00019  * If _hostname_ is given, the socket is bound to it.
00020  *
00021  *   serv = TCPServer.new("127.0.0.1", 28561)
00022  *   s = serv.accept
00023  *   s.puts Time.now
00024  *   s.close
00025  */
00026 static VALUE
00027 tcp_svr_init(int argc, VALUE *argv, VALUE sock)
00028 {
00029     VALUE hostname, port;
00030 
00031     rb_scan_args(argc, argv, "011", &hostname, &port);
00032     return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER);
00033 }
00034 
00035 /*
00036  * call-seq:
00037  *   tcpserver.accept => tcpsocket
00038  *
00039  *   TCPServer.open("127.0.0.1", 14641) {|serv|
00040  *     s = serv.accept
00041  *     s.puts Time.now
00042  *     s.close
00043  *   }
00044  *
00045  */
00046 static VALUE
00047 tcp_accept(VALUE sock)
00048 {
00049     rb_io_t *fptr;
00050     struct sockaddr_storage from;
00051     socklen_t fromlen;
00052 
00053     GetOpenFile(sock, fptr);
00054     fromlen = (socklen_t)sizeof(from);
00055     return rsock_s_accept(rb_cTCPSocket, fptr->fd,
00056                           (struct sockaddr*)&from, &fromlen);
00057 }
00058 
00059 /*
00060  * call-seq:
00061  *      tcpserver.accept_nonblock => tcpsocket
00062  *
00063  * Accepts an incoming connection using accept(2) after
00064  * O_NONBLOCK is set for the underlying file descriptor.
00065  * It returns an accepted TCPSocket for the incoming connection.
00066  *
00067  * === Example
00068  *      require 'socket'
00069  *      serv = TCPServer.new(2202)
00070  *      begin # emulate blocking accept
00071  *        sock = serv.accept_nonblock
00072  *      rescue IO::WaitReadable, Errno::EINTR
00073  *        IO.select([serv])
00074  *        retry
00075  *      end
00076  *      # sock is an accepted socket.
00077  *
00078  * Refer to Socket#accept for the exceptions that may be thrown if the call
00079  * to TCPServer#accept_nonblock fails.
00080  *
00081  * TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure,
00082  * including Errno::EWOULDBLOCK.
00083  *
00084  * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED, Errno::EPROTO,
00085  * it is extended by IO::WaitReadable.
00086  * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
00087  *
00088  * === See
00089  * * TCPServer#accept
00090  * * Socket#accept
00091  */
00092 static VALUE
00093 tcp_accept_nonblock(VALUE sock)
00094 {
00095     rb_io_t *fptr;
00096     struct sockaddr_storage from;
00097     socklen_t fromlen;
00098 
00099     GetOpenFile(sock, fptr);
00100     fromlen = (socklen_t)sizeof(from);
00101     return rsock_s_accept_nonblock(rb_cTCPSocket, fptr,
00102                                    (struct sockaddr *)&from, &fromlen);
00103 }
00104 
00105 /*
00106  * call-seq:
00107  *   tcpserver.sysaccept => file_descriptor
00108  *
00109  * Returns a file descriptor of a accepted connection.
00110  *
00111  *   TCPServer.open("127.0.0.1", 28561) {|serv|
00112  *     fd = serv.sysaccept
00113  *     s = IO.for_fd(fd)
00114  *     s.puts Time.now
00115  *     s.close
00116  *   }
00117  *
00118  */
00119 static VALUE
00120 tcp_sysaccept(VALUE sock)
00121 {
00122     rb_io_t *fptr;
00123     struct sockaddr_storage from;
00124     socklen_t fromlen;
00125 
00126     GetOpenFile(sock, fptr);
00127     fromlen = (socklen_t)sizeof(from);
00128     return rsock_s_accept(0, fptr->fd, (struct sockaddr*)&from, &fromlen);
00129 }
00130 
00131 void
00132 rsock_init_tcpserver(void)
00133 {
00134     /*
00135      * Document-class: TCPServer < TCPSocket
00136      *
00137      * TCPServer represents a TCP/IP server socket.
00138      *
00139      * A simple TCP server may look like:
00140      *
00141      *   require 'socket'
00142      *
00143      *   server = TCPServer.new 2000 # Server bind to port 2000
00144      *   loop do
00145      *     client = server.accept    # Wait for a client to connect
00146      *     client.puts "Hello !"
00147      *     client.puts "Time is #{Time.now}"
00148      *     client.close
00149      *   end
00150      *
00151      * A more usable server (serving multiple clients):
00152      *
00153      *   require 'socket'
00154      *
00155      *   server = TCPServer.new 2000
00156      *   loop do
00157      *     Thread.start(server.accept) do |client|
00158      *       client.puts "Hello !"
00159      *       client.puts "Time is #{Time.now}"
00160      *       client.close
00161      *     end
00162      *   end
00163      *
00164      */
00165     rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket);
00166     rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0);
00167     rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, 0);
00168     rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0);
00169     rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1);
00170     rb_define_method(rb_cTCPServer, "listen", rsock_sock_listen, 1); /* in socket.c */
00171 }
00172