kgio 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/ISSUES ADDED
@@ -0,0 +1,36 @@
1
+ = Issues
2
+
3
+ The Unicorn {mailing list}[mailto:mongrel-unicorn@rubyforge.org] is the best
4
+ place to report bugs, submit patches and/or obtain support after you
5
+ have searched the mailing list archives and
6
+ {documentation}[http://unicorn.bogomips.org/kgio].
7
+
8
+ * No subscription is needed to post to the mailing list,
9
+ let us know that we need to Cc: replies to you if you're unsubscribed.
10
+ * Do not {top post}[http://catb.org/jargon/html/T/top-post.html] in replies
11
+ * Quote only the relevant portions of the message you're replying to
12
+ * Do not send HTML mail
13
+
14
+ If your issue is of a sensitive nature or you're just shy in public,
15
+ then feel free to email us privately at mailto:unicorn@bogomips.org
16
+ instead and your issue will be handled discreetly.
17
+
18
+ If you don't get a response within a few days, we may have forgotten
19
+ about it so feel free to ask again.
20
+
21
+ == Submitting Patches
22
+
23
+ See the HACKING document (and additionally, the
24
+ Documentation/SubmittingPatches document distributed with git) on
25
+ guidelines for patch submission.
26
+
27
+ == Mailing List Info
28
+
29
+ * subscribe: http://rubyforge.org/mailman/listinfo/mongrel-unicorn
30
+ * post: mailto:mongrel-unicorn@rubyforge.org
31
+ * private: mailto:unicorn@bogomips.org
32
+
33
+ == Mailing List Archives
34
+
35
+ * nntp://news.gmane.org/gmane.comp.lang.ruby.unicorn.general
36
+ * http://rubyforge.org/pipermail/mongrel-unicorn
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ kgio is copyrighted Free Software by all contributors, see logs in
2
+ revision control for names and email addresses of all of them.
3
+
4
+ You can redistribute it and/or modify it under the terms of the GNU
5
+ Lesser General Public License (LGPL) as published by the Free Software
6
+ Foundation, version {2.1}[http://www.gnu.org/licenses/lgpl-2.1.txt] or
7
+ or {3}[http://www.gnu.org/licenses/lgpl-3.0.txt] (see link:COPYING).
8
+ The kgio project leader (Eric Wong) reserves the right to
9
+ relicense kgio under future versions of the LGPL.
10
+
11
+ kgio is distributed in the hope that it will be useful, but WITHOUT
12
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14
+ License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License
17
+ along with the GNU C Library; if not, write to the Free Software
18
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
data/README ADDED
@@ -0,0 +1,68 @@
1
+ = kgio - kinder, gentler I/O for Ruby
2
+
3
+ kgio provides non-blocking I/O methods for Ruby without raising
4
+ exceptions on EAGAIN and EINPROGRESS. It is intended for use with the
5
+ Unicorn and Rainbows! Rack servers, but may be used by other
6
+ applications.
7
+
8
+ == Features
9
+
10
+ * Can avoid expensive exceptions on common EAGAIN/EINPROGRESS errors,
11
+ returning Kgio::WaitReadable or Kgio::WaitWritable instead.
12
+ These exceptions got more expensive to hit under Ruby 1.9.2
13
+ (but should be fixed in Ruby 1.9.3 to 1.9.1 performance levels)
14
+
15
+ * Returns the unwritten portion of the string on partial writes,
16
+ making it ideal for buffering unwritten data.
17
+
18
+ * May be assigned Kgio.wait_writable= and Kgio.wait_readable=
19
+ methods to allow socket/pipe objects to make custom callbacks
20
+ (such as adding the file descriptor to a poll set and yielding
21
+ the current Fiber).
22
+
23
+ * Uses
24
+ {accept4}[http://kernel.org/doc/man-pages/online/pages/man2/accept4.2.html]
25
+ on new GNU/Linux systems to avoid unnecessary fcntl() calls
26
+
27
+ * Uses MSG_DONTWAIT on GNU/Linux to further avoid unnecessary fcntl() calls
28
+
29
+ * Compatible with existing Ruby IO objects and Ruby threading.
30
+
31
+ == Install
32
+
33
+ The library consists of a C extension so you'll need a C compiler
34
+ and Ruby development libraries/headers.
35
+
36
+ You may download the tarball from the Mongrel project page on Rubyforge
37
+ and run setup.rb after unpacking it:
38
+
39
+ http://rubyforge.org/frs/?group_id=8977
40
+
41
+ You may also install it via RubyGems on Gemcutter:
42
+
43
+ gem install kgio
44
+
45
+ You can get the latest source via git from the following locations
46
+ (these versions may not be stable):
47
+
48
+ git://git.bogomips.org/kgio.git
49
+ git://repo.or.cz/kgio.git (mirror)
50
+
51
+ You may browse the code from the web and download the latest snapshot
52
+ tarballs here:
53
+
54
+ * http://git.bogomips.org/cgit/kgio.git (cgit)
55
+ * http://repo.or.cz/w/kgio.git (gitweb)
56
+
57
+ See the HACKING guide on how to contribute and build prerelease gems
58
+ from git.
59
+
60
+ == Contact
61
+
62
+ All feedback (bug reports, user/development dicussion, patches, pull
63
+ requests) go to the mailing list/newsgroup. See the ISSUES document for
64
+ information on the
65
+ {Unicorn mailing list}[mailto:mongrel-unicorn@rubyforge.org].
66
+
67
+ For the latest on kgio releases, you may check our NEWS page (and
68
+ subscribe to our Atom feed).
@@ -0,0 +1,169 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # most tasks are in the GNUmakefile which offers better parallelism
4
+
5
+ def tags
6
+ timefmt = '%Y-%m-%dT%H:%M:%SZ'
7
+ @tags ||= `git tag -l`.split(/\n/).map do |tag|
8
+ if %r{\Av[\d\.]+\z} =~ tag
9
+ header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
10
+ header = header.split(/\n/)
11
+ tagger = header.grep(/\Atagger /).first
12
+ body ||= "initial"
13
+ {
14
+ :time => Time.at(tagger.split(/ /)[-2].to_i).utc.strftime(timefmt),
15
+ :tagger_name => %r{^tagger ([^<]+)}.match(tagger)[1].strip,
16
+ :tagger_email => %r{<([^>]+)>}.match(tagger)[1].strip,
17
+ :id => `git rev-parse refs/tags/#{tag}`.chomp!,
18
+ :tag => tag,
19
+ :subject => subject,
20
+ :body => body,
21
+ }
22
+ end
23
+ end.compact.sort { |a,b| b[:time] <=> a[:time] }
24
+ end
25
+
26
+ cgit_url = "http://git.bogomips.org/cgit/kgio.git"
27
+ git_url = ENV['GIT_URL'] || 'git://git.bogomips.org/kgio.git'
28
+ web_url = "http://unicorn.bogomips.org/kgio"
29
+
30
+ desc 'prints news as an Atom feed'
31
+ task :news_atom do
32
+ require 'nokogiri'
33
+ new_tags = tags[0,10]
34
+ puts(Nokogiri::XML::Builder.new do
35
+ feed :xmlns => "http://www.w3.org/2005/Atom" do
36
+ id! "#{web_url}NEWS.atom.xml"
37
+ title "kgio news"
38
+ subtitle "socket methods using MSG_DONTWAIT and more"
39
+ link! :rel => "alternate", :type => "text/html",
40
+ :href => "#{web_url}NEWS.html"
41
+ updated(new_tags.empty? ? "1970-01-01T00:00:00Z" : new_tags.first[:time])
42
+ new_tags.each do |tag|
43
+ entry do
44
+ title tag[:subject]
45
+ updated tag[:time]
46
+ published tag[:time]
47
+ author {
48
+ name tag[:tagger_name]
49
+ email tag[:tagger_email]
50
+ }
51
+ url = "#{cgit_url}/tag/?id=#{tag[:tag]}"
52
+ link! :rel => "alternate", :type => "text/html", :href =>url
53
+ id! url
54
+ message_only = tag[:body].split(/\n.+\(\d+\):\n {6}/s).first.strip
55
+ content({:type =>:text}, message_only)
56
+ content(:type =>:xhtml) { pre tag[:body] }
57
+ end
58
+ end
59
+ end
60
+ end.to_xml)
61
+ end
62
+
63
+ desc 'prints RDoc-formatted news'
64
+ task :news_rdoc do
65
+ tags.each do |tag|
66
+ time = tag[:time].tr!('T', ' ').gsub!(/:\d\dZ/, ' UTC')
67
+ puts "=== #{tag[:tag].sub(/^v/, '')} / #{time}"
68
+ puts ""
69
+
70
+ body = tag[:body]
71
+ puts tag[:body].gsub(/^/sm, " ").gsub(/[ \t]+$/sm, "")
72
+ puts ""
73
+ end
74
+ end
75
+
76
+ desc "print release changelog for Rubyforge"
77
+ task :release_changes do
78
+ version = ENV['VERSION'] or abort "VERSION= needed"
79
+ version = "v#{version}"
80
+ vtags = tags.map { |tag| tag[:tag] =~ /\Av/ and tag[:tag] }.sort
81
+ prev = vtags[vtags.index(version) - 1]
82
+ if prev
83
+ system('git', 'diff', '--stat', prev, version) or abort $?
84
+ puts ""
85
+ system('git', 'log', "#{prev}..#{version}") or abort $?
86
+ else
87
+ system('git', 'log', version) or abort $?
88
+ end
89
+ end
90
+
91
+ desc "print release notes for Rubyforge"
92
+ task :release_notes do
93
+ spec = Gem::Specification.load('kgio.gemspec')
94
+ puts spec.description.strip
95
+ puts ""
96
+ puts "* #{spec.homepage}"
97
+ puts "* #{spec.email}"
98
+ puts "* #{git_url}"
99
+
100
+ _, _, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
101
+ print "\nChanges:\n\n"
102
+ puts body
103
+ end
104
+
105
+ desc "post news article to rubyforge"
106
+ task :publish_news do
107
+ require 'rubyforge'
108
+ spec = Gem::Specification.load('kgio.gemspec')
109
+ tmp = Tempfile.new('rf-news')
110
+ _, subject, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
111
+ tmp.puts subject
112
+ tmp.puts
113
+ tmp.puts spec.description.strip
114
+ tmp.puts ""
115
+ tmp.puts "* #{spec.homepage}"
116
+ tmp.puts "* #{spec.email}"
117
+ tmp.puts "* #{git_url}"
118
+ tmp.print "\nChanges:\n\n"
119
+ tmp.puts body
120
+ tmp.flush
121
+ system(ENV["VISUAL"], tmp.path) or abort "#{ENV["VISUAL"]} failed: #$?"
122
+ msg = File.readlines(tmp.path)
123
+ subject = msg.shift
124
+ blank = msg.shift
125
+ blank == "\n" or abort "no newline after subject!"
126
+ subject.strip!
127
+ body = msg.join("").strip!
128
+
129
+ rf = RubyForge.new.configure
130
+ rf.login
131
+ rf.post_news('rainbows', subject, body)
132
+ end
133
+
134
+ desc "post to RAA"
135
+ task :raa_update do
136
+ require 'net/http'
137
+ require 'net/netrc'
138
+ rc = Net::Netrc.locate('kgio-raa') or abort "~/.netrc not found"
139
+ password = rc.password
140
+
141
+ s = Gem::Specification.load('kgio.gemspec')
142
+ desc = [ s.description.strip ]
143
+ desc << ""
144
+ desc << "* #{s.email}"
145
+ desc << "* #{git_url}"
146
+ desc << "* #{cgit_url}"
147
+ desc = desc.join("\n")
148
+ uri = URI.parse('http://raa.ruby-lang.org/regist.rhtml')
149
+ form = {
150
+ :name => s.name,
151
+ :short_description => s.summary,
152
+ :version => s.version.to_s,
153
+ :status => 'experimental',
154
+ :owner => s.authors.first,
155
+ :email => s.email,
156
+ :category_major => 'Library',
157
+ :category_minor => 'System',
158
+ :url => s.homepage,
159
+ :download => 'http://rubyforge.org/frs/?group_id=8977',
160
+ :license => "Ruby's",
161
+ :description_style => 'Plain',
162
+ :description => desc,
163
+ :pass => password,
164
+ :submit => 'Update',
165
+ }
166
+ res = Net::HTTP.post_form(uri, form)
167
+ p res
168
+ puts res.body
169
+ end
data/TODO ADDED
@@ -0,0 +1 @@
1
+ * SSL/TLS support with SNI
@@ -0,0 +1,21 @@
1
+ require 'mkmf'
2
+ $CPPFLAGS << ' -D_GNU_SOURCE'
3
+
4
+ have_func('accept4', %w(sys/socket.h))
5
+ if have_header('ruby/io.h')
6
+ have_struct_member("rb_io_t", "fd", "ruby/io.h")
7
+ have_struct_member("rb_io_t", "mode", "ruby/io.h")
8
+ else
9
+ rubyio = %w(ruby.h rubyio.h)
10
+ rb_io_t = have_type("OpenFile", rubyio) ? "OpenFile" : "rb_io_t"
11
+ have_struct_member(rb_io_t, "f", rubyio)
12
+ have_struct_member(rb_io_t, "f2", rubyio)
13
+ have_struct_member(rb_io_t, "mode", rubyio)
14
+ have_func('rb_fdopen')
15
+ end
16
+ have_func('rb_io_ascii8bit_binmode')
17
+ have_func('rb_thread_blocking_region')
18
+ have_func('rb_str_set_len')
19
+
20
+ dir_config('kgio')
21
+ create_makefile('kgio_ext')
@@ -0,0 +1,1066 @@
1
+ #include <ruby.h>
2
+ #ifdef HAVE_RUBY_IO_H
3
+ # include <ruby/io.h>
4
+ #else
5
+ # include <rubyio.h>
6
+ #endif
7
+ #include <errno.h>
8
+ #include <sys/types.h>
9
+ #include <sys/socket.h>
10
+ #include <sys/un.h>
11
+ #include <netinet/in.h>
12
+ #include <fcntl.h>
13
+ #include <unistd.h>
14
+ #include <arpa/inet.h>
15
+ #include <assert.h>
16
+
17
+ #include "missing/accept4.h"
18
+ #include "missing/ancient_ruby.h"
19
+ #include "nonblock.h"
20
+ #include "my_fileno.h"
21
+ #include "sock_for_fd.h"
22
+
23
+ #if defined(__linux__)
24
+ /*
25
+ * we know MSG_DONTWAIT works properly on all stream sockets under Linux
26
+ * we can define this macro for other platforms as people care and
27
+ * notice.
28
+ */
29
+ # define USE_MSG_DONTWAIT
30
+ static int accept4_flags = A4_SOCK_CLOEXEC;
31
+ #else /* ! linux */
32
+ static int accept4_flags = A4_SOCK_CLOEXEC | A4_SOCK_NONBLOCK;
33
+ #endif /* ! linux */
34
+
35
+ static VALUE cSocket;
36
+ static VALUE localhost;
37
+ static VALUE mKgio_WaitReadable, mKgio_WaitWritable;
38
+ static ID io_wait_rd, io_wait_wr;
39
+ static ID iv_kgio_addr;
40
+
41
+ struct io_args {
42
+ VALUE io;
43
+ VALUE buf;
44
+ char *ptr;
45
+ long len;
46
+ int fd;
47
+ };
48
+
49
+ struct accept_args {
50
+ int fd;
51
+ struct sockaddr *addr;
52
+ socklen_t *addrlen;
53
+ };
54
+
55
+ static void wait_readable(VALUE io, int fd)
56
+ {
57
+ if (io_wait_rd) {
58
+ (void)rb_funcall(io, io_wait_rd, 0, 0);
59
+ } else {
60
+ if (!rb_io_wait_readable(fd))
61
+ rb_sys_fail("wait readable");
62
+ }
63
+ }
64
+
65
+ static void wait_writable(VALUE io, int fd)
66
+ {
67
+ if (io_wait_wr) {
68
+ (void)rb_funcall(io, io_wait_wr, 0, 0);
69
+ } else {
70
+ if (!rb_io_wait_writable(fd))
71
+ rb_sys_fail("wait writable");
72
+ }
73
+ }
74
+
75
+ static void prepare_read(struct io_args *a, int argc, VALUE *argv, VALUE io)
76
+ {
77
+ VALUE length;
78
+
79
+ a->io = io;
80
+ a->fd = my_fileno(io);
81
+ rb_scan_args(argc, argv, "11", &length, &a->buf);
82
+ a->len = NUM2LONG(length);
83
+ if (NIL_P(a->buf)) {
84
+ a->buf = rb_str_new(NULL, a->len);
85
+ } else {
86
+ StringValue(a->buf);
87
+ rb_str_resize(a->buf, a->len);
88
+ }
89
+ a->ptr = RSTRING_PTR(a->buf);
90
+ }
91
+
92
+ static int read_check(struct io_args *a, long n, const char *msg, int io_wait)
93
+ {
94
+ if (n == -1) {
95
+ if (errno == EINTR)
96
+ return -1;
97
+ rb_str_set_len(a->buf, 0);
98
+ if (errno == EAGAIN) {
99
+ if (io_wait) {
100
+ wait_readable(a->io, a->fd);
101
+
102
+ /* buf may be modified in other thread/fiber */
103
+ rb_str_resize(a->buf, a->len);
104
+ a->ptr = RSTRING_PTR(a->buf);
105
+ return -1;
106
+ } else {
107
+ a->buf = mKgio_WaitReadable;
108
+ return 0;
109
+ }
110
+ }
111
+ rb_sys_fail(msg);
112
+ }
113
+ rb_str_set_len(a->buf, n);
114
+ if (n == 0)
115
+ a->buf = Qnil;
116
+ return 0;
117
+ }
118
+
119
+ static VALUE my_read(int io_wait, int argc, VALUE *argv, VALUE io)
120
+ {
121
+ struct io_args a;
122
+ long n;
123
+
124
+ prepare_read(&a, argc, argv, io);
125
+ set_nonblocking(a.fd);
126
+ retry:
127
+ n = (long)read(a.fd, a.ptr, a.len);
128
+ if (read_check(&a, n, "read", io_wait) != 0)
129
+ goto retry;
130
+ return a.buf;
131
+ }
132
+
133
+ /*
134
+ * call-seq:
135
+ *
136
+ * io.kgio_read(maxlen) -> buffer
137
+ * io.kgio_read(maxlen, buffer) -> buffer
138
+ *
139
+ * Reads at most maxlen bytes from the stream socket. Returns with a
140
+ * newly allocated buffer, or may reuse an existing buffer if supplied.
141
+ *
142
+ * Calls the method assigned to Kgio.wait_readable, or blocks in a
143
+ * thread-safe manner for writability.
144
+ *
145
+ * Returns nil on EOF.
146
+ *
147
+ * This behaves like read(2) and IO#readpartial, NOT fread(3) or
148
+ * IO#read which possess read-in-full behavior.
149
+ */
150
+ static VALUE kgio_read(int argc, VALUE *argv, VALUE io)
151
+ {
152
+ return my_read(1, argc, argv, io);
153
+ }
154
+
155
+ /*
156
+ * call-seq:
157
+ *
158
+ * io.kgio_tryread(maxlen) -> buffer
159
+ * io.kgio_tryread(maxlen, buffer) -> buffer
160
+ *
161
+ * Reads at most maxlen bytes from the stream socket. Returns with a
162
+ * newly allocated buffer, or may reuse an existing buffer if supplied.
163
+ *
164
+ * Returns nil on EOF.
165
+ *
166
+ * Returns Kgio::WaitReadable if EAGAIN is encountered.
167
+ */
168
+ static VALUE kgio_tryread(int argc, VALUE *argv, VALUE io)
169
+ {
170
+ return my_read(0, argc, argv, io);
171
+ }
172
+
173
+ #ifdef USE_MSG_DONTWAIT
174
+ static VALUE my_recv(int io_wait, int argc, VALUE *argv, VALUE io)
175
+ {
176
+ struct io_args a;
177
+ long n;
178
+
179
+ prepare_read(&a, argc, argv, io);
180
+ retry:
181
+ n = (long)recv(a.fd, a.ptr, a.len, MSG_DONTWAIT);
182
+ if (read_check(&a, n, "recv", io_wait) != 0)
183
+ goto retry;
184
+ return a.buf;
185
+ }
186
+
187
+ /*
188
+ * This method may be optimized on some systems (e.g. GNU/Linux) to use
189
+ * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
190
+ * Otherwise this is the same as Kgio::PipeMethods#kgio_read
191
+ */
192
+ static VALUE kgio_recv(int argc, VALUE *argv, VALUE io)
193
+ {
194
+ return my_recv(1, argc, argv, io);
195
+ }
196
+
197
+ /*
198
+ * This method may be optimized on some systems (e.g. GNU/Linux) to use
199
+ * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
200
+ * Otherwise this is the same as Kgio::PipeMethods#kgio_tryread
201
+ */
202
+ static VALUE kgio_tryrecv(int argc, VALUE *argv, VALUE io)
203
+ {
204
+ return my_recv(0, argc, argv, io);
205
+ }
206
+ #else /* ! USE_MSG_DONTWAIT */
207
+ # define kgio_recv kgio_read
208
+ # define kgio_tryrecv kgio_tryread
209
+ #endif /* USE_MSG_DONTWAIT */
210
+
211
+ static void prepare_write(struct io_args *a, VALUE io, VALUE str)
212
+ {
213
+ a->buf = (TYPE(str) == T_STRING) ? str : rb_obj_as_string(str);
214
+ a->ptr = RSTRING_PTR(a->buf);
215
+ a->len = RSTRING_LEN(a->buf);
216
+ a->io = io;
217
+ a->fd = my_fileno(io);
218
+ }
219
+
220
+ static int write_check(struct io_args *a, long n, const char *msg, int io_wait)
221
+ {
222
+ if (a->len == n) {
223
+ done:
224
+ a->buf = Qnil;
225
+ } else if (n == -1) {
226
+ if (errno == EINTR)
227
+ return -1;
228
+ if (errno == EAGAIN) {
229
+ if (io_wait) {
230
+ long written = RSTRING_LEN(a->buf) - a->len;
231
+
232
+ wait_writable(a->io, a->fd);
233
+
234
+ /* buf may be modified in other thread/fiber */
235
+ a->len = RSTRING_LEN(a->buf) - written;
236
+ if (a->len <= 0)
237
+ goto done;
238
+ a->ptr = RSTRING_PTR(a->buf) + written;
239
+ return -1;
240
+ } else {
241
+ a->buf = mKgio_WaitWritable;
242
+ return 0;
243
+ }
244
+ }
245
+ rb_sys_fail(msg);
246
+ } else {
247
+ assert(n >= 0 && n < a->len && "write/send syscall broken?");
248
+ if (io_wait) {
249
+ a->ptr += n;
250
+ a->len -= n;
251
+ return -1;
252
+ }
253
+ a->buf = rb_str_new(a->ptr + n, a->len - n);
254
+ }
255
+ return 0;
256
+ }
257
+
258
+ static VALUE my_write(VALUE io, VALUE str, int io_wait)
259
+ {
260
+ struct io_args a;
261
+ long n;
262
+
263
+ prepare_write(&a, io, str);
264
+ set_nonblocking(a.fd);
265
+ retry:
266
+ n = (long)write(a.fd, a.ptr, a.len);
267
+ if (write_check(&a, n, "write", io_wait) != 0)
268
+ goto retry;
269
+ return a.buf;
270
+ }
271
+
272
+ /*
273
+ * call-seq:
274
+ *
275
+ * io.kgio_write(str) -> nil
276
+ *
277
+ * Returns nil when the write completes.
278
+ *
279
+ * Calls the method Kgio.wait_writable if it is set. Otherwise this
280
+ * blocks in a thread-safe manner until all data is written or a
281
+ * fatal error occurs.
282
+ */
283
+ static VALUE kgio_write(VALUE io, VALUE str)
284
+ {
285
+ return my_write(io, str, 1);
286
+ }
287
+
288
+ /*
289
+ * call-seq:
290
+ *
291
+ * io.kgio_trywrite(str) -> nil or Kgio::WaitWritable
292
+ *
293
+ * Returns nil if the write was completed in full.
294
+ *
295
+ * Returns a String containing the unwritten portion if there was a
296
+ * partial write.
297
+ *
298
+ * Returns Kgio::WaitWritable if EAGAIN is encountered.
299
+ */
300
+ static VALUE kgio_trywrite(VALUE io, VALUE str)
301
+ {
302
+ return my_write(io, str, 0);
303
+ }
304
+
305
+ #ifdef USE_MSG_DONTWAIT
306
+ /*
307
+ * This method behaves like Kgio::PipeMethods#kgio_write, except
308
+ * it will use send(2) with the MSG_DONTWAIT flag on sockets to
309
+ * avoid unnecessary calls to fcntl(2).
310
+ */
311
+ static VALUE my_send(VALUE io, VALUE str, int io_wait)
312
+ {
313
+ struct io_args a;
314
+ long n;
315
+
316
+ prepare_write(&a, io, str);
317
+ retry:
318
+ n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
319
+ if (write_check(&a, n, "send", io_wait) != 0)
320
+ goto retry;
321
+ return a.buf;
322
+ }
323
+
324
+ /*
325
+ * This method may be optimized on some systems (e.g. GNU/Linux) to use
326
+ * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
327
+ * Otherwise this is the same as Kgio::PipeMethods#kgio_write
328
+ */
329
+ static VALUE kgio_send(VALUE io, VALUE str)
330
+ {
331
+ return my_send(io, str, 1);
332
+ }
333
+
334
+ /*
335
+ * This method may be optimized on some systems (e.g. GNU/Linux) to use
336
+ * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
337
+ * Otherwise this is the same as Kgio::PipeMethods#kgio_trywrite
338
+ */
339
+ static VALUE kgio_trysend(VALUE io, VALUE str)
340
+ {
341
+ return my_send(io, str, 0);
342
+ }
343
+ #else /* ! USE_MSG_DONTWAIT */
344
+ # define kgio_send kgio_write
345
+ # define kgio_trysend kgio_trywrite
346
+ #endif /* ! USE_MSG_DONTWAIT */
347
+
348
+ /*
349
+ * call-seq:
350
+ *
351
+ * Kgio.wait_readable = :method_name
352
+ * Kgio.wait_readable = nil
353
+ *
354
+ * Sets a method for kgio_read to call when a read would block.
355
+ * This is useful for non-blocking frameworks that use Fibers,
356
+ * as the method referred to this may cause the current Fiber
357
+ * to yield execution.
358
+ *
359
+ * A special value of nil will cause Ruby to wait using the
360
+ * rb_io_wait_readable() function.
361
+ */
362
+ static VALUE set_wait_rd(VALUE mod, VALUE sym)
363
+ {
364
+ switch (TYPE(sym)) {
365
+ case T_SYMBOL:
366
+ io_wait_rd = SYM2ID(sym);
367
+ return sym;
368
+ case T_NIL:
369
+ io_wait_rd = 0;
370
+ return sym;
371
+ }
372
+ rb_raise(rb_eTypeError, "must be a symbol or nil");
373
+ return sym;
374
+ }
375
+
376
+ /*
377
+ * call-seq:
378
+ *
379
+ * Kgio.wait_writable = :method_name
380
+ * Kgio.wait_writable = nil
381
+ *
382
+ * Sets a method for kgio_write to call when a read would block.
383
+ * This is useful for non-blocking frameworks that use Fibers,
384
+ * as the method referred to this may cause the current Fiber
385
+ * to yield execution.
386
+ *
387
+ * A special value of nil will cause Ruby to wait using the
388
+ * rb_io_wait_writable() function.
389
+ */
390
+ static VALUE set_wait_wr(VALUE mod, VALUE sym)
391
+ {
392
+ switch (TYPE(sym)) {
393
+ case T_SYMBOL:
394
+ io_wait_wr = SYM2ID(sym);
395
+ return sym;
396
+ case T_NIL:
397
+ io_wait_wr = 0;
398
+ return sym;
399
+ }
400
+ rb_raise(rb_eTypeError, "must be a symbol or nil");
401
+ return sym;
402
+ }
403
+
404
+ /*
405
+ * call-seq:
406
+ *
407
+ * Kgio.wait_writable -> Symbol or nil
408
+ *
409
+ * Returns the symbolic method name of the method assigned to
410
+ * call when EAGAIN is occurs on a Kgio::PipeMethods#kgio_write
411
+ * or Kgio::SocketMethods#kgio_write call
412
+ */
413
+ static VALUE wait_wr(VALUE mod)
414
+ {
415
+ return io_wait_wr ? ID2SYM(io_wait_wr) : Qnil;
416
+ }
417
+
418
+ /*
419
+ * call-seq:
420
+ *
421
+ * Kgio.wait_readable -> Symbol or nil
422
+ *
423
+ * Returns the symbolic method name of the method assigned to
424
+ * call when EAGAIN is occurs on a Kgio::PipeMethods#kgio_read
425
+ * or Kgio::SocketMethods#kgio_read call.
426
+ */
427
+ static VALUE wait_rd(VALUE mod)
428
+ {
429
+ return io_wait_rd ? ID2SYM(io_wait_rd) : Qnil;
430
+ }
431
+
432
+ static VALUE xaccept(void *ptr)
433
+ {
434
+ struct accept_args *a = ptr;
435
+
436
+ return (VALUE)accept4(a->fd, a->addr, a->addrlen, accept4_flags);
437
+ }
438
+
439
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
440
+ # include <time.h>
441
+ /*
442
+ * Try to use a (real) blocking accept() since that can prevent
443
+ * thundering herds under Linux:
444
+ * http://www.citi.umich.edu/projects/linux-scalability/reports/accept.html
445
+ *
446
+ * So we periodically disable non-blocking, but not too frequently
447
+ * because other processes may set non-blocking (especially during
448
+ * a process upgrade) with Rainbows! concurrency model changes.
449
+ */
450
+ static int thread_accept(struct accept_args *a, int force_nonblock)
451
+ {
452
+ if (force_nonblock)
453
+ set_nonblocking(a->fd);
454
+ return (int)rb_thread_blocking_region(xaccept, a, RUBY_UBF_IO, 0);
455
+ }
456
+
457
+ static void set_blocking_or_block(int fd)
458
+ {
459
+ static time_t last_set_blocking;
460
+ time_t now = time(NULL);
461
+
462
+ if (last_set_blocking == 0) {
463
+ last_set_blocking = now;
464
+ (void)rb_io_wait_readable(fd);
465
+ } else if ((now - last_set_blocking) <= 5) {
466
+ (void)rb_io_wait_readable(fd);
467
+ } else {
468
+ int flags = fcntl(fd, F_GETFL);
469
+ if (flags == -1)
470
+ rb_sys_fail("fcntl(F_GETFL)");
471
+ if (flags & O_NONBLOCK) {
472
+ flags = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
473
+ if (flags == -1)
474
+ rb_sys_fail("fcntl(F_SETFL)");
475
+ }
476
+ last_set_blocking = now;
477
+ }
478
+ }
479
+ #else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
480
+ # include <rubysig.h>
481
+ static int thread_accept(struct accept_args *a, int force_nonblock)
482
+ {
483
+ int rv;
484
+
485
+ /* always use non-blocking accept() under 1.8 for green threads */
486
+ set_nonblocking(a->fd);
487
+ TRAP_BEG;
488
+ rv = (int)xaccept(a);
489
+ TRAP_END;
490
+ return rv;
491
+ }
492
+ #define set_blocking_or_block(fd) (void)rb_io_wait_readable(fd)
493
+ #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
494
+
495
+ static VALUE
496
+ my_accept(VALUE io, struct sockaddr *addr, socklen_t *addrlen, int nonblock)
497
+ {
498
+ int client;
499
+ struct accept_args a;
500
+
501
+ a.fd = my_fileno(io);
502
+ a.addr = addr;
503
+ a.addrlen = addrlen;
504
+ retry:
505
+ client = thread_accept(&a, nonblock);
506
+ if (client == -1) {
507
+ switch (errno) {
508
+ case EAGAIN:
509
+ if (nonblock)
510
+ return Qnil;
511
+ set_blocking_or_block(a.fd);
512
+ #ifdef ECONNABORTED
513
+ case ECONNABORTED:
514
+ #endif /* ECONNABORTED */
515
+ #ifdef EPROTO
516
+ case EPROTO:
517
+ #endif /* EPROTO */
518
+ case EINTR:
519
+ goto retry;
520
+ case ENOMEM:
521
+ case EMFILE:
522
+ case ENFILE:
523
+ #ifdef ENOBUFS
524
+ case ENOBUFS:
525
+ #endif /* ENOBUFS */
526
+ errno = 0;
527
+ rb_gc();
528
+ client = thread_accept(&a, nonblock);
529
+ }
530
+ if (client == -1) {
531
+ if (errno == EINTR)
532
+ goto retry;
533
+ rb_sys_fail("accept");
534
+ }
535
+ }
536
+ return sock_for_fd(cSocket, client);
537
+ }
538
+
539
+ static void in_addr_set(VALUE io, struct sockaddr_in *addr)
540
+ {
541
+ VALUE host = rb_str_new(0, INET_ADDRSTRLEN);
542
+ socklen_t addrlen = (socklen_t)INET_ADDRSTRLEN;
543
+ const char *name;
544
+
545
+ name = inet_ntop(AF_INET, &addr->sin_addr, RSTRING_PTR(host), addrlen);
546
+ if (name == NULL)
547
+ rb_sys_fail("inet_ntop");
548
+ rb_str_set_len(host, strlen(name));
549
+ rb_ivar_set(io, iv_kgio_addr, host);
550
+ }
551
+
552
+ /*
553
+ * call-seq:
554
+ *
555
+ * server = Kgio::TCPServer.new('0.0.0.0', 80)
556
+ * server.kgio_tryaccept -> Kgio::Socket or nil
557
+ *
558
+ * Initiates a non-blocking accept and returns a generic Kgio::Socket
559
+ * object with the kgio_addr attribute set to the IP address of the
560
+ * connected client on success.
561
+ *
562
+ * Returns nil on EAGAIN, and raises on other errors.
563
+ */
564
+ static VALUE tcp_tryaccept(VALUE io)
565
+ {
566
+ struct sockaddr_in addr;
567
+ socklen_t addrlen = sizeof(struct sockaddr_in);
568
+ VALUE rv = my_accept(io, (struct sockaddr *)&addr, &addrlen, 1);
569
+
570
+ if (!NIL_P(rv))
571
+ in_addr_set(rv, &addr);
572
+ return rv;
573
+ }
574
+
575
+ /*
576
+ * call-seq:
577
+ *
578
+ * server = Kgio::TCPServer.new('0.0.0.0', 80)
579
+ * server.kgio_accept -> Kgio::Socket or nil
580
+ *
581
+ * Initiates a blocking accept and returns a generic Kgio::Socket
582
+ * object with the kgio_addr attribute set to the IP address of
583
+ * the client on success.
584
+ *
585
+ * On Ruby implementations using native threads, this can use a blocking
586
+ * accept(2) (or accept4(2)) system call to avoid thundering herds.
587
+ */
588
+ static VALUE tcp_accept(VALUE io)
589
+ {
590
+ struct sockaddr_in addr;
591
+ socklen_t addrlen = sizeof(struct sockaddr_in);
592
+ VALUE rv = my_accept(io, (struct sockaddr *)&addr, &addrlen, 0);
593
+
594
+ in_addr_set(rv, &addr);
595
+ return rv;
596
+ }
597
+
598
+ /*
599
+ * call-seq:
600
+ *
601
+ * server = Kgio::UNIXServer.new("/path/to/unix/socket")
602
+ * server.kgio_tryaccept -> Kgio::Socket or nil
603
+ *
604
+ * Initiates a non-blocking accept and returns a generic Kgio::Socket
605
+ * object with the kgio_addr attribute set (to the value of
606
+ * Kgio::LOCALHOST) on success.
607
+ *
608
+ * Returns nil on EAGAIN, and raises on other errors.
609
+ */
610
+ static VALUE unix_tryaccept(VALUE io)
611
+ {
612
+ VALUE rv = my_accept(io, NULL, NULL, 1);
613
+
614
+ if (!NIL_P(rv))
615
+ rb_ivar_set(rv, iv_kgio_addr, localhost);
616
+ return rv;
617
+ }
618
+
619
+ /*
620
+ * call-seq:
621
+ *
622
+ * server = Kgio::UNIXServer.new("/path/to/unix/socket")
623
+ * server.kgio_accept -> Kgio::Socket or nil
624
+ *
625
+ * Initiates a blocking accept and returns a generic Kgio::Socket
626
+ * object with the kgio_addr attribute set (to the value of
627
+ * Kgio::LOCALHOST) on success.
628
+ *
629
+ * On Ruby implementations using native threads, this can use a blocking
630
+ * accept(2) (or accept4(2)) system call to avoid thundering herds.
631
+ */
632
+ static VALUE unix_accept(VALUE io)
633
+ {
634
+ VALUE rv = my_accept(io, NULL, NULL, 0);
635
+
636
+ rb_ivar_set(rv, iv_kgio_addr, localhost);
637
+ return rv;
638
+ }
639
+
640
+ /*
641
+ * call-seq:
642
+ *
643
+ * Kgio.accept_cloexec? -> true or false
644
+ *
645
+ * Returns true if newly accepted Kgio::Sockets are created with the
646
+ * FD_CLOEXEC file descriptor flag, false if not.
647
+ */
648
+ static VALUE get_cloexec(VALUE mod)
649
+ {
650
+ return (accept4_flags & A4_SOCK_CLOEXEC) ==
651
+ A4_SOCK_CLOEXEC ? Qtrue : Qfalse;
652
+ }
653
+
654
+ /*
655
+ *
656
+ * call-seq:
657
+ *
658
+ * Kgio.accept_nonblock? -> true or false
659
+ *
660
+ * Returns true if newly accepted Kgio::Sockets are created with the
661
+ * O_NONBLOCK file status flag, false if not.
662
+ */
663
+ static VALUE get_nonblock(VALUE mod)
664
+ {
665
+ return (accept4_flags & A4_SOCK_NONBLOCK) ==
666
+ A4_SOCK_NONBLOCK ? Qtrue : Qfalse;
667
+ }
668
+
669
+ /*
670
+ * call-seq:
671
+ *
672
+ * Kgio.accept_cloexec = true
673
+ * Kgio.accept_clocexec = false
674
+ *
675
+ * Sets whether or not Kgio::Socket objects created by
676
+ * TCPServer#kgio_accept,
677
+ * TCPServer#kgio_tryaccept,
678
+ * UNIXServer#kgio_accept,
679
+ * and UNIXServer#kgio_tryaccept
680
+ * are created with the FD_CLOEXEC file descriptor flag.
681
+ *
682
+ * This is on by default, as there is little reason to deal to enable
683
+ * it for client sockets on a socket server.
684
+ */
685
+ static VALUE set_cloexec(VALUE mod, VALUE boolean)
686
+ {
687
+ switch (TYPE(boolean)) {
688
+ case T_TRUE:
689
+ accept4_flags |= A4_SOCK_CLOEXEC;
690
+ return boolean;
691
+ case T_FALSE:
692
+ accept4_flags &= ~A4_SOCK_CLOEXEC;
693
+ return boolean;
694
+ }
695
+ rb_raise(rb_eTypeError, "not true or false");
696
+ return Qnil;
697
+ }
698
+
699
+ /*
700
+ * call-seq:
701
+ *
702
+ * Kgio.accept_nonblock = true
703
+ * Kgio.accept_nonblock = false
704
+ *
705
+ * Sets whether or not Kgio::Socket objects created by
706
+ * TCPServer#kgio_accept,
707
+ * TCPServer#kgio_tryaccept,
708
+ * UNIXServer#kgio_accept,
709
+ * and UNIXServer#kgio_tryaccept
710
+ * are created with the O_NONBLOCK file status flag.
711
+ *
712
+ * This defaults to +false+ for GNU/Linux where MSG_DONTWAIT is
713
+ * available (and on newer GNU/Linux, accept4() may also set
714
+ * the non-blocking flag. This defaults to +true+ on non-GNU/Linux
715
+ * systems.
716
+ */
717
+ static VALUE set_nonblock(VALUE mod, VALUE boolean)
718
+ {
719
+ switch (TYPE(boolean)) {
720
+ case T_TRUE:
721
+ accept4_flags |= A4_SOCK_NONBLOCK;
722
+ return boolean;
723
+ case T_FALSE:
724
+ accept4_flags &= ~A4_SOCK_NONBLOCK;
725
+ return boolean;
726
+ }
727
+ rb_raise(rb_eTypeError, "not true or false");
728
+ return Qnil;
729
+ }
730
+
731
+ static void close_fail(int fd, const char *msg)
732
+ {
733
+ int saved_errno = errno;
734
+ (void)close(fd);
735
+ errno = saved_errno;
736
+ rb_sys_fail(msg);
737
+ }
738
+
739
+ #ifdef SOCK_NONBLOCK
740
+ # define MY_SOCK_STREAM (SOCK_STREAM|SOCK_NONBLOCK)
741
+ #else
742
+ # define MY_SOCK_STREAM SOCK_STREAM
743
+ #endif /* ! SOCK_NONBLOCK */
744
+
745
+ static VALUE
746
+ my_connect(VALUE klass, int io_wait, int domain, void *addr, socklen_t addrlen)
747
+ {
748
+ int fd = socket(domain, MY_SOCK_STREAM, 0);
749
+
750
+ if (fd == -1) {
751
+ switch (errno) {
752
+ case EMFILE:
753
+ case ENFILE:
754
+ #ifdef ENOBUFS
755
+ case ENOBUFS:
756
+ #endif /* ENOBUFS */
757
+ errno = 0;
758
+ rb_gc();
759
+ fd = socket(domain, MY_SOCK_STREAM, 0);
760
+ }
761
+ if (fd == -1)
762
+ rb_sys_fail("socket");
763
+ }
764
+
765
+ #ifndef SOCK_NONBLOCK
766
+ if (fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK) == -1)
767
+ close_fail(fd, "fcntl(F_SETFL, O_RDWR | O_NONBLOCK)");
768
+ #endif /* SOCK_NONBLOCK */
769
+
770
+ if (connect(fd, addr, addrlen) == -1) {
771
+ if (errno == EINPROGRESS) {
772
+ VALUE io = sock_for_fd(klass, fd);
773
+
774
+ if (io_wait) {
775
+ errno = EAGAIN;
776
+ wait_writable(io, fd);
777
+ }
778
+ return io;
779
+ }
780
+ close_fail(fd, "connect");
781
+ }
782
+ return sock_for_fd(klass, fd);
783
+ }
784
+
785
+ static VALUE tcp_connect(VALUE klass, VALUE ip, VALUE port, int io_wait)
786
+ {
787
+ struct sockaddr_in addr = { 0 };
788
+
789
+ addr.sin_family = AF_INET;
790
+ addr.sin_port = htons((unsigned short)NUM2INT(port));
791
+
792
+ switch (inet_pton(AF_INET, StringValuePtr(ip), &addr.sin_addr)) {
793
+ case 1:
794
+ return my_connect(klass, io_wait, PF_INET, &addr, sizeof(addr));
795
+ case -1:
796
+ rb_sys_fail("inet_pton");
797
+ }
798
+ rb_raise(rb_eArgError, "invalid address: %s", StringValuePtr(ip));
799
+
800
+ return Qnil;
801
+ }
802
+
803
+ /*
804
+ * call-seq:
805
+ *
806
+ * Kgio::TCPSocket.new('127.0.0.1', 80) -> socket
807
+ *
808
+ * Creates a new Kgio::TCPSocket object and initiates a
809
+ * non-blocking connection.
810
+ *
811
+ * This may block and call any method assigned to Kgio.wait_writable.
812
+ *
813
+ * Unlike the TCPSocket.new in Ruby, this does NOT perform DNS
814
+ * lookups (which is subject to a different set of timeouts and
815
+ * best handled elsewhere).
816
+ */
817
+ static VALUE kgio_tcp_connect(VALUE klass, VALUE ip, VALUE port)
818
+ {
819
+ return tcp_connect(klass, ip, port, 1);
820
+ }
821
+
822
+ /*
823
+ * call-seq:
824
+ *
825
+ * Kgio::TCPSocket.start('127.0.0.1', 80) -> socket
826
+ *
827
+ * Creates a new Kgio::TCPSocket object and initiates a
828
+ * non-blocking connection. The caller should select/poll
829
+ * on the socket for writability before attempting to write
830
+ * or optimistically attempt a write and handle Kgio::WaitWritable
831
+ * or Errno::EAGAIN.
832
+ *
833
+ * Unlike the TCPSocket.new in Ruby, this does NOT perform DNS
834
+ * lookups (which is subject to a different set of timeouts and
835
+ * best handled elsewhere).
836
+ */
837
+ static VALUE kgio_tcp_start(VALUE klass, VALUE ip, VALUE port)
838
+ {
839
+ return tcp_connect(klass, ip, port, 0);
840
+ }
841
+
842
+ static VALUE unix_connect(VALUE klass, VALUE path, int io_wait)
843
+ {
844
+ struct sockaddr_un addr = { 0 };
845
+ long len;
846
+
847
+ StringValue(path);
848
+ len = RSTRING_LEN(path);
849
+ if (sizeof(addr.sun_path) <= len)
850
+ rb_raise(rb_eArgError,
851
+ "too long unix socket path (max: %dbytes)",
852
+ (int)sizeof(addr.sun_path)-1);
853
+
854
+ memcpy(addr.sun_path, RSTRING_PTR(path), len);
855
+ addr.sun_family = AF_UNIX;
856
+
857
+ return my_connect(klass, io_wait, PF_UNIX, &addr, sizeof(addr));
858
+ }
859
+
860
+ /*
861
+ * call-seq:
862
+ *
863
+ * Kgio::UNIXSocket.new("/path/to/unix/socket") -> socket
864
+ *
865
+ * Creates a new Kgio::UNIXSocket object and initiates a
866
+ * non-blocking connection.
867
+ *
868
+ * This may block and call any method assigned to Kgio.wait_writable.
869
+ */
870
+ static VALUE kgio_unix_connect(VALUE klass, VALUE path)
871
+ {
872
+ return unix_connect(klass, path, 1);
873
+ }
874
+
875
+ /*
876
+ * call-seq:
877
+ *
878
+ * Kgio::UNIXSocket.start("/path/to/unix/socket") -> socket
879
+ *
880
+ * Creates a new Kgio::UNIXSocket object and initiates a
881
+ * non-blocking connection. The caller should select/poll
882
+ * on the socket for writability before attempting to write
883
+ * or optimistically attempt a write and handle Kgio::WaitWritable
884
+ * or Errno::EAGAIN.
885
+ */
886
+ static VALUE kgio_unix_start(VALUE klass, VALUE path)
887
+ {
888
+ return unix_connect(klass, path, 0);
889
+ }
890
+
891
+ static VALUE stream_connect(VALUE klass, VALUE addr, int io_wait)
892
+ {
893
+ int domain;
894
+ socklen_t addrlen;
895
+ struct sockaddr *sockaddr;
896
+
897
+ if (TYPE(addr) == T_STRING) {
898
+ sockaddr = (struct sockaddr *)(RSTRING_PTR(addr));
899
+ addrlen = (socklen_t)RSTRING_LEN(addr);
900
+ } else {
901
+ rb_raise(rb_eTypeError, "invalid address");
902
+ }
903
+ switch (((struct sockaddr_in *)(sockaddr))->sin_family) {
904
+ case AF_UNIX: domain = PF_UNIX; break;
905
+ case AF_INET: domain = PF_INET; break;
906
+ #ifdef AF_INET6 /* IPv6 support incomplete */
907
+ case AF_INET6: domain = PF_INET6; break;
908
+ #endif /* AF_INET6 */
909
+ default:
910
+ rb_raise(rb_eArgError, "invalid address family");
911
+ }
912
+
913
+ return my_connect(klass, io_wait, domain, sockaddr, addrlen);
914
+ }
915
+
916
+ /* call-seq:
917
+ *
918
+ * addr = Socket.pack_sockaddr_in(80, 'example.com')
919
+ * Kgio::Socket.connect(addr) -> socket
920
+ *
921
+ * addr = Socket.pack_sockaddr_un("/path/to/unix/socket")
922
+ * Kgio::Socket.connect(addr) -> socket
923
+ *
924
+ * Creates a generic Kgio::Socket object and initiates a
925
+ * non-blocking connection.
926
+ *
927
+ * This may block and call any method assigned to Kgio.wait_writable.
928
+ */
929
+ static VALUE kgio_connect(VALUE klass, VALUE addr)
930
+ {
931
+ return stream_connect(klass, addr, 1);
932
+ }
933
+
934
+ /* call-seq:
935
+ *
936
+ * addr = Socket.pack_sockaddr_in(80, 'example.com')
937
+ * Kgio::Socket.start(addr) -> socket
938
+ *
939
+ * addr = Socket.pack_sockaddr_un("/path/to/unix/socket")
940
+ * Kgio::Socket.start(addr) -> socket
941
+ *
942
+ * Creates a generic Kgio::Socket object and initiates a
943
+ * non-blocking connection. The caller should select/poll
944
+ * on the socket for writability before attempting to write
945
+ * or optimistically attempt a write and handle Kgio::WaitWritable
946
+ * or Errno::EAGAIN.
947
+ */
948
+ static VALUE kgio_start(VALUE klass, VALUE addr)
949
+ {
950
+ return stream_connect(klass, addr, 0);
951
+ }
952
+
953
+ void Init_kgio_ext(void)
954
+ {
955
+ VALUE mKgio = rb_define_module("Kgio");
956
+ VALUE mPipeMethods, mSocketMethods;
957
+ VALUE cUNIXServer, cTCPServer, cUNIXSocket, cTCPSocket;
958
+
959
+ rb_require("socket");
960
+
961
+ /*
962
+ * Document-module: Kgio::Socket
963
+ *
964
+ * A generic socket class with Kgio::SocketMethods included.
965
+ * This is returned by all Kgio methods that accept(2) a connected
966
+ * stream socket.
967
+ */
968
+ cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
969
+ cSocket = rb_define_class_under(mKgio, "Socket", cSocket);
970
+
971
+ localhost = rb_str_new2("127.0.0.1");
972
+
973
+ /*
974
+ * The IPv4 address of UNIX domain sockets, useful for creating
975
+ * Rack (and CGI) servers that also serve HTTP traffic over
976
+ * UNIX domain sockets.
977
+ */
978
+ rb_const_set(mKgio, rb_intern("LOCALHOST"), localhost);
979
+
980
+ /*
981
+ * Document-module: Kgio::WaitReadable
982
+ *
983
+ * PipeMethods#kgio_tryread and SocketMethods#kgio_tryread will
984
+ * return this constant when waiting for a read is required.
985
+ */
986
+ mKgio_WaitReadable = rb_define_module_under(mKgio, "WaitReadable");
987
+
988
+ /*
989
+ * Document-module: Kgio::WaitWritable
990
+ *
991
+ * PipeMethods#kgio_trywrite and SocketMethods#kgio_trywrite will
992
+ * return this constant when waiting for a read is required.
993
+ */
994
+ mKgio_WaitWritable = rb_define_module_under(mKgio, "WaitWritable");
995
+
996
+ rb_define_singleton_method(mKgio, "wait_readable=", set_wait_rd, 1);
997
+ rb_define_singleton_method(mKgio, "wait_writable=", set_wait_wr, 1);
998
+ rb_define_singleton_method(mKgio, "wait_readable", wait_rd, 0);
999
+ rb_define_singleton_method(mKgio, "wait_writable", wait_wr, 0);
1000
+ rb_define_singleton_method(mKgio, "accept_cloexec?", get_cloexec, 0);
1001
+ rb_define_singleton_method(mKgio, "accept_cloexec=", set_cloexec, 1);
1002
+ rb_define_singleton_method(mKgio, "accept_nonblock?", get_nonblock, 0);
1003
+ rb_define_singleton_method(mKgio, "accept_nonblock=", set_nonblock, 1);
1004
+
1005
+ /*
1006
+ * Document-module: Kgio::PipeMethods
1007
+ *
1008
+ * This module may be used used to create classes that respond to
1009
+ * various Kgio methods for reading and writing. This is included
1010
+ * in Kgio::Pipe by default.
1011
+ */
1012
+ mPipeMethods = rb_define_module_under(mKgio, "PipeMethods");
1013
+ rb_define_method(mPipeMethods, "kgio_read", kgio_read, -1);
1014
+ rb_define_method(mPipeMethods, "kgio_write", kgio_write, 1);
1015
+ rb_define_method(mPipeMethods, "kgio_tryread", kgio_tryread, -1);
1016
+ rb_define_method(mPipeMethods, "kgio_trywrite", kgio_trywrite, 1);
1017
+
1018
+ /*
1019
+ * Document-module: Kgio::SocketMethods
1020
+ *
1021
+ * This method behaves like Kgio::PipeMethods, but contains
1022
+ * optimizations for sockets on certain operating systems
1023
+ * (e.g. GNU/Linux).
1024
+ */
1025
+ mSocketMethods = rb_define_module_under(mKgio, "SocketMethods");
1026
+ rb_define_method(mSocketMethods, "kgio_read", kgio_recv, -1);
1027
+ rb_define_method(mSocketMethods, "kgio_write", kgio_send, 1);
1028
+ rb_define_method(mSocketMethods, "kgio_tryread", kgio_tryrecv, -1);
1029
+ rb_define_method(mSocketMethods, "kgio_trywrite", kgio_trysend, 1);
1030
+
1031
+ /*
1032
+ * Returns the client IPv4 address of the socket in dotted quad
1033
+ * form as a string. This is always the value of the
1034
+ * Kgio::LOCALHOST constant for UNIX domain sockets.
1035
+ */
1036
+ rb_define_attr(mSocketMethods, "kgio_addr", 1, 1);
1037
+
1038
+ rb_include_module(cSocket, mSocketMethods);
1039
+ rb_define_singleton_method(cSocket, "new", kgio_connect, 1);
1040
+ rb_define_singleton_method(cSocket, "start", kgio_start, 1);
1041
+
1042
+ cUNIXServer = rb_const_get(rb_cObject, rb_intern("UNIXServer"));
1043
+ cUNIXServer = rb_define_class_under(mKgio, "UNIXServer", cUNIXServer);
1044
+ rb_define_method(cUNIXServer, "kgio_tryaccept", unix_tryaccept, 0);
1045
+ rb_define_method(cUNIXServer, "kgio_accept", unix_accept, 0);
1046
+
1047
+ cTCPServer = rb_const_get(rb_cObject, rb_intern("TCPServer"));
1048
+ cTCPServer = rb_define_class_under(mKgio, "TCPServer", cTCPServer);
1049
+ rb_define_method(cTCPServer, "kgio_tryaccept", tcp_tryaccept, 0);
1050
+ rb_define_method(cTCPServer, "kgio_accept", tcp_accept, 0);
1051
+
1052
+ cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
1053
+ cTCPSocket = rb_define_class_under(mKgio, "TCPSocket", cTCPSocket);
1054
+ rb_include_module(cTCPSocket, mSocketMethods);
1055
+ rb_define_singleton_method(cTCPSocket, "new", kgio_tcp_connect, 2);
1056
+ rb_define_singleton_method(cTCPSocket, "start", kgio_tcp_start, 2);
1057
+
1058
+ cUNIXSocket = rb_const_get(rb_cObject, rb_intern("UNIXSocket"));
1059
+ cUNIXSocket = rb_define_class_under(mKgio, "UNIXSocket", cUNIXSocket);
1060
+ rb_include_module(cUNIXSocket, mSocketMethods);
1061
+ rb_define_singleton_method(cUNIXSocket, "new", kgio_unix_connect, 1);
1062
+ rb_define_singleton_method(cUNIXSocket, "start", kgio_unix_start, 1);
1063
+
1064
+ iv_kgio_addr = rb_intern("@kgio_addr");
1065
+ init_sock_for_fd();
1066
+ }