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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7