kgio 2.1.1 → 2.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.
- data/.gitignore +1 -0
- data/.manifest +11 -2
- data/.wrongdoc.yml +4 -0
- data/ChangeLog +810 -531
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +4 -147
- data/LATEST +25 -0
- data/NEWS +49 -9
- data/README +2 -2
- data/Rakefile +2 -2
- data/ext/kgio/accept.c +64 -20
- data/ext/kgio/{missing/ancient_ruby.h → ancient_ruby.h} +0 -0
- data/ext/kgio/autopush.c +203 -0
- data/ext/kgio/connect.c +29 -14
- data/ext/kgio/extconf.rb +13 -2
- data/ext/kgio/kgio.h +7 -1
- data/ext/kgio/kgio_ext.c +1 -0
- data/ext/kgio/{missing/accept4.h → missing_accept4.h} +0 -0
- data/ext/kgio/read_write.c +58 -3
- data/kgio.gemspec +2 -1
- data/pkg.mk +168 -0
- data/test/lib_read_write.rb +10 -2
- data/test/test_autopush.rb +165 -0
- data/test/test_kgio_addr.rb +19 -0
- data/test/test_no_dns_on_tcp_connect.rb +13 -0
- data/test/test_singleton_read_write.rb +21 -0
- data/test/test_tcp6_client_read_server_write.rb +23 -0
- metadata +41 -12
data/ext/kgio/connect.c
CHANGED
@@ -57,20 +57,37 @@ my_connect(VALUE klass, int io_wait, int domain, void *addr, socklen_t addrlen)
|
|
57
57
|
|
58
58
|
static VALUE tcp_connect(VALUE klass, VALUE ip, VALUE port, int io_wait)
|
59
59
|
{
|
60
|
-
struct
|
60
|
+
struct addrinfo hints;
|
61
|
+
struct sockaddr_storage addr;
|
62
|
+
int rc;
|
63
|
+
struct addrinfo *res;
|
64
|
+
VALUE sock;
|
65
|
+
const char *ipname = StringValuePtr(ip);
|
66
|
+
char ipport[6];
|
67
|
+
unsigned uport = FIX2UINT(port);
|
61
68
|
|
62
|
-
|
63
|
-
|
69
|
+
rc = snprintf(ipport, sizeof(ipport), "%u", uport);
|
70
|
+
if (rc >= (int)sizeof(ipport) || rc <= 0)
|
71
|
+
rb_raise(rb_eArgError, "invalid TCP port: %u", uport);
|
72
|
+
hints.ai_family = AF_UNSPEC;
|
73
|
+
hints.ai_socktype = SOCK_STREAM;
|
74
|
+
hints.ai_protocol = IPPROTO_TCP;
|
75
|
+
/* disallow non-deterministic DNS lookups */
|
76
|
+
hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
|
64
77
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
78
|
+
rc = getaddrinfo(ipname, ipport, &hints, &res);
|
79
|
+
if (rc != 0)
|
80
|
+
rb_raise(rb_eArgError, "getaddrinfo(%s:%s): %s",
|
81
|
+
ipname, ipport, gai_strerror(rc));
|
82
|
+
|
83
|
+
/* copy needed data and free ASAP to avoid needing rb_ensure */
|
84
|
+
hints.ai_family = res->ai_family;
|
85
|
+
hints.ai_addrlen = res->ai_addrlen;
|
86
|
+
memcpy(&addr, res->ai_addr, res->ai_addrlen);
|
87
|
+
freeaddrinfo(res);
|
72
88
|
|
73
|
-
return
|
89
|
+
return my_connect(klass, io_wait, hints.ai_family,
|
90
|
+
&addr, hints.ai_addrlen);
|
74
91
|
}
|
75
92
|
|
76
93
|
/*
|
@@ -173,12 +190,10 @@ static VALUE stream_connect(VALUE klass, VALUE addr, int io_wait)
|
|
173
190
|
} else {
|
174
191
|
rb_raise(rb_eTypeError, "invalid address");
|
175
192
|
}
|
176
|
-
switch (((struct
|
193
|
+
switch (((struct sockaddr_storage *)(sockaddr))->ss_family) {
|
177
194
|
case AF_UNIX: domain = PF_UNIX; break;
|
178
195
|
case AF_INET: domain = PF_INET; break;
|
179
|
-
#ifdef AF_INET6 /* IPv6 support incomplete */
|
180
196
|
case AF_INET6: domain = PF_INET6; break;
|
181
|
-
#endif /* AF_INET6 */
|
182
197
|
default:
|
183
198
|
rb_raise(rb_eArgError, "invalid address family");
|
184
199
|
}
|
data/ext/kgio/extconf.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
$CPPFLAGS << ' -D_GNU_SOURCE'
|
3
|
+
$CPPFLAGS << ' -DPOSIX_C_SOURCE=1'
|
3
4
|
|
5
|
+
have_func("getaddrinfo", %w(sys/types.h sys/socket.h netdb.h)) or
|
6
|
+
abort "getaddrinfo required"
|
7
|
+
have_func("getnameinfo", %w(sys/socket.h netdb.h)) or
|
8
|
+
abort "getnameinfo required"
|
9
|
+
have_type("struct sockaddr_storage", %w(sys/types.h sys/socket.h)) or
|
10
|
+
abort "struct sockaddr_storage required"
|
4
11
|
have_func('accept4', %w(sys/socket.h))
|
5
12
|
if have_header('ruby/io.h')
|
6
|
-
|
7
|
-
have_struct_member("rb_io_t", "
|
13
|
+
rubyio = %w(ruby.h ruby/io.h)
|
14
|
+
have_struct_member("rb_io_t", "fd", rubyio)
|
15
|
+
have_struct_member("rb_io_t", "mode", rubyio)
|
8
16
|
else
|
9
17
|
rubyio = %w(ruby.h rubyio.h)
|
10
18
|
rb_io_t = have_type("OpenFile", rubyio) ? "OpenFile" : "rb_io_t"
|
@@ -13,6 +21,9 @@ else
|
|
13
21
|
have_struct_member(rb_io_t, "mode", rubyio)
|
14
22
|
have_func('rb_fdopen')
|
15
23
|
end
|
24
|
+
have_type("struct RFile", rubyio) and check_sizeof("struct RFile", rubyio)
|
25
|
+
have_type("struct RObject") and check_sizeof("struct RObject")
|
26
|
+
check_sizeof("int")
|
16
27
|
have_func('rb_io_ascii8bit_binmode')
|
17
28
|
have_func('rb_thread_blocking_region')
|
18
29
|
have_func('rb_str_set_len')
|
data/ext/kgio/kgio.h
CHANGED
@@ -16,8 +16,9 @@
|
|
16
16
|
#include <unistd.h>
|
17
17
|
#include <arpa/inet.h>
|
18
18
|
#include <assert.h>
|
19
|
+
#include <netdb.h>
|
19
20
|
|
20
|
-
#include "
|
21
|
+
#include "ancient_ruby.h"
|
21
22
|
#include "nonblock.h"
|
22
23
|
#include "my_fileno.h"
|
23
24
|
|
@@ -33,6 +34,11 @@ void init_kgio_wait(void);
|
|
33
34
|
void init_kgio_read_write(void);
|
34
35
|
void init_kgio_accept(void);
|
35
36
|
void init_kgio_connect(void);
|
37
|
+
void init_kgio_autopush(void);
|
38
|
+
|
39
|
+
void kgio_autopush_accept(VALUE, VALUE);
|
40
|
+
void kgio_autopush_recv(VALUE);
|
41
|
+
void kgio_autopush_send(VALUE);
|
36
42
|
|
37
43
|
VALUE kgio_call_wait_writable(VALUE io);
|
38
44
|
VALUE kgio_call_wait_readable(VALUE io);
|
data/ext/kgio/kgio_ext.c
CHANGED
File without changes
|
data/ext/kgio/read_write.c
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#include "kgio.h"
|
2
2
|
static VALUE sym_wait_readable, sym_wait_writable;
|
3
3
|
static VALUE eErrno_EPIPE, eErrno_ECONNRESET;
|
4
|
+
static ID id_set_backtrace;
|
4
5
|
|
5
6
|
/*
|
6
7
|
* we know MSG_DONTWAIT works properly on all stream sockets under Linux
|
@@ -14,13 +15,14 @@ static VALUE eErrno_EPIPE, eErrno_ECONNRESET;
|
|
14
15
|
NORETURN(static void raise_empty_bt(VALUE, const char *));
|
15
16
|
NORETURN(static void my_eof_error(void));
|
16
17
|
NORETURN(static void wr_sys_fail(const char *));
|
18
|
+
NORETURN(static void rd_sys_fail(const char *));
|
17
19
|
|
18
20
|
static void raise_empty_bt(VALUE err, const char *msg)
|
19
21
|
{
|
20
22
|
VALUE exc = rb_exc_new2(err, msg);
|
21
23
|
VALUE bt = rb_ary_new();
|
22
24
|
|
23
|
-
rb_funcall(exc,
|
25
|
+
rb_funcall(exc, id_set_backtrace, 1, bt);
|
24
26
|
rb_exc_raise(exc);
|
25
27
|
}
|
26
28
|
|
@@ -42,6 +44,15 @@ static void wr_sys_fail(const char *msg)
|
|
42
44
|
rb_sys_fail(msg);
|
43
45
|
}
|
44
46
|
|
47
|
+
static void rd_sys_fail(const char *msg)
|
48
|
+
{
|
49
|
+
if (errno == ECONNRESET) {
|
50
|
+
errno = 0;
|
51
|
+
raise_empty_bt(eErrno_ECONNRESET, msg);
|
52
|
+
}
|
53
|
+
rb_sys_fail(msg);
|
54
|
+
}
|
55
|
+
|
45
56
|
static void prepare_read(struct io_args *a, int argc, VALUE *argv, VALUE io)
|
46
57
|
{
|
47
58
|
VALUE length;
|
@@ -78,7 +89,7 @@ static int read_check(struct io_args *a, long n, const char *msg, int io_wait)
|
|
78
89
|
return 0;
|
79
90
|
}
|
80
91
|
}
|
81
|
-
|
92
|
+
rd_sys_fail(msg);
|
82
93
|
}
|
83
94
|
rb_str_set_len(a->buf, n);
|
84
95
|
if (n == 0)
|
@@ -164,6 +175,7 @@ static VALUE my_recv(int io_wait, int argc, VALUE *argv, VALUE io)
|
|
164
175
|
long n;
|
165
176
|
|
166
177
|
prepare_read(&a, argc, argv, io);
|
178
|
+
kgio_autopush_recv(io);
|
167
179
|
|
168
180
|
if (a.len > 0) {
|
169
181
|
retry:
|
@@ -320,6 +332,8 @@ retry:
|
|
320
332
|
n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
|
321
333
|
if (write_check(&a, n, "send", io_wait) != 0)
|
322
334
|
goto retry;
|
335
|
+
if (TYPE(a.buf) != T_SYMBOL)
|
336
|
+
kgio_autopush_send(io);
|
323
337
|
return a.buf;
|
324
338
|
}
|
325
339
|
|
@@ -347,6 +361,44 @@ static VALUE kgio_trysend(VALUE io, VALUE str)
|
|
347
361
|
# define kgio_trysend kgio_trywrite
|
348
362
|
#endif /* ! USE_MSG_DONTWAIT */
|
349
363
|
|
364
|
+
/*
|
365
|
+
* call-seq:
|
366
|
+
*
|
367
|
+
* Kgio.tryread(io, maxlen) -> buffer
|
368
|
+
* Kgio.tryread(io, maxlen, buffer) -> buffer
|
369
|
+
*
|
370
|
+
* Returns nil on EOF.
|
371
|
+
* Returns :wait_readable if EAGAIN is encountered.
|
372
|
+
*
|
373
|
+
* Maybe used in place of PipeMethods#kgio_tryread for non-Kgio objects
|
374
|
+
*/
|
375
|
+
static VALUE s_tryread(int argc, VALUE *argv, VALUE mod)
|
376
|
+
{
|
377
|
+
if (argc <= 1)
|
378
|
+
rb_raise(rb_eArgError, "wrong number of arguments");
|
379
|
+
return my_read(0, argc - 1, &argv[1], argv[0]);
|
380
|
+
}
|
381
|
+
|
382
|
+
/*
|
383
|
+
* call-seq:
|
384
|
+
*
|
385
|
+
* Kgio.trywrite(io, str) -> nil or :wait_writable
|
386
|
+
*
|
387
|
+
* Returns nil if the write was completed in full.
|
388
|
+
*
|
389
|
+
* Returns a String containing the unwritten portion if EAGAIN
|
390
|
+
* was encountered, but some portion was successfully written.
|
391
|
+
*
|
392
|
+
* Returns :wait_writable if EAGAIN is encountered and nothing
|
393
|
+
* was written.
|
394
|
+
*
|
395
|
+
* Maybe used in place of PipeMethods#kgio_trywrite for non-Kgio objects
|
396
|
+
*/
|
397
|
+
static VALUE s_trywrite(VALUE mod, VALUE io, VALUE str)
|
398
|
+
{
|
399
|
+
return my_write(io, str, 0);
|
400
|
+
}
|
401
|
+
|
350
402
|
void init_kgio_read_write(void)
|
351
403
|
{
|
352
404
|
VALUE mPipeMethods, mSocketMethods;
|
@@ -356,6 +408,9 @@ void init_kgio_read_write(void)
|
|
356
408
|
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
|
357
409
|
sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
|
358
410
|
|
411
|
+
rb_define_singleton_method(mKgio, "tryread", s_tryread, -1);
|
412
|
+
rb_define_singleton_method(mKgio, "trywrite", s_trywrite, 2);
|
413
|
+
|
359
414
|
/*
|
360
415
|
* Document-module: Kgio::PipeMethods
|
361
416
|
*
|
@@ -390,7 +445,7 @@ void init_kgio_read_write(void)
|
|
390
445
|
* Kgio::LOCALHOST constant for UNIX domain sockets.
|
391
446
|
*/
|
392
447
|
rb_define_attr(mSocketMethods, "kgio_addr", 1, 1);
|
393
|
-
|
448
|
+
id_set_backtrace = rb_intern("set_backtrace");
|
394
449
|
eErrno_EPIPE = rb_const_get(rb_mErrno, rb_intern("EPIPE"));
|
395
450
|
eErrno_ECONNRESET = rb_const_get(rb_mErrno, rb_intern("ECONNRESET"));
|
396
451
|
rb_include_module(mPipeMethods, mWaiters);
|
data/kgio.gemspec
CHANGED
@@ -21,7 +21,8 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.test_files = Dir['test/test_*.rb']
|
22
22
|
s.extensions = %w(ext/kgio/extconf.rb)
|
23
23
|
|
24
|
-
s.add_development_dependency('wrongdoc', '~> 1.
|
24
|
+
s.add_development_dependency('wrongdoc', '~> 1.4')
|
25
|
+
s.add_development_dependency('strace_me', '~> 1.0')
|
25
26
|
|
26
27
|
# s.license = %w(LGPL) # disabled for compatibility with older RubyGems
|
27
28
|
end
|
data/pkg.mk
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
RUBY = ruby
|
2
|
+
RAKE = rake
|
3
|
+
RSYNC = rsync
|
4
|
+
WRONGDOC = wrongdoc
|
5
|
+
|
6
|
+
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
7
|
+
@./GIT-VERSION-GEN
|
8
|
+
-include GIT-VERSION-FILE
|
9
|
+
-include local.mk
|
10
|
+
DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
|
11
|
+
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
12
|
+
RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
|
13
|
+
lib := lib
|
14
|
+
|
15
|
+
ifeq ($(shell test -f script/isolate_for_tests && echo t),t)
|
16
|
+
isolate_libs := tmp/isolate/$(RUBY_ENGINE)-$(RUBY_VERSION)/isolate.mk
|
17
|
+
$(isolate_libs): script/isolate_for_tests
|
18
|
+
@$(RUBY) script/isolate_for_tests
|
19
|
+
-include $(isolate_libs)
|
20
|
+
lib := $(lib):$(ISOLATE_LIBS)
|
21
|
+
endif
|
22
|
+
|
23
|
+
ext := $(firstword $(wildcard ext/*))
|
24
|
+
ifneq ($(ext),)
|
25
|
+
ext_pfx := tmp/ext/$(RUBY_ENGINE)-$(RUBY_VERSION)
|
26
|
+
ext_h := $(wildcard $(ext)/*/*.h $(ext)/*.h)
|
27
|
+
ext_src := $(wildcard $(ext)/*.c $(ext_h))
|
28
|
+
ext_pfx_src := $(addprefix $(ext_pfx)/,$(ext_src))
|
29
|
+
ext_d := $(ext_pfx)/$(ext)/.d
|
30
|
+
$(ext)/extconf.rb: $(wildcard $(ext)/*.h)
|
31
|
+
@>> $@
|
32
|
+
$(ext_d):
|
33
|
+
@mkdir -p $(@D)
|
34
|
+
@> $@
|
35
|
+
$(ext_pfx)/$(ext)/%: $(ext)/% $(ext_d)
|
36
|
+
install -m 644 $< $@
|
37
|
+
$(ext_pfx)/$(ext)/Makefile: $(ext)/extconf.rb $(ext_d) $(ext_h)
|
38
|
+
$(RM) -f $(@D)/*.o
|
39
|
+
cd $(@D) && $(RUBY) $(CURDIR)/$(ext)/extconf.rb
|
40
|
+
ext_sfx := _ext.$(DLEXT)
|
41
|
+
ext_dl := $(ext_pfx)/$(ext)/$(notdir $(ext)_ext.$(DLEXT))
|
42
|
+
$(ext_dl): $(ext_src) $(ext_pfx_src) $(ext_pfx)/$(ext)/Makefile
|
43
|
+
@echo $^ == $@
|
44
|
+
$(MAKE) -C $(@D)
|
45
|
+
lib := $(lib):$(ext_pfx)/$(ext)
|
46
|
+
build: $(ext_dl)
|
47
|
+
endif
|
48
|
+
|
49
|
+
pkg_extra := GIT-VERSION-FILE NEWS ChangeLog LATEST
|
50
|
+
ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
|
51
|
+
$(WRONGDOC) prepare
|
52
|
+
|
53
|
+
manifest:
|
54
|
+
$(RM) .manifest
|
55
|
+
$(MAKE) .manifest
|
56
|
+
|
57
|
+
.manifest: ChangeLog
|
58
|
+
(git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
|
59
|
+
LC_ALL=C sort > $@+
|
60
|
+
cmp $@+ $@ || mv $@+ $@
|
61
|
+
$(RM) $@+
|
62
|
+
|
63
|
+
doc:: .document .wrongdoc.yml
|
64
|
+
find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
|
65
|
+
-find ext -type f -name '*.rbc' -exec rm -f '{}' ';'
|
66
|
+
$(RM) -r doc
|
67
|
+
$(WRONGDOC) all
|
68
|
+
install -m644 COPYING doc/COPYING
|
69
|
+
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
70
|
+
|
71
|
+
ifneq ($(VERSION),)
|
72
|
+
pkggem := pkg/$(rfpackage)-$(VERSION).gem
|
73
|
+
pkgtgz := pkg/$(rfpackage)-$(VERSION).tgz
|
74
|
+
release_notes := release_notes-$(VERSION)
|
75
|
+
release_changes := release_changes-$(VERSION)
|
76
|
+
|
77
|
+
release-notes: $(release_notes)
|
78
|
+
release-changes: $(release_changes)
|
79
|
+
$(release_changes):
|
80
|
+
$(WRONGDOC) release_changes > $@+
|
81
|
+
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
82
|
+
$(release_notes):
|
83
|
+
$(WRONGDOC) release_notes > $@+
|
84
|
+
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
85
|
+
|
86
|
+
# ensures we're actually on the tagged $(VERSION), only used for release
|
87
|
+
verify:
|
88
|
+
test x"$(shell umask)" = x0022
|
89
|
+
git rev-parse --verify refs/tags/v$(VERSION)^{}
|
90
|
+
git diff-index --quiet HEAD^0
|
91
|
+
test $$(git rev-parse --verify HEAD^0) = \
|
92
|
+
$$(git rev-parse --verify refs/tags/v$(VERSION)^{})
|
93
|
+
|
94
|
+
fix-perms:
|
95
|
+
-git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
|
96
|
+
-git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
|
97
|
+
|
98
|
+
gem: $(pkggem)
|
99
|
+
|
100
|
+
install-gem: $(pkggem)
|
101
|
+
gem install $(CURDIR)/$<
|
102
|
+
|
103
|
+
$(pkggem): manifest fix-perms
|
104
|
+
gem build $(rfpackage).gemspec
|
105
|
+
mkdir -p pkg
|
106
|
+
mv $(@F) $@
|
107
|
+
|
108
|
+
$(pkgtgz): distdir = $(basename $@)
|
109
|
+
$(pkgtgz): HEAD = v$(VERSION)
|
110
|
+
$(pkgtgz): manifest fix-perms
|
111
|
+
@test -n "$(distdir)"
|
112
|
+
$(RM) -r $(distdir)
|
113
|
+
mkdir -p $(distdir)
|
114
|
+
tar cf - $$(cat .manifest) | (cd $(distdir) && tar xf -)
|
115
|
+
cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
|
116
|
+
mv $@+ $@
|
117
|
+
|
118
|
+
package: $(pkgtgz) $(pkggem)
|
119
|
+
|
120
|
+
test-release:: verify package $(release_notes) $(release_changes)
|
121
|
+
# make tgz release on RubyForge
|
122
|
+
@echo rubyforge add_release -f \
|
123
|
+
-n $(release_notes) -a $(release_changes) \
|
124
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
|
125
|
+
@echo gem push $(pkggem)
|
126
|
+
@echo rubyforge add_file \
|
127
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
128
|
+
release:: verify package $(release_notes) $(release_changes)
|
129
|
+
# make tgz release on RubyForge
|
130
|
+
rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
|
131
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
|
132
|
+
# push gem to RubyGems.org
|
133
|
+
gem push $(pkggem)
|
134
|
+
# in case of gem downloads from RubyForge releases page
|
135
|
+
rubyforge add_file \
|
136
|
+
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
137
|
+
else
|
138
|
+
gem install-gem: GIT-VERSION-FILE
|
139
|
+
$(MAKE) $@ VERSION=$(GIT_VERSION)
|
140
|
+
endif
|
141
|
+
|
142
|
+
all:: test
|
143
|
+
test_units := $(wildcard test/test_*.rb)
|
144
|
+
test: test-unit
|
145
|
+
test-unit: $(test_units)
|
146
|
+
$(test_units): build
|
147
|
+
$(RUBY) -I $(lib) $@
|
148
|
+
|
149
|
+
# this requires GNU coreutils variants
|
150
|
+
ifneq ($(RSYNC_DEST),)
|
151
|
+
publish_doc:
|
152
|
+
-git set-file-times
|
153
|
+
$(MAKE) doc
|
154
|
+
find doc/images -type f | \
|
155
|
+
TZ=UTC xargs touch -d '1970-01-01 00:00:06' doc/rdoc.css
|
156
|
+
$(MAKE) doc_gz
|
157
|
+
$(RSYNC) -av doc/ $(RSYNC_DEST)/
|
158
|
+
git ls-files | xargs touch
|
159
|
+
endif
|
160
|
+
|
161
|
+
# Create gzip variants of the same timestamp as the original so nginx
|
162
|
+
# "gzip_static on" can serve the gzipped versions directly.
|
163
|
+
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
164
|
+
doc_gz:
|
165
|
+
for i in $(docs); do \
|
166
|
+
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
167
|
+
|
168
|
+
.PHONY: all .FORCE-GIT-VERSION-FILE doc test $(test_units) manifest
|
data/test/lib_read_write.rb
CHANGED
@@ -10,11 +10,19 @@ module LibReadWriteTest
|
|
10
10
|
|
11
11
|
def teardown
|
12
12
|
assert_nothing_raised do
|
13
|
-
@rd.close
|
14
|
-
@wr.close
|
13
|
+
@rd.close if defined?(@rd) && ! @rd.closed?
|
14
|
+
@wr.close if defined?(@wr) && ! @wr.closed?
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
def test_write_empty
|
19
|
+
assert_nil @wr.kgio_write("")
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_trywrite_empty
|
23
|
+
assert_nil @wr.kgio_trywrite("")
|
24
|
+
end
|
25
|
+
|
18
26
|
def test_read_zero
|
19
27
|
assert_equal "", @rd.kgio_read(0)
|
20
28
|
buf = "foo"
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'test/unit'
|
3
|
+
RUBY_PLATFORM =~ /linux/ and require 'strace'
|
4
|
+
$-w = true
|
5
|
+
require 'kgio'
|
6
|
+
|
7
|
+
class TestAutopush < Test::Unit::TestCase
|
8
|
+
TCP_CORK = 3
|
9
|
+
TCP_NOPUSH = 4
|
10
|
+
|
11
|
+
def setup
|
12
|
+
Kgio.autopush = false
|
13
|
+
assert_equal false, Kgio.autopush?
|
14
|
+
|
15
|
+
@host = ENV["TEST_HOST"] || '127.0.0.1'
|
16
|
+
@srv = Kgio::TCPServer.new(@host, 0)
|
17
|
+
assert_nothing_raised {
|
18
|
+
@srv.setsockopt(Socket::IPPROTO_TCP, TCP_CORK, 1)
|
19
|
+
} if RUBY_PLATFORM =~ /linux/
|
20
|
+
assert_nothing_raised {
|
21
|
+
@srv.setsockopt(Socket::IPPROTO_TCP, TCP_NOPUSH, 1)
|
22
|
+
} if RUBY_PLATFORM =~ /freebsd/
|
23
|
+
@port = @srv.addr[1]
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_autopush_accessors
|
27
|
+
Kgio.autopush = true
|
28
|
+
opt = RUBY_PLATFORM =~ /freebsd/ ? TCP_NOPUSH : TCP_CORK
|
29
|
+
s = Kgio::TCPSocket.new(@host, @port)
|
30
|
+
assert_equal 0, s.getsockopt(Socket::IPPROTO_TCP, opt).unpack('i')[0]
|
31
|
+
assert ! s.kgio_autopush?
|
32
|
+
s.kgio_autopush = true
|
33
|
+
assert s.kgio_autopush?
|
34
|
+
assert_nothing_raised { s.kgio_write 'asdf' }
|
35
|
+
assert_equal :wait_readable, s.kgio_tryread(1)
|
36
|
+
assert s.kgio_autopush?
|
37
|
+
assert_equal 1, s.getsockopt(Socket::IPPROTO_TCP, opt).unpack('i')[0]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_autopush_true_unix
|
41
|
+
Kgio.autopush = true
|
42
|
+
tmp = Tempfile.new('kgio_unix')
|
43
|
+
@path = tmp.path
|
44
|
+
File.unlink(@path)
|
45
|
+
tmp.close rescue nil
|
46
|
+
@srv = Kgio::UNIXServer.new(@path)
|
47
|
+
@rd = Kgio::UNIXSocket.new(@path)
|
48
|
+
t0 = nil
|
49
|
+
if defined?(Strace)
|
50
|
+
io, err = Strace.me { @wr = @srv.kgio_accept }
|
51
|
+
assert_nil err
|
52
|
+
rc = nil
|
53
|
+
io, err = Strace.me {
|
54
|
+
t0 = Time.now
|
55
|
+
@wr.kgio_write "HI\n"
|
56
|
+
rc = @wr.kgio_tryread 666
|
57
|
+
}
|
58
|
+
assert_nil err
|
59
|
+
lines = io.readlines
|
60
|
+
assert lines.grep(/TCP_CORK/).empty?, lines.inspect
|
61
|
+
else
|
62
|
+
assert_nothing_raised do
|
63
|
+
@wr = @srv.kgio_accept
|
64
|
+
t0 = Time.now
|
65
|
+
@wr.kgio_write "HI\n"
|
66
|
+
rc = @wr.kgio_tryread 666
|
67
|
+
end
|
68
|
+
end
|
69
|
+
assert_equal "HI\n", @rd.kgio_read(3)
|
70
|
+
diff = Time.now - t0
|
71
|
+
assert(diff < 0.200, "nopush on UNIX sockets? diff=#{diff} > 200ms")
|
72
|
+
assert_equal :wait_readable, rc
|
73
|
+
ensure
|
74
|
+
File.unlink(@path) rescue nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_autopush_false
|
78
|
+
Kgio.autopush = nil
|
79
|
+
assert_equal false, Kgio.autopush?
|
80
|
+
|
81
|
+
@wr = Kgio::TCPSocket.new(@host, @port)
|
82
|
+
if defined?(Strace)
|
83
|
+
io, err = Strace.me { @rd = @srv.kgio_accept }
|
84
|
+
assert_nil err
|
85
|
+
lines = io.readlines
|
86
|
+
assert lines.grep(/TCP_CORK/).empty?, lines.inspect
|
87
|
+
assert_equal 1, @rd.getsockopt(Socket::SOL_TCP, TCP_CORK).unpack("i")[0]
|
88
|
+
else
|
89
|
+
@rd = @srv.kgio_accept
|
90
|
+
end
|
91
|
+
|
92
|
+
rbuf = "..."
|
93
|
+
t0 = Time.now
|
94
|
+
@rd.kgio_write "HI\n"
|
95
|
+
@wr.kgio_read(3, rbuf)
|
96
|
+
diff = Time.now - t0
|
97
|
+
assert(diff >= 0.200, "nopush broken? diff=#{diff} > 200ms")
|
98
|
+
assert_equal "HI\n", rbuf
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_autopush_true
|
102
|
+
Kgio.autopush = true
|
103
|
+
assert_equal true, Kgio.autopush?
|
104
|
+
@wr = Kgio::TCPSocket.new(@host, @port)
|
105
|
+
|
106
|
+
if defined?(Strace)
|
107
|
+
io, err = Strace.me { @rd = @srv.kgio_accept }
|
108
|
+
assert_nil err
|
109
|
+
lines = io.readlines
|
110
|
+
assert_equal 1, lines.grep(/TCP_CORK/).size, lines.inspect
|
111
|
+
assert_equal 1, @rd.getsockopt(Socket::SOL_TCP, TCP_CORK).unpack("i")[0]
|
112
|
+
else
|
113
|
+
@rd = @srv.kgio_accept
|
114
|
+
end
|
115
|
+
|
116
|
+
@wr.write "HI\n"
|
117
|
+
rbuf = ""
|
118
|
+
if defined?(Strace)
|
119
|
+
io, err = Strace.me { @rd.kgio_read(3, rbuf) }
|
120
|
+
assert_nil err
|
121
|
+
lines = io.readlines
|
122
|
+
assert lines.grep(/TCP_CORK/).empty?, lines.inspect
|
123
|
+
assert_equal "HI\n", rbuf
|
124
|
+
else
|
125
|
+
assert_equal "HI\n", @rd.kgio_read(3, rbuf)
|
126
|
+
end
|
127
|
+
|
128
|
+
t0 = Time.now
|
129
|
+
@rd.kgio_write "HI2U2\n"
|
130
|
+
@rd.kgio_write "HOW\n"
|
131
|
+
rc = false
|
132
|
+
|
133
|
+
if defined?(Strace)
|
134
|
+
io, err = Strace.me { rc = @rd.kgio_tryread(666) }
|
135
|
+
else
|
136
|
+
rc = @rd.kgio_tryread(666)
|
137
|
+
end
|
138
|
+
|
139
|
+
@wr.readpartial(666, rbuf)
|
140
|
+
rbuf == "HI2U2\nHOW\n" or warn "rbuf=#{rbuf.inspect} looking bad?"
|
141
|
+
diff = Time.now - t0
|
142
|
+
assert(diff < 0.200, "time diff=#{diff} >= 200ms")
|
143
|
+
assert_equal :wait_readable, rc
|
144
|
+
if defined?(Strace)
|
145
|
+
assert_nil err
|
146
|
+
lines = io.readlines
|
147
|
+
assert_equal 2, lines.grep(/TCP_CORK/).size, lines.inspect
|
148
|
+
end
|
149
|
+
assert_nothing_raised { @wr.close }
|
150
|
+
assert_nothing_raised { @rd.close }
|
151
|
+
|
152
|
+
@wr = Kgio::TCPSocket.new(@host, @port)
|
153
|
+
if defined?(Strace)
|
154
|
+
io, err = Strace.me { @rd = @srv.kgio_accept }
|
155
|
+
assert_nil err
|
156
|
+
lines = io.readlines
|
157
|
+
assert lines.grep(/TCP_CORK/).empty?,"optimization fail: #{lines.inspect}"
|
158
|
+
assert_equal 1, @rd.getsockopt(Socket::SOL_TCP, TCP_CORK).unpack("i")[0]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def teardown
|
163
|
+
Kgio.autopush = false
|
164
|
+
end
|
165
|
+
end if RUBY_PLATFORM =~ /linux|freebsd/
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'test/unit'
|
3
|
+
$-w = true
|
4
|
+
require 'kgio'
|
5
|
+
|
6
|
+
class TestKgioAddr < Test::Unit::TestCase
|
7
|
+
def test_tcp
|
8
|
+
addr = ENV["TEST_HOST"] || '127.0.0.1'
|
9
|
+
tcp = TCPServer.new(addr, 0)
|
10
|
+
port = tcp.addr[1]
|
11
|
+
client = Kgio::TCPSocket.new(addr, port)
|
12
|
+
accepted = tcp.accept
|
13
|
+
assert ! accepted.instance_eval { defined?(@kgio_addr) }
|
14
|
+
accepted.extend Kgio::SocketMethods
|
15
|
+
s = accepted.kgio_addr!
|
16
|
+
assert_equal addr, s
|
17
|
+
assert_equal addr, accepted.instance_variable_get(:@kgio_addr)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
$-w = true
|
3
|
+
require 'kgio'
|
4
|
+
|
5
|
+
class TestNoDnsOnTcpConnect < Test::Unit::TestCase
|
6
|
+
def test_connect_remote
|
7
|
+
assert_raises(ArgumentError) { Kgio::TCPSocket.new("example.com", 666) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_connect_localhost
|
11
|
+
assert_raises(ArgumentError) { Kgio::TCPSocket.new("localhost", 666) }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
$-w = true
|
3
|
+
require 'kgio'
|
4
|
+
|
5
|
+
class TestSingletonReadWrite < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_unix_socketpair
|
8
|
+
a, b = UNIXSocket.pair
|
9
|
+
assert_nothing_raised { Kgio.trywrite(a, "HELLO") }
|
10
|
+
buf = ""
|
11
|
+
assert_equal "HELLO", Kgio.tryread(b, 5, buf)
|
12
|
+
assert_equal "HELLO", buf
|
13
|
+
assert_equal :wait_readable, Kgio.tryread(b, 5)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_arg_error
|
17
|
+
assert_raises(ArgumentError) { Kgio.tryread }
|
18
|
+
assert_raises(ArgumentError) { Kgio.tryread($stdin) }
|
19
|
+
assert_raises(ArgumentError) { Kgio.trywrite($stdout) }
|
20
|
+
end
|
21
|
+
end
|