Project

General

Profile

Feature #11139 ยป socket-support-accept-sock_nonblock-true-false-v2.patch

normalperson (Eric Wong), 07/02/2015 01:30 AM

View differences:

ext/socket/ancdata.c
1285 1285
            goto retry;
1286 1286
        }
1287 1287
        if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
1288
	    if (rsock_opt_false_p(opts, sym_exception)) {
1288
	    if (rsock_opt_eq(opts, sym_exception, Qfalse)) {
1289 1289
		return sym_wait_writable;
1290 1290
	    }
1291 1291
	    rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE,
......
1602 1602
            goto retry;
1603 1603
        }
1604 1604
        if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
1605
            if (rsock_opt_false_p(vopts, sym_exception)) {
1605
            if (rsock_opt_eq(vopts, sym_exception, Qfalse)) {
1606 1606
                return sym_wait_readable;
1607 1607
            }
1608 1608
            rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
ext/socket/init.c
29 29
#endif
30 30

  
31 31
int rsock_do_not_reverse_lookup = 1;
32
static VALUE sym_exception, sym_wait_readable;
32
static VALUE sym_exception, sym_wait_readable, sym_sock_nonblock;
33 33

  
34 34
void
35 35
rsock_raise_socket_error(const char *reason, int error)
......
247 247
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
248 248
	  case EWOULDBLOCK:
249 249
#endif
250
            if (rsock_opt_false_p(opts, sym_exception))
250
            if (rsock_opt_eq(opts, sym_exception, Qfalse))
251 251
		return sym_wait_readable;
252 252
            rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
253 253
	}
......
498 498

  
499 499
static int
500 500
cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len,
501
	       int nonblock)
501
	       int sock_nonblock)
502 502
{
503 503
    int ret;
504 504
    socklen_t len0 = 0;
......
513 513
        flags |= SOCK_CLOEXEC;
514 514
#endif
515 515
#ifdef SOCK_NONBLOCK
516
        if (nonblock) {
516
        if (sock_nonblock) {
517 517
            flags |= SOCK_NONBLOCK;
518 518
        }
519 519
#endif
......
523 523
            if (ret <= 2)
524 524
                rb_maygvl_fd_fix_cloexec(ret);
525 525
#ifndef SOCK_NONBLOCK
526
            if (nonblock) {
526
            if (sock_nonblock) {
527 527
                make_fd_nonblock(ret);
528 528
            }
529 529
#endif
......
540 540
    if (ret == -1) return -1;
541 541
    if (address_len && len0 < *address_len) *address_len = len0;
542 542
    rb_maygvl_fd_fix_cloexec(ret);
543
    if (nonblock) {
543
    if (sock_nonblock) {
544 544
        make_fd_nonblock(ret);
545 545
    }
546 546
    return ret;
......
551 551
			struct sockaddr *sockaddr, socklen_t *len)
552 552
{
553 553
    int fd2;
554
    VALUE opts = Qnil;
554
    VALUE opts;
555
    int sock_nonblock = 1;
555 556

  
556 557
    rb_scan_args(argc, argv, "0:", &opts);
557 558

  
559
    if (rsock_opt_eq(opts, sym_sock_nonblock, Qfalse))
560
        sock_nonblock = 0;
561

  
558 562
    rb_io_set_nonblock(fptr);
559
    fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len, 1);
563
    fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len,
564
                         sock_nonblock);
560 565
    if (fd2 < 0) {
561 566
	switch (errno) {
562 567
	  case EAGAIN:
......
567 572
#if defined EPROTO
568 573
	  case EPROTO:
569 574
#endif
570
            if (rsock_opt_false_p(opts, sym_exception))
575
            if (rsock_opt_eq(opts, sym_exception, Qfalse))
571 576
		return sym_wait_readable;
572 577
            rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "accept(2) would block");
573 578
	}
......
579 584

  
580 585
struct accept_arg {
581 586
    int fd;
587
    int sock_nonblock;
582 588
    struct sockaddr *sockaddr;
583 589
    socklen_t *len;
584 590
};
......
587 593
accept_blocking(void *data)
588 594
{
589 595
    struct accept_arg *arg = data;
590
    return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len, 0);
596
    return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len,
597
				 arg->sock_nonblock);
591 598
}
592 599

  
593 600
VALUE
594
rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
601
rsock_s_accept(int argc, VALUE *argv, VALUE klass, int fd,
602
               struct sockaddr *sockaddr, socklen_t *len)
595 603
{
596 604
    int fd2;
597 605
    int retry = 0;
598 606
    struct accept_arg arg;
607
    VALUE opts;
599 608

  
600 609
    arg.fd = fd;
610
    arg.sock_nonblock = 0;
601 611
    arg.sockaddr = sockaddr;
602 612
    arg.len = len;
613

  
614
    rb_scan_args(argc, argv, "0:", &opts);
615

  
616
    if (!NIL_P(opts) &&
617
		rb_hash_lookup2(opts, sym_sock_nonblock, Qundef) == Qtrue) {
618
	arg.sock_nonblock = 1;
619
    }
620

  
603 621
  retry:
604 622
    rsock_maybe_wait_fd(fd);
605 623
    fd2 = (int)BLOCKING_REGION_FD(accept_blocking, &arg);
......
659 677
#undef rb_intern
660 678
    sym_exception = ID2SYM(rb_intern("exception"));
661 679
    sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
680
    sym_sock_nonblock = ID2SYM(rb_intern("sock_nonblock"));
662 681
}
ext/socket/rubysocket.h
342 342

  
343 343
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);
344 344

  
345
VALUE rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len);
345
VALUE rsock_s_accept(int argc, VALUE *argv, VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len);
346 346
VALUE rsock_s_accept_nonblock(int argc, VALUE *argv, VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len);
347 347
VALUE rsock_sock_listen(VALUE sock, VALUE log);
348 348

  
......
424 424
#endif
425 425

  
426 426
static inline int
427
rsock_opt_false_p(VALUE opt, VALUE sym)
427
rsock_opt_eq(VALUE opt, VALUE sym, VALUE exp)
428 428
{
429
    if (!NIL_P(opt) && Qfalse == rb_hash_lookup2(opt, sym, Qundef))
429
    if (!NIL_P(opt) && exp == rb_hash_lookup2(opt, sym, Qundef))
430 430
	return 1;
431 431
    return 0;
432 432
}
ext/socket/socket.c
502 502
    n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr));
503 503
    if (n < 0) {
504 504
        if (errno == EINPROGRESS) {
505
           if (rsock_opt_false_p(opts, sym_exception)) {
505
           if (rsock_opt_eq(opts, sym_exception, Qfalse)) {
506 506
                return sym_wait_writable;
507 507
            }
508 508
            rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "connect(2) would block");
509 509
	}
510 510
	if (errno == EISCONN) {
511
           if (rsock_opt_false_p(opts, sym_exception)) {
511
           if (rsock_opt_eq(opts, sym_exception, Qfalse)) {
512 512
                return INT2FIX(0);
513 513
            }
514 514
	}
......
896 896
 *
897 897
 */
898 898
static VALUE
899
sock_accept(VALUE sock)
899
sock_accept(int argc, VALUE *argv, VALUE sock)
900 900
{
901 901
    rb_io_t *fptr;
902 902
    VALUE sock2;
......
904 904
    socklen_t len = (socklen_t)sizeof buf;
905 905

  
906 906
    GetOpenFile(sock, fptr);
907
    sock2 = rsock_s_accept(rb_cSocket,fptr->fd,&buf.addr,&len);
907
    sock2 = rsock_s_accept(argc, argv, rb_cSocket, fptr->fd, &buf.addr, &len);
908 908

  
909 909
    return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
910 910
}
......
1020 1020
 * * Socket#accept
1021 1021
 */
1022 1022
static VALUE
1023
sock_sysaccept(VALUE sock)
1023
sock_sysaccept(int argc, VALUE *argv, VALUE sock)
1024 1024
{
1025 1025
    rb_io_t *fptr;
1026 1026
    VALUE sock2;
......
1028 1028
    socklen_t len = (socklen_t)sizeof buf;
1029 1029

  
1030 1030
    GetOpenFile(sock, fptr);
1031
    sock2 = rsock_s_accept(0,fptr->fd,&buf.addr,&len);
1031
    sock2 = rsock_s_accept(argc, argv, 0, fptr->fd, &buf.addr, &len);
1032 1032

  
1033 1033
    return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
1034 1034
}
......
2175 2175
    rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, -1);
2176 2176
    rb_define_method(rb_cSocket, "bind", sock_bind, 1);
2177 2177
    rb_define_method(rb_cSocket, "listen", rsock_sock_listen, 1);
2178
    rb_define_method(rb_cSocket, "accept", sock_accept, 0);
2178
    rb_define_method(rb_cSocket, "accept", sock_accept, -1);
2179 2179
    rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, -1);
2180
    rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
2180
    rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, -1);
2181 2181

  
2182 2182
    rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
2183 2183
    rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
ext/socket/tcpserver.c
53 53
 *
54 54
 */
55 55
static VALUE
56
tcp_accept(VALUE sock)
56
tcp_accept(int argc, VALUE *argv, VALUE sock)
57 57
{
58 58
    rb_io_t *fptr;
59 59
    union_sockaddr from;
......
61 61

  
62 62
    GetOpenFile(sock, fptr);
63 63
    fromlen = (socklen_t)sizeof(from);
64
    return rsock_s_accept(rb_cTCPSocket, fptr->fd, &from.addr, &fromlen);
64
    return rsock_s_accept(argc, argv, rb_cTCPSocket,
65
                          fptr->fd, &from.addr, &fromlen);
65 66
}
66 67

  
67 68
/*
......
128 129
 *
129 130
 */
130 131
static VALUE
131
tcp_sysaccept(VALUE sock)
132
tcp_sysaccept(int argc, VALUE *argv, VALUE sock)
132 133
{
133 134
    rb_io_t *fptr;
134 135
    union_sockaddr from;
......
136 137

  
137 138
    GetOpenFile(sock, fptr);
138 139
    fromlen = (socklen_t)sizeof(from);
139
    return rsock_s_accept(0, fptr->fd, &from.addr, &fromlen);
140
    return rsock_s_accept(argc, argv, 0, fptr->fd, &from.addr, &fromlen);
140 141
}
141 142

  
142 143
void
......
174 175
     *
175 176
     */
176 177
    rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket);
177
    rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0);
178
    rb_define_method(rb_cTCPServer, "accept", tcp_accept, -1);
178 179
    rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, -1);
179
    rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0);
180
    rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, -1);
180 181
    rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1);
181 182
    rb_define_method(rb_cTCPServer, "listen", rsock_sock_listen, 1); /* in socket.c */
182 183
}
ext/socket/unixserver.c
45 45
 *
46 46
 */
47 47
static VALUE
48
unix_accept(VALUE sock)
48
unix_accept(int argc, VALUE *argv, VALUE sock)
49 49
{
50 50
    rb_io_t *fptr;
51 51
    struct sockaddr_un from;
......
53 53

  
54 54
    GetOpenFile(sock, fptr);
55 55
    fromlen = (socklen_t)sizeof(struct sockaddr_un);
56
    return rsock_s_accept(rb_cUNIXSocket, fptr->fd,
56
    return rsock_s_accept(argc, argv, rb_cUNIXSocket, fptr->fd,
57 57
		          (struct sockaddr*)&from, &fromlen);
58 58
}
59 59

  
......
126 126
 *
127 127
 */
128 128
static VALUE
129
unix_sysaccept(VALUE sock)
129
unix_sysaccept(int argc, VALUE *argv, VALUE sock)
130 130
{
131 131
    rb_io_t *fptr;
132 132
    struct sockaddr_un from;
......
134 134

  
135 135
    GetOpenFile(sock, fptr);
136 136
    fromlen = (socklen_t)sizeof(struct sockaddr_un);
137
    return rsock_s_accept(0, fptr->fd, (struct sockaddr*)&from, &fromlen);
137
    return rsock_s_accept(argc, argv, 0, fptr->fd,
138
                          (struct sockaddr*)&from, &fromlen);
138 139
}
139 140

  
140 141
#endif
......
151 152
     */
152 153
    rb_cUNIXServer = rb_define_class("UNIXServer", rb_cUNIXSocket);
153 154
    rb_define_method(rb_cUNIXServer, "initialize", unix_svr_init, 1);
154
    rb_define_method(rb_cUNIXServer, "accept", unix_accept, 0);
155
    rb_define_method(rb_cUNIXServer, "accept", unix_accept, -1);
155 156
    rb_define_method(rb_cUNIXServer, "accept_nonblock", unix_accept_nonblock, -1);
156
    rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, 0);
157
    rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, -1);
157 158
    rb_define_method(rb_cUNIXServer, "listen", rsock_sock_listen, 1); /* in socket.c */
158 159
#endif
159 160
}
test/socket/test_nonblock.rb
26 26
      s, sockaddr = serv.accept_nonblock
27 27
    end
28 28
    assert_equal(Socket.unpack_sockaddr_in(c.getsockname), Socket.unpack_sockaddr_in(sockaddr))
29
    if s.respond_to?(:nonblock?)
30
      assert_predicate(s, :nonblock?, 'accepted socket is non-blocking')
29

  
30
    assert_predicate(s, :nonblock?, 'default behavior should be non-blocking')
31

  
32
    [ true, false ].each do |nb|
33
      begin
34
        b = Socket.new(:INET, :STREAM)
35
        b.connect(serv.getsockname)
36
        serv.wait_readable
37
        a, _ = serv.accept_nonblock(sock_nonblock: nb)
38
        assert_equal nb, a.nonblock?
39
      ensure
40
        a.close if a
41
        b.close if b
42
      end
31 43
    end
32 44
  ensure
33 45
    serv.close if serv
......
392 404
    s.close if s && !s.closed?
393 405
  end
394 406

  
407
  def test_accept_sock_nonblock
408
    serv = Socket.new(:INET, :STREAM)
409
    serv.bind(Socket.sockaddr_in(0, "127.0.0.1"))
410
    serv.listen(5)
411
    begin
412
      s, _ = serv.accept_nonblock
413
    rescue Errno::EWOULDBLOCK
414
      assert_kind_of(IO::WaitReadable, $!)
415
    end
416
  ensure
417
    serv.close if serv && !serv.closed?
418
    s.close if s && !s.closed?
419
  end
420

  
421
  def test_accept_blocking_sock_nonblock
422
    serv = Socket.new(:INET, :STREAM)
423
    serv.bind(Socket.sockaddr_in(0, "127.0.0.1"))
424
    serv.listen(5)
425

  
426
    begin
427
      b = Socket.new(:INET, :STREAM)
428
      b.connect(serv.getsockname)
429
      a, _ = serv.accept
430
      refute_predicate a, :nonblock?
431
    ensure
432
      a.close
433
      b.close
434
    end
435

  
436
    begin
437
      b = Socket.new(:INET, :STREAM)
438
      b.connect(serv.getsockname)
439
      a, _ = serv.sysaccept
440
      a = Socket.for_fd(a)
441
      refute_predicate a, :nonblock?
442
    ensure
443
      a.close
444
      b.close
445
    end
446

  
447
    [ true, false ].each do |nb|
448
      begin
449
        b = Socket.new(:INET, :STREAM)
450
        b.connect(serv.getsockname)
451
        serv.wait_readable
452
        a, _ = serv.accept(sock_nonblock: nb)
453
        assert_equal nb, a.nonblock?
454
      ensure
455
        a.close if a
456
        b.close if b
457
      end
458

  
459
      begin
460
        b = Socket.new(:INET, :STREAM)
461
        b.connect(serv.getsockname)
462
        serv.wait_readable
463
        a, _ = serv.sysaccept(sock_nonblock: nb)
464
        a = Socket.for_fd(a)
465
        assert_equal nb, a.nonblock?
466
      ensure
467
        a.close if a
468
        b.close if b
469
      end
470
    end
471
  ensure
472
    serv.close
473
  end
395 474
end if defined?(Socket)
test/socket/test_tcp.rb
4 4
rescue LoadError
5 5
end
6 6

  
7
require "io/wait"
8
require "io/nonblock"
7 9

  
8 10
class TestSocket_TCPSocket < Test::Unit::TestCase
9 11
  def test_initialize_failure
......
82 84
      assert_raise(IO::WaitReadable) { svr.accept_nonblock }
83 85
      assert_equal :wait_readable, svr.accept_nonblock(exception: false)
84 86
      assert_raise(IO::WaitReadable) { svr.accept_nonblock(exception: true) }
87
      addr = svr.addr
88
      host, port = addr[3], addr[1]
89

  
90
      begin
91
        c = TCPSocket.new(host, port)
92
        svr.wait_readable
93
        a = svr.accept_nonblock
94
        assert_predicate a, :nonblock?, 'default behavior'
95
      ensure
96
        c.close if c
97
        a.close if a
98
      end
99

  
100
      [ true, false ].each do |nb|
101
        begin
102
          c = TCPSocket.new(host, port)
103
          svr.wait_readable
104
          a = svr.accept_nonblock(sock_nonblock: nb)
105
          assert_equal nb, a.nonblock?
106
        ensure
107
          c.close if c
108
          a.close if a
109
        end
110
      end
85 111
    }
86 112
  end
113

  
114
  def test_accept_sock_nonblock
115
    TCPServer.open("localhost", 0) do |svr|
116
      addr = svr.addr
117
      host, port = addr[3], addr[1]
118

  
119
      begin
120
        c = TCPSocket.new(host, port)
121
        a = svr.accept
122
        refute_predicate a, :nonblock?, 'default behavior'
123
      ensure
124
        c.close if c
125
        a.close if a
126
      end
127

  
128
      [ true, false ].each do |nb|
129
        begin
130
          c = TCPSocket.new(host, port)
131
          a = svr.accept(sock_nonblock: nb)
132
          assert_equal nb, a.nonblock?
133
        ensure
134
          c.close if c
135
          a.close if a
136
        end
137
      end
138
    end
139
  end
87 140
end if defined?(TCPSocket)
test/socket/test_unix.rb
9 9
require "tmpdir"
10 10
require "thread"
11 11
require "io/nonblock"
12
require "io/wait"
12 13

  
13 14
class TestSocket_UNIXSocket < Test::Unit::TestCase
14 15
  def test_fd_passing
......
675 676
      assert_raise(IO::WaitReadable) { serv.accept_nonblock }
676 677
      assert_raise(IO::WaitReadable) { serv.accept_nonblock(exception: true) }
677 678
      assert_equal :wait_readable, serv.accept_nonblock(exception: false)
679

  
680
      begin
681
        c = UNIXSocket.new(path)
682
        serv.wait_readable
683
        a = serv.accept_nonblock
684
        assert_predicate a, :nonblock?, 'default behavior'
685
      ensure
686
        c.close if c
687
        a.close if a
688
      end
689

  
690
      [ true, false ].each do |nb|
691
        begin
692
          c = UNIXSocket.new(path)
693
          serv.wait_readable
694
          a = serv.accept_nonblock(sock_nonblock: nb)
695
          assert_equal nb, a.nonblock?
696
        ensure
697
          c.close if c
698
          a.close if a
699
        end
700
      end
678 701
    }
679 702
  end
703

  
704
  def test_accept_sock_nonblock
705
    bound_unix_socket(UNIXServer) do |serv, path|
706
      begin
707
        c = UNIXSocket.new(path)
708
        a = serv.accept
709
        refute_predicate a, :nonblock?, 'default behavior'
710
      ensure
711
        c.close if c
712
        a.close if a
713
      end
714

  
715
      begin
716
        c = UNIXSocket.new(path)
717
        a = serv.sysaccept
718
        a = UNIXSocket.for_fd(a)
719
        refute_predicate a, :nonblock?, 'default behavior'
720
      ensure
721
        c.close if c
722
        a.close if a
723
      end
724

  
725
      [ true, false ].each do |nb|
726
        begin
727
          c = UNIXSocket.new(path)
728
          a = serv.accept(sock_nonblock: nb)
729
          assert_equal nb, a.nonblock?
730
        ensure
731
          c.close if c
732
          a.close if a
733
        end
734

  
735
        begin
736
          c = UNIXSocket.new(path)
737
          a = serv.sysaccept(sock_nonblock: nb)
738
          a = UNIXSocket.for_fd(a)
739
          assert_equal nb, a.nonblock?
740
        ensure
741
          c.close if c
742
          a.close if a
743
        end
744
      end
745
    end
746
  end
680 747
end if defined?(UNIXSocket) && /cygwin/ !~ RUBY_PLATFORM
681
-