kgio 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }