Project

General

Profile

Feature #11242 ยป 0001-socket-allow-explicit-buffer-for-recv-and-recv_nonbl.patch

normalperson (Eric Wong), 06/10/2015 12:43 AM

View differences:

ext/socket/basicsocket.c
615 615

  
616 616
/*
617 617
 * call-seq:
618
 *   basicsocket.recv(maxlen) => mesg
619
 *   basicsocket.recv(maxlen, flags) => mesg
618
 *   basicsocket.recv(maxlen[, flags[, outbuf]]) => mesg
620 619
 *
621 620
 * Receives a message.
622 621
 *
......
624 623
 *
625 624
 * _flags_ should be a bitwise OR of Socket::MSG_* constants.
626 625
 *
626
 * _outbuf_ will contain only the received data after the method call
627
 * even if it is not empty at the beginning.
628
 *
627 629
 *   UNIXSocket.pair {|s1, s2|
628 630
 *     s1.puts "Hello World"
629 631
 *     p s2.recv(4)                     #=> "Hell"
ext/socket/init.c
108 108
    return (VALUE)ret;
109 109
}
110 110

  
111
static VALUE
112
rsock_strbuf(VALUE str, long buflen)
113
{
114
    long len;
115

  
116
    if (NIL_P(str)) return rb_tainted_str_new(0, buflen);
117

  
118
    StringValue(str);
119
    len = RSTRING_LEN(str);
120
    if (len >= buflen) {
121
	rb_str_modify(str);
122
    } else {
123
	rb_str_modify_expand(str, buflen - len);
124
    }
125
    rb_str_set_len(str, buflen);
126
    return str;
127
}
128

  
129
static VALUE
130
recvfrom_locktmp(VALUE v)
131
{
132
  struct recvfrom_arg *arg = (struct recvfrom_arg *)v;
133

  
134
  return rb_thread_io_blocking_region(recvfrom_blocking, arg, arg->fd);
135
}
136

  
111 137
VALUE
112 138
rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
113 139
{
114 140
    rb_io_t *fptr;
115
    VALUE str, klass;
141
    VALUE str;
116 142
    struct recvfrom_arg arg;
117 143
    VALUE len, flg;
118 144
    long buflen;
119 145
    long slen;
120 146

  
121
    rb_scan_args(argc, argv, "11", &len, &flg);
147
    rb_scan_args(argc, argv, "12", &len, &flg, &str);
122 148

  
123 149
    if (flg == Qnil) arg.flags = 0;
124 150
    else             arg.flags = NUM2INT(flg);
125 151
    buflen = NUM2INT(len);
152
    str = rsock_strbuf(str, buflen);
126 153

  
127 154
    GetOpenFile(sock, fptr);
128 155
    if (rb_io_read_pending(fptr)) {
......
130 157
    }
131 158
    arg.fd = fptr->fd;
132 159
    arg.alen = (socklen_t)sizeof(arg.buf);
133

  
134
    arg.str = str = rb_tainted_str_new(0, buflen);
135
    klass = RBASIC(str)->klass;
136
    rb_obj_hide(str);
160
    arg.str = str;
137 161

  
138 162
    while (rb_io_check_closed(fptr),
139 163
	   rsock_maybe_wait_fd(arg.fd),
140
	   (slen = BLOCKING_REGION_FD(recvfrom_blocking, &arg)) < 0) {
164
	   (slen = (long)rb_str_locktmp_ensure(str, recvfrom_locktmp,
165
	                                       (VALUE)&arg)) < 0) {
141 166
        if (!rb_io_wait_readable(fptr->fd)) {
142 167
            rb_sys_fail("recvfrom(2)");
143 168
        }
144
	if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) {
145
	    rb_raise(rb_eRuntimeError, "buffer string modified");
146
	}
147 169
    }
148 170

  
149
    rb_obj_reveal(str, klass);
150
    if (slen < RSTRING_LEN(str)) {
171
    if (slen != RSTRING_LEN(str)) {
151 172
	rb_str_set_len(str, slen);
152 173
    }
153 174
    rb_obj_taint(str);
......
191 212
    VALUE opts = Qnil;
192 213
    socklen_t len0;
193 214

  
194
    rb_scan_args(argc, argv, "11:", &len, &flg, &opts);
215
    rb_scan_args(argc, argv, "12:", &len, &flg, &str, &opts);
195 216

  
196 217
    if (flg == Qnil) flags = 0;
197 218
    else             flags = NUM2INT(flg);
198 219
    buflen = NUM2INT(len);
220
    str = rsock_strbuf(str, buflen);
199 221

  
200 222
#ifdef MSG_DONTWAIT
201 223
    /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom.
......
209 231
    }
210 232
    fd = fptr->fd;
211 233

  
212
    str = rb_tainted_str_new(0, buflen);
213

  
214 234
    rb_io_check_closed(fptr);
215 235

  
216 236
    if (!MSG_DONTWAIT_RELIABLE)
......
233 253
	}
234 254
	rb_sys_fail("recvfrom(2)");
235 255
    }
236
    if (slen < RSTRING_LEN(str)) {
256
    if (slen != RSTRING_LEN(str)) {
237 257
	rb_str_set_len(str, slen);
238 258
    }
239 259
    rb_obj_taint(str);
ext/socket/unixsocket.c
131 131

  
132 132
/*
133 133
 * call-seq:
134
 *   unixsocket.recvfrom(maxlen [, flags]) => [mesg, unixaddress]
134
 *   unixsocket.recvfrom(maxlen [, flags[, outbuf]) => [mesg, unixaddress]
135 135
 *
136 136
 * Receives a message via _unixsocket_.
137 137
 *
......
139 139
 *
140 140
 * _flags_ should be a bitwise OR of Socket::MSG_* constants.
141 141
 *
142
 * _outbuf_ will contain only the received data after the method call
143
 * even if it is not empty at the beginning.
144
 *
142 145
 *   s1 = Socket.new(:UNIX, :DGRAM, 0)
143 146
 *   s1_ai = Addrinfo.unix("/tmp/sock1")
144 147
 *   s1.bind(s1_ai)
string.c
2107 2107
    return str;
2108 2108
}
2109 2109

  
2110
VALUE
2110
RUBY_FUNC_EXPORTED VALUE
2111 2111
rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg)
2112 2112
{
2113 2113
    rb_str_locktmp(str);
test/socket/test_nonblock.rb
128 128
    }
129 129
    mesg = u1.recv_nonblock(100)
130 130
    assert_equal("", mesg)
131

  
132
    buf = "short"
133
    out = "hello world" * 4
134
    out.freeze
135
    u2.send(out, 0, u1.getsockname)
136
    IO.select [u1]
137
    rv = u1.recv_nonblock(100, 0, buf)
138
    assert_equal rv.object_id, buf.object_id
139
    assert_equal out, rv
140
    assert_equal out, buf
131 141
  ensure
132 142
    u1.close if u1
133 143
    u2.close if u2
test/socket/test_unix.rb
385 385
    assert_equal("", s1.recv(10))
386 386
    assert_equal("", s1.recv(10))
387 387
    assert_raise(IO::EAGAINWaitReadable) { s1.recv_nonblock(10) }
388

  
389
    buf = ""
390
    s2.send("BBBBBB", 0)
391
    sleep 0.1
392
    rv = s1.recv(100, 0, buf)
393
    assert_equal buf.object_id, rv.object_id
394
    assert_equal "BBBBBB", rv
388 395
  ensure
389 396
    s1.close if s1
390 397
    s2.close if s2
391
-