kgio 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v1.1.0.GIT
4
+ DEF_VER=v1.2.0.GIT
5
5
 
6
6
  LF='
7
7
  '
@@ -128,8 +128,8 @@ $(pkgtgz): manifest fix-perms
128
128
  @test -n "$(distdir)"
129
129
  $(RM) -r $(distdir)
130
130
  mkdir -p $(distdir)
131
- tar c `cat .manifest` | (cd $(distdir) && tar x)
132
- cd pkg && tar c $(basename $(@F)) | gzip -9 > $(@F)+
131
+ tar cf - `cat .manifest` | (cd $(distdir) && tar xf -)
132
+ cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
133
133
  mv $@+ $@
134
134
 
135
135
  package: $(pkgtgz) $(pkggem)
@@ -0,0 +1,371 @@
1
+ #include "kgio.h"
2
+ #include "missing/accept4.h"
3
+ #include "sock_for_fd.h"
4
+
5
+ static VALUE localhost;
6
+ static VALUE cClientSocket;
7
+ static VALUE cKgio_Socket;
8
+ static VALUE mSocketMethods;
9
+ static VALUE iv_kgio_addr;
10
+
11
+ #if defined(__linux__)
12
+ static int accept4_flags = SOCK_CLOEXEC;
13
+ #else /* ! linux */
14
+ static int accept4_flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
15
+ #endif /* ! linux */
16
+
17
+ struct accept_args {
18
+ int fd;
19
+ struct sockaddr *addr;
20
+ socklen_t *addrlen;
21
+ };
22
+
23
+ static VALUE set_accepted(VALUE klass, VALUE aclass)
24
+ {
25
+ VALUE tmp;
26
+
27
+ if (NIL_P(aclass))
28
+ aclass = cKgio_Socket;
29
+
30
+ tmp = rb_funcall(aclass, rb_intern("included_modules"), 0, 0);
31
+ tmp = rb_funcall(tmp, rb_intern("include?"), 1, mSocketMethods);
32
+
33
+ if (tmp != Qtrue)
34
+ rb_raise(rb_eTypeError,
35
+ "class must include Kgio::SocketMethods");
36
+
37
+ cClientSocket = aclass;
38
+
39
+ return aclass;
40
+ }
41
+
42
+ static VALUE get_accepted(VALUE klass)
43
+ {
44
+ return cClientSocket;
45
+ }
46
+
47
+ static VALUE xaccept(void *ptr)
48
+ {
49
+ struct accept_args *a = ptr;
50
+
51
+ return (VALUE)accept4(a->fd, a->addr, a->addrlen, accept4_flags);
52
+ }
53
+
54
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
55
+ # include <time.h>
56
+ /*
57
+ * Try to use a (real) blocking accept() since that can prevent
58
+ * thundering herds under Linux:
59
+ * http://www.citi.umich.edu/projects/linux-scalability/reports/accept.html
60
+ *
61
+ * So we periodically disable non-blocking, but not too frequently
62
+ * because other processes may set non-blocking (especially during
63
+ * a process upgrade) with Rainbows! concurrency model changes.
64
+ */
65
+ static int thread_accept(struct accept_args *a, int force_nonblock)
66
+ {
67
+ if (force_nonblock)
68
+ set_nonblocking(a->fd);
69
+ return (int)rb_thread_blocking_region(xaccept, a, RUBY_UBF_IO, 0);
70
+ }
71
+
72
+ static void set_blocking_or_block(int fd)
73
+ {
74
+ static time_t last_set_blocking;
75
+ time_t now = time(NULL);
76
+
77
+ if (last_set_blocking == 0) {
78
+ last_set_blocking = now;
79
+ (void)rb_io_wait_readable(fd);
80
+ } else if ((now - last_set_blocking) <= 5) {
81
+ (void)rb_io_wait_readable(fd);
82
+ } else {
83
+ int flags = fcntl(fd, F_GETFL);
84
+ if (flags == -1)
85
+ rb_sys_fail("fcntl(F_GETFL)");
86
+ if (flags & O_NONBLOCK) {
87
+ flags = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
88
+ if (flags == -1)
89
+ rb_sys_fail("fcntl(F_SETFL)");
90
+ }
91
+ last_set_blocking = now;
92
+ }
93
+ }
94
+ #else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
95
+ # include <rubysig.h>
96
+ static int thread_accept(struct accept_args *a, int force_nonblock)
97
+ {
98
+ int rv;
99
+
100
+ /* always use non-blocking accept() under 1.8 for green threads */
101
+ set_nonblocking(a->fd);
102
+ TRAP_BEG;
103
+ rv = (int)xaccept(a);
104
+ TRAP_END;
105
+ return rv;
106
+ }
107
+ #define set_blocking_or_block(fd) (void)rb_io_wait_readable(fd)
108
+ #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
109
+
110
+ static VALUE
111
+ my_accept(VALUE io, struct sockaddr *addr, socklen_t *addrlen, int nonblock)
112
+ {
113
+ int client;
114
+ struct accept_args a;
115
+
116
+ a.fd = my_fileno(io);
117
+ a.addr = addr;
118
+ a.addrlen = addrlen;
119
+ retry:
120
+ client = thread_accept(&a, nonblock);
121
+ if (client == -1) {
122
+ switch (errno) {
123
+ case EAGAIN:
124
+ if (nonblock)
125
+ return Qnil;
126
+ set_blocking_or_block(a.fd);
127
+ #ifdef ECONNABORTED
128
+ case ECONNABORTED:
129
+ #endif /* ECONNABORTED */
130
+ #ifdef EPROTO
131
+ case EPROTO:
132
+ #endif /* EPROTO */
133
+ case EINTR:
134
+ goto retry;
135
+ case ENOMEM:
136
+ case EMFILE:
137
+ case ENFILE:
138
+ #ifdef ENOBUFS
139
+ case ENOBUFS:
140
+ #endif /* ENOBUFS */
141
+ errno = 0;
142
+ rb_gc();
143
+ client = thread_accept(&a, nonblock);
144
+ }
145
+ if (client == -1) {
146
+ if (errno == EINTR)
147
+ goto retry;
148
+ rb_sys_fail("accept");
149
+ }
150
+ }
151
+ return sock_for_fd(cClientSocket, client);
152
+ }
153
+
154
+ static void in_addr_set(VALUE io, struct sockaddr_in *addr)
155
+ {
156
+ VALUE host = rb_str_new(0, INET_ADDRSTRLEN);
157
+ socklen_t addrlen = (socklen_t)INET_ADDRSTRLEN;
158
+ const char *name;
159
+
160
+ name = inet_ntop(AF_INET, &addr->sin_addr, RSTRING_PTR(host), addrlen);
161
+ if (name == NULL)
162
+ rb_sys_fail("inet_ntop");
163
+ rb_str_set_len(host, strlen(name));
164
+ rb_ivar_set(io, iv_kgio_addr, host);
165
+ }
166
+
167
+ /*
168
+ * call-seq:
169
+ *
170
+ * server = Kgio::TCPServer.new('0.0.0.0', 80)
171
+ * server.kgio_tryaccept -> Kgio::Socket or nil
172
+ *
173
+ * Initiates a non-blocking accept and returns a generic Kgio::Socket
174
+ * object with the kgio_addr attribute set to the IP address of the
175
+ * connected client on success.
176
+ *
177
+ * Returns nil on EAGAIN, and raises on other errors.
178
+ */
179
+ static VALUE tcp_tryaccept(VALUE io)
180
+ {
181
+ struct sockaddr_in addr;
182
+ socklen_t addrlen = sizeof(struct sockaddr_in);
183
+ VALUE rv = my_accept(io, (struct sockaddr *)&addr, &addrlen, 1);
184
+
185
+ if (!NIL_P(rv))
186
+ in_addr_set(rv, &addr);
187
+ return rv;
188
+ }
189
+
190
+ /*
191
+ * call-seq:
192
+ *
193
+ * server = Kgio::TCPServer.new('0.0.0.0', 80)
194
+ * server.kgio_accept -> Kgio::Socket or nil
195
+ *
196
+ * Initiates a blocking accept and returns a generic Kgio::Socket
197
+ * object with the kgio_addr attribute set to the IP address of
198
+ * the client on success.
199
+ *
200
+ * On Ruby implementations using native threads, this can use a blocking
201
+ * accept(2) (or accept4(2)) system call to avoid thundering herds.
202
+ */
203
+ static VALUE tcp_accept(VALUE io)
204
+ {
205
+ struct sockaddr_in addr;
206
+ socklen_t addrlen = sizeof(struct sockaddr_in);
207
+ VALUE rv = my_accept(io, (struct sockaddr *)&addr, &addrlen, 0);
208
+
209
+ in_addr_set(rv, &addr);
210
+ return rv;
211
+ }
212
+
213
+ /*
214
+ * call-seq:
215
+ *
216
+ * server = Kgio::UNIXServer.new("/path/to/unix/socket")
217
+ * server.kgio_tryaccept -> Kgio::Socket or nil
218
+ *
219
+ * Initiates a non-blocking accept and returns a generic Kgio::Socket
220
+ * object with the kgio_addr attribute set (to the value of
221
+ * Kgio::LOCALHOST) on success.
222
+ *
223
+ * Returns nil on EAGAIN, and raises on other errors.
224
+ */
225
+ static VALUE unix_tryaccept(VALUE io)
226
+ {
227
+ VALUE rv = my_accept(io, NULL, NULL, 1);
228
+
229
+ if (!NIL_P(rv))
230
+ rb_ivar_set(rv, iv_kgio_addr, localhost);
231
+ return rv;
232
+ }
233
+
234
+ /*
235
+ * call-seq:
236
+ *
237
+ * server = Kgio::UNIXServer.new("/path/to/unix/socket")
238
+ * server.kgio_accept -> Kgio::Socket or nil
239
+ *
240
+ * Initiates a blocking accept and returns a generic Kgio::Socket
241
+ * object with the kgio_addr attribute set (to the value of
242
+ * Kgio::LOCALHOST) on success.
243
+ *
244
+ * On Ruby implementations using native threads, this can use a blocking
245
+ * accept(2) (or accept4(2)) system call to avoid thundering herds.
246
+ */
247
+ static VALUE unix_accept(VALUE io)
248
+ {
249
+ VALUE rv = my_accept(io, NULL, NULL, 0);
250
+
251
+ rb_ivar_set(rv, iv_kgio_addr, localhost);
252
+ return rv;
253
+ }
254
+
255
+ /*
256
+ * call-seq:
257
+ *
258
+ * Kgio.accept_cloexec? -> true or false
259
+ *
260
+ * Returns true if newly accepted Kgio::Sockets are created with the
261
+ * FD_CLOEXEC file descriptor flag, false if not.
262
+ */
263
+ static VALUE get_cloexec(VALUE mod)
264
+ {
265
+ return (accept4_flags & SOCK_CLOEXEC) == SOCK_CLOEXEC ? Qtrue : Qfalse;
266
+ }
267
+
268
+ /*
269
+ *
270
+ * call-seq:
271
+ *
272
+ * Kgio.accept_nonblock? -> true or false
273
+ *
274
+ * Returns true if newly accepted Kgio::Sockets are created with the
275
+ * O_NONBLOCK file status flag, false if not.
276
+ */
277
+ static VALUE get_nonblock(VALUE mod)
278
+ {
279
+ return (accept4_flags & SOCK_NONBLOCK)==SOCK_NONBLOCK ? Qtrue : Qfalse;
280
+ }
281
+
282
+ /*
283
+ * call-seq:
284
+ *
285
+ * Kgio.accept_cloexec = true
286
+ * Kgio.accept_clocexec = false
287
+ *
288
+ * Sets whether or not Kgio::Socket objects created by
289
+ * TCPServer#kgio_accept,
290
+ * TCPServer#kgio_tryaccept,
291
+ * UNIXServer#kgio_accept,
292
+ * and UNIXServer#kgio_tryaccept
293
+ * are created with the FD_CLOEXEC file descriptor flag.
294
+ *
295
+ * This is on by default, as there is little reason to deal to enable
296
+ * it for client sockets on a socket server.
297
+ */
298
+ static VALUE set_cloexec(VALUE mod, VALUE boolean)
299
+ {
300
+ switch (TYPE(boolean)) {
301
+ case T_TRUE:
302
+ accept4_flags |= SOCK_CLOEXEC;
303
+ return boolean;
304
+ case T_FALSE:
305
+ accept4_flags &= ~SOCK_CLOEXEC;
306
+ return boolean;
307
+ }
308
+ rb_raise(rb_eTypeError, "not true or false");
309
+ return Qnil;
310
+ }
311
+
312
+ /*
313
+ * call-seq:
314
+ *
315
+ * Kgio.accept_nonblock = true
316
+ * Kgio.accept_nonblock = false
317
+ *
318
+ * Sets whether or not Kgio::Socket objects created by
319
+ * TCPServer#kgio_accept,
320
+ * TCPServer#kgio_tryaccept,
321
+ * UNIXServer#kgio_accept,
322
+ * and UNIXServer#kgio_tryaccept
323
+ * are created with the O_NONBLOCK file status flag.
324
+ *
325
+ * This defaults to +false+ for GNU/Linux where MSG_DONTWAIT is
326
+ * available (and on newer GNU/Linux, accept4() may also set
327
+ * the non-blocking flag. This defaults to +true+ on non-GNU/Linux
328
+ * systems.
329
+ */
330
+ static VALUE set_nonblock(VALUE mod, VALUE boolean)
331
+ {
332
+ switch (TYPE(boolean)) {
333
+ case T_TRUE:
334
+ accept4_flags |= SOCK_NONBLOCK;
335
+ return boolean;
336
+ case T_FALSE:
337
+ accept4_flags &= ~SOCK_NONBLOCK;
338
+ return boolean;
339
+ }
340
+ rb_raise(rb_eTypeError, "not true or false");
341
+ return Qnil;
342
+ }
343
+
344
+ void init_kgio_accept(VALUE mKgio)
345
+ {
346
+ VALUE cUNIXServer, cTCPServer;
347
+
348
+ localhost = rb_const_get(mKgio, rb_intern("LOCALHOST"));
349
+ cKgio_Socket = rb_const_get(mKgio, rb_intern("Socket"));
350
+ cClientSocket = cKgio_Socket;
351
+ mSocketMethods = rb_const_get(mKgio, rb_intern("SocketMethods"));
352
+
353
+ rb_define_singleton_method(mKgio, "accept_cloexec?", get_cloexec, 0);
354
+ rb_define_singleton_method(mKgio, "accept_cloexec=", set_cloexec, 1);
355
+ rb_define_singleton_method(mKgio, "accept_nonblock?", get_nonblock, 0);
356
+ rb_define_singleton_method(mKgio, "accept_nonblock=", set_nonblock, 1);
357
+ rb_define_singleton_method(mKgio, "accept_class=", set_accepted, 1);
358
+ rb_define_singleton_method(mKgio, "accept_class", get_accepted, 0);
359
+
360
+ cUNIXServer = rb_const_get(rb_cObject, rb_intern("UNIXServer"));
361
+ cUNIXServer = rb_define_class_under(mKgio, "UNIXServer", cUNIXServer);
362
+ rb_define_method(cUNIXServer, "kgio_tryaccept", unix_tryaccept, 0);
363
+ rb_define_method(cUNIXServer, "kgio_accept", unix_accept, 0);
364
+
365
+ cTCPServer = rb_const_get(rb_cObject, rb_intern("TCPServer"));
366
+ cTCPServer = rb_define_class_under(mKgio, "TCPServer", cTCPServer);
367
+ rb_define_method(cTCPServer, "kgio_tryaccept", tcp_tryaccept, 0);
368
+ rb_define_method(cTCPServer, "kgio_accept", tcp_accept, 0);
369
+ init_sock_for_fd();
370
+ iv_kgio_addr = rb_intern("@kgio_addr");
371
+ }
@@ -0,0 +1,256 @@
1
+ #include "kgio.h"
2
+ #include "sock_for_fd.h"
3
+
4
+ static void close_fail(int fd, const char *msg)
5
+ {
6
+ int saved_errno = errno;
7
+ (void)close(fd);
8
+ errno = saved_errno;
9
+ rb_sys_fail(msg);
10
+ }
11
+
12
+ #ifdef SOCK_NONBLOCK
13
+ # define MY_SOCK_STREAM (SOCK_STREAM|SOCK_NONBLOCK)
14
+ #else
15
+ # define MY_SOCK_STREAM SOCK_STREAM
16
+ #endif /* ! SOCK_NONBLOCK */
17
+
18
+ static VALUE
19
+ my_connect(VALUE klass, int io_wait, int domain, void *addr, socklen_t addrlen)
20
+ {
21
+ int fd = socket(domain, MY_SOCK_STREAM, 0);
22
+
23
+ if (fd == -1) {
24
+ switch (errno) {
25
+ case EMFILE:
26
+ case ENFILE:
27
+ #ifdef ENOBUFS
28
+ case ENOBUFS:
29
+ #endif /* ENOBUFS */
30
+ errno = 0;
31
+ rb_gc();
32
+ fd = socket(domain, MY_SOCK_STREAM, 0);
33
+ }
34
+ if (fd == -1)
35
+ rb_sys_fail("socket");
36
+ }
37
+
38
+ #ifndef SOCK_NONBLOCK
39
+ if (fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK) == -1)
40
+ close_fail(fd, "fcntl(F_SETFL, O_RDWR | O_NONBLOCK)");
41
+ #endif /* SOCK_NONBLOCK */
42
+
43
+ if (connect(fd, addr, addrlen) == -1) {
44
+ if (errno == EINPROGRESS) {
45
+ VALUE io = sock_for_fd(klass, fd);
46
+
47
+ if (io_wait) {
48
+ errno = EAGAIN;
49
+ kgio_wait_writable(io, fd);
50
+ }
51
+ return io;
52
+ }
53
+ close_fail(fd, "connect");
54
+ }
55
+ return sock_for_fd(klass, fd);
56
+ }
57
+
58
+ static VALUE tcp_connect(VALUE klass, VALUE ip, VALUE port, int io_wait)
59
+ {
60
+ struct sockaddr_in addr = { 0 };
61
+
62
+ addr.sin_family = AF_INET;
63
+ addr.sin_port = htons((unsigned short)NUM2INT(port));
64
+
65
+ switch (inet_pton(AF_INET, StringValuePtr(ip), &addr.sin_addr)) {
66
+ case 1:
67
+ return my_connect(klass, io_wait, PF_INET, &addr, sizeof(addr));
68
+ case -1:
69
+ rb_sys_fail("inet_pton");
70
+ }
71
+ rb_raise(rb_eArgError, "invalid address: %s", StringValuePtr(ip));
72
+
73
+ return Qnil;
74
+ }
75
+
76
+ /*
77
+ * call-seq:
78
+ *
79
+ * Kgio::TCPSocket.new('127.0.0.1', 80) -> socket
80
+ *
81
+ * Creates a new Kgio::TCPSocket object and initiates a
82
+ * non-blocking connection.
83
+ *
84
+ * This may block and call any method assigned to Kgio.wait_writable.
85
+ *
86
+ * Unlike the TCPSocket.new in Ruby, this does NOT perform DNS
87
+ * lookups (which is subject to a different set of timeouts and
88
+ * best handled elsewhere).
89
+ */
90
+ static VALUE kgio_tcp_connect(VALUE klass, VALUE ip, VALUE port)
91
+ {
92
+ return tcp_connect(klass, ip, port, 1);
93
+ }
94
+
95
+ /*
96
+ * call-seq:
97
+ *
98
+ * Kgio::TCPSocket.start('127.0.0.1', 80) -> socket
99
+ *
100
+ * Creates a new Kgio::TCPSocket object and initiates a
101
+ * non-blocking connection. The caller should select/poll
102
+ * on the socket for writability before attempting to write
103
+ * or optimistically attempt a write and handle Kgio::WaitWritable
104
+ * or Errno::EAGAIN.
105
+ *
106
+ * Unlike the TCPSocket.new in Ruby, this does NOT perform DNS
107
+ * lookups (which is subject to a different set of timeouts and
108
+ * best handled elsewhere).
109
+ */
110
+ static VALUE kgio_tcp_start(VALUE klass, VALUE ip, VALUE port)
111
+ {
112
+ return tcp_connect(klass, ip, port, 0);
113
+ }
114
+
115
+ static VALUE unix_connect(VALUE klass, VALUE path, int io_wait)
116
+ {
117
+ struct sockaddr_un addr = { 0 };
118
+ long len;
119
+
120
+ StringValue(path);
121
+ len = RSTRING_LEN(path);
122
+ if (sizeof(addr.sun_path) <= len)
123
+ rb_raise(rb_eArgError,
124
+ "too long unix socket path (max: %dbytes)",
125
+ (int)sizeof(addr.sun_path)-1);
126
+
127
+ memcpy(addr.sun_path, RSTRING_PTR(path), len);
128
+ addr.sun_family = AF_UNIX;
129
+
130
+ return my_connect(klass, io_wait, PF_UNIX, &addr, sizeof(addr));
131
+ }
132
+
133
+ /*
134
+ * call-seq:
135
+ *
136
+ * Kgio::UNIXSocket.new("/path/to/unix/socket") -> socket
137
+ *
138
+ * Creates a new Kgio::UNIXSocket object and initiates a
139
+ * non-blocking connection.
140
+ *
141
+ * This may block and call any method assigned to Kgio.wait_writable.
142
+ */
143
+ static VALUE kgio_unix_connect(VALUE klass, VALUE path)
144
+ {
145
+ return unix_connect(klass, path, 1);
146
+ }
147
+
148
+ /*
149
+ * call-seq:
150
+ *
151
+ * Kgio::UNIXSocket.start("/path/to/unix/socket") -> socket
152
+ *
153
+ * Creates a new Kgio::UNIXSocket object and initiates a
154
+ * non-blocking connection. The caller should select/poll
155
+ * on the socket for writability before attempting to write
156
+ * or optimistically attempt a write and handle Kgio::WaitWritable
157
+ * or Errno::EAGAIN.
158
+ */
159
+ static VALUE kgio_unix_start(VALUE klass, VALUE path)
160
+ {
161
+ return unix_connect(klass, path, 0);
162
+ }
163
+
164
+ static VALUE stream_connect(VALUE klass, VALUE addr, int io_wait)
165
+ {
166
+ int domain;
167
+ socklen_t addrlen;
168
+ struct sockaddr *sockaddr;
169
+
170
+ if (TYPE(addr) == T_STRING) {
171
+ sockaddr = (struct sockaddr *)(RSTRING_PTR(addr));
172
+ addrlen = (socklen_t)RSTRING_LEN(addr);
173
+ } else {
174
+ rb_raise(rb_eTypeError, "invalid address");
175
+ }
176
+ switch (((struct sockaddr_in *)(sockaddr))->sin_family) {
177
+ case AF_UNIX: domain = PF_UNIX; break;
178
+ case AF_INET: domain = PF_INET; break;
179
+ #ifdef AF_INET6 /* IPv6 support incomplete */
180
+ case AF_INET6: domain = PF_INET6; break;
181
+ #endif /* AF_INET6 */
182
+ default:
183
+ rb_raise(rb_eArgError, "invalid address family");
184
+ }
185
+
186
+ return my_connect(klass, io_wait, domain, sockaddr, addrlen);
187
+ }
188
+
189
+ /* call-seq:
190
+ *
191
+ * addr = Socket.pack_sockaddr_in(80, 'example.com')
192
+ * Kgio::Socket.connect(addr) -> socket
193
+ *
194
+ * addr = Socket.pack_sockaddr_un("/path/to/unix/socket")
195
+ * Kgio::Socket.connect(addr) -> socket
196
+ *
197
+ * Creates a generic Kgio::Socket object and initiates a
198
+ * non-blocking connection.
199
+ *
200
+ * This may block and call any method assigned to Kgio.wait_writable.
201
+ */
202
+ static VALUE kgio_connect(VALUE klass, VALUE addr)
203
+ {
204
+ return stream_connect(klass, addr, 1);
205
+ }
206
+
207
+ /* call-seq:
208
+ *
209
+ * addr = Socket.pack_sockaddr_in(80, 'example.com')
210
+ * Kgio::Socket.start(addr) -> socket
211
+ *
212
+ * addr = Socket.pack_sockaddr_un("/path/to/unix/socket")
213
+ * Kgio::Socket.start(addr) -> socket
214
+ *
215
+ * Creates a generic Kgio::Socket object and initiates a
216
+ * non-blocking connection. The caller should select/poll
217
+ * on the socket for writability before attempting to write
218
+ * or optimistically attempt a write and handle Kgio::WaitWritable
219
+ * or Errno::EAGAIN.
220
+ */
221
+ static VALUE kgio_start(VALUE klass, VALUE addr)
222
+ {
223
+ return stream_connect(klass, addr, 0);
224
+ }
225
+
226
+ void init_kgio_connect(VALUE mKgio)
227
+ {
228
+ VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
229
+ VALUE mSocketMethods = rb_const_get(mKgio, rb_intern("SocketMethods"));
230
+ VALUE cKgio_Socket, cTCPSocket, cUNIXSocket;
231
+
232
+ /*
233
+ * Document-class: Kgio::Socket
234
+ *
235
+ * A generic socket class with Kgio::SocketMethods included.
236
+ * This is returned by all Kgio methods that accept(2) a connected
237
+ * stream socket.
238
+ */
239
+ cKgio_Socket = rb_define_class_under(mKgio, "Socket", cSocket);
240
+ rb_include_module(cKgio_Socket, mSocketMethods);
241
+ rb_define_singleton_method(cKgio_Socket, "new", kgio_connect, 1);
242
+ rb_define_singleton_method(cKgio_Socket, "start", kgio_start, 1);
243
+
244
+ cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
245
+ cTCPSocket = rb_define_class_under(mKgio, "TCPSocket", cTCPSocket);
246
+ rb_include_module(cTCPSocket, mSocketMethods);
247
+ rb_define_singleton_method(cTCPSocket, "new", kgio_tcp_connect, 2);
248
+ rb_define_singleton_method(cTCPSocket, "start", kgio_tcp_start, 2);
249
+
250
+ cUNIXSocket = rb_const_get(rb_cObject, rb_intern("UNIXSocket"));
251
+ cUNIXSocket = rb_define_class_under(mKgio, "UNIXSocket", cUNIXSocket);
252
+ rb_include_module(cUNIXSocket, mSocketMethods);
253
+ rb_define_singleton_method(cUNIXSocket, "new", kgio_unix_connect, 1);
254
+ rb_define_singleton_method(cUNIXSocket, "start", kgio_unix_start, 1);
255
+ init_sock_for_fd();
256
+ }