summaryrefslogtreecommitdiff
path: root/jni/ruby/ext/socket/unixserver.c
blob: df9849703b3b5236776a7c8f5cfe783a087e5ba4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/************************************************

  unixserver.c -

  created at: Thu Mar 31 12:21:29 JST 1994

  Copyright (C) 1993-2007 Yukihiro Matsumoto

************************************************/

#include "rubysocket.h"

#ifdef HAVE_SYS_UN_H
/*
 * call-seq:
 *   UNIXServer.new(path) => unixserver
 *
 * Creates a new UNIX server socket bound to _path_.
 *
 *   serv = UNIXServer.new("/tmp/sock")
 *   s = serv.accept
 *   p s.read
 */
static VALUE
unix_svr_init(VALUE sock, VALUE path)
{
    return rsock_init_unixsock(sock, path, 1);
}

/*
 * call-seq:
 *   unixserver.accept => unixsocket
 *
 * Accepts an incoming connection.
 * It returns a new UNIXSocket object.
 *
 *   UNIXServer.open("/tmp/sock") {|serv|
 *     UNIXSocket.open("/tmp/sock") {|c|
 *       s = serv.accept
 *       s.puts "hi"
 *       s.close
 *       p c.read #=> "hi\n"
 *     }
 *   }
 *
 */
static VALUE
unix_accept(VALUE sock)
{
    rb_io_t *fptr;
    struct sockaddr_un from;
    socklen_t fromlen;

    GetOpenFile(sock, fptr);
    fromlen = (socklen_t)sizeof(struct sockaddr_un);
    return rsock_s_accept(rb_cUNIXSocket, fptr->fd,
                          (struct sockaddr*)&from, &fromlen);
}

/*
 * call-seq:
 *   unixserver.accept_nonblock => unixsocket
 *
 * Accepts an incoming connection using accept(2) after
 * O_NONBLOCK is set for the underlying file descriptor.
 * It returns an accepted UNIXSocket for the incoming connection.
 *
 * === Example
 *      require 'socket'
 *      serv = UNIXServer.new("/tmp/sock")
 *      begin # emulate blocking accept
 *        sock = serv.accept_nonblock
 *      rescue IO::WaitReadable, Errno::EINTR
 *        IO.select([serv])
 *        retry
 *      end
 *      # sock is an accepted socket.
 *
 * Refer to Socket#accept for the exceptions that may be thrown if the call
 * to UNIXServer#accept_nonblock fails.
 *
 * UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure,
 * including Errno::EWOULDBLOCK.
 *
 * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO,
 * it is extended by IO::WaitReadable.
 * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
 *
 * === See
 * * UNIXServer#accept
 * * Socket#accept
 */
static VALUE
unix_accept_nonblock(VALUE sock)
{
    rb_io_t *fptr;
    struct sockaddr_un from;
    socklen_t fromlen;

    GetOpenFile(sock, fptr);
    fromlen = (socklen_t)sizeof(from);
    return rsock_s_accept_nonblock(rb_cUNIXSocket, fptr,
                                   (struct sockaddr *)&from, &fromlen);
}

/*
 * call-seq:
 *   unixserver.sysaccept => file_descriptor
 *
 * Accepts a new connection.
 * It returns the new file descriptor which is an integer.
 *
 *   UNIXServer.open("/tmp/sock") {|serv|
 *     UNIXSocket.open("/tmp/sock") {|c|
 *       fd = serv.sysaccept
 *       s = IO.new(fd)
 *       s.puts "hi"
 *       s.close
 *       p c.read #=> "hi\n"
 *     }
 *   }
 *
 */
static VALUE
unix_sysaccept(VALUE sock)
{
    rb_io_t *fptr;
    struct sockaddr_un from;
    socklen_t fromlen;

    GetOpenFile(sock, fptr);
    fromlen = (socklen_t)sizeof(struct sockaddr_un);
    return rsock_s_accept(0, fptr->fd, (struct sockaddr*)&from, &fromlen);
}

#endif

void
rsock_init_unixserver(void)
{
#ifdef HAVE_SYS_UN_H
    /*
     * Document-class: UNIXServer < UNIXSocket
     *
     * UNIXServer represents a UNIX domain stream server socket.
     *
     */
    rb_cUNIXServer = rb_define_class("UNIXServer", rb_cUNIXSocket);
    rb_define_method(rb_cUNIXServer, "initialize", unix_svr_init, 1);
    rb_define_method(rb_cUNIXServer, "accept", unix_accept, 0);
    rb_define_method(rb_cUNIXServer, "accept_nonblock", unix_accept_nonblock, 0);
    rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, 0);
    rb_define_method(rb_cUNIXServer, "listen", rsock_sock_listen, 1); /* in socket.c */
#endif
}