~ubuntu-branches/ubuntu/quantal/ruby1.9.1/quantal

« back to all changes in this revision

Viewing changes to ext/socket/basicsocket.c

  • Committer: Bazaar Package Importer
  • Author(s): Lucas Nussbaum
  • Date: 2010-07-31 17:08:39 UTC
  • mfrom: (1.1.4 upstream) (8.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100731170839-j034dmpdqt1cc4p6
Tags: 1.9.2~svn28788-1
* New release based on upstream snapshot from the 1.9.2 branch,
  after 1.9.2 RC2. That branch is (supposed to be) binary-compatible
  with the 1.9.1 branch.
  + Builds fine on i386. Closes: #580852.
* Upgrade to Standards-Version: 3.9.1. No changes needed.
* Updated generated incs.
* Patches that still need work:
  + Unclear status, need more investigation:
   090729_fix_Makefile_deps.dpatch
   090803_exclude_rdoc.dpatch
   203_adjust_base_of_search_path.dpatch
   902_define_YAML_in_yaml_stringio.rb.dpatch
   919_common.mk_tweaks.dpatch
   931_libruby_suffix.dpatch
   940_test_thread_mutex_sync_shorter.dpatch
  + Maybe not needed anymore, keeping but not applying.
   102_skip_test_copy_stream.dpatch (test doesn't block anymore?)
   104_skip_btest_io.dpatch (test doesn't block anymore?)
   201_gem_prelude.dpatch (we don't use that rubygems anyway?)
   202_gem_default_dir.dpatch (we don't use that rubygems anyway?)
   940_test_file_exhaustive_fails_as_root.dpatch
   940_test_priority_fails.dpatch
   100518_load_libc_libm.dpatch
* Add disable-tests.diff: disable some tests that cause failures on FreeBSD.
  Closes: #590002, #543805, #542927.
* However, many new failures on FreeBSD. Since that version is still an
  improvement, add the check that makes test suite failures non-fatal on
  FreeBSD again. That still needs to be investigated.
* Re-add 903_skip_base_ruby_check.dpatch
* Add build-dependency on ruby1.8 and drop all pre-generated files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/************************************************
 
2
 
 
3
  basicsocket.c -
 
4
 
 
5
  created at: Thu Mar 31 12:21:29 JST 1994
 
6
 
 
7
  Copyright (C) 1993-2007 Yukihiro Matsumoto
 
8
 
 
9
************************************************/
 
10
 
 
11
#include "rubysocket.h"
 
12
 
 
13
/*
 
14
 * call-seq:
 
15
 *   BasicSocket.for_fd(fd) => basicsocket
 
16
 *
 
17
 * Returns a socket object which contains the file descriptor, _fd_.
 
18
 *
 
19
 *   # If invoked by inetd, STDIN/STDOUT/STDERR is a socket.
 
20
 *   STDIN_SOCK = Socket.for_fd(STDIN.fileno)
 
21
 *   p STDIN_SOCK.remote_address
 
22
 *
 
23
 */
 
24
static VALUE
 
25
bsock_s_for_fd(VALUE klass, VALUE fd)
 
26
{
 
27
    rb_io_t *fptr;
 
28
    VALUE sock = rsock_init_sock(rb_obj_alloc(klass), NUM2INT(fd));
 
29
 
 
30
    GetOpenFile(sock, fptr);
 
31
 
 
32
    return sock;
 
33
}
 
34
 
 
35
/*
 
36
 * call-seq:
 
37
 *   basicsocket.shutdown([how]) => 0
 
38
 *
 
39
 * Calls shutdown(2) system call.
 
40
 *
 
41
 * s.shutdown(Socket::SHUT_RD) disallows further read.
 
42
 *
 
43
 * s.shutdown(Socket::SHUT_WR) disallows further write.
 
44
 *
 
45
 * s.shutdown(Socket::SHUT_RDWR) disallows further read and write.
 
46
 *
 
47
 * _how_ can be symbol or string:
 
48
 * - :RD, :SHUT_RD, "RD" and "SHUT_RD" are accepted as Socket::SHUT_RD.
 
49
 * - :WR, :SHUT_WR, "WR" and "SHUT_WR" are accepted as Socket::SHUT_WR.
 
50
 * - :RDWR, :SHUT_RDWR, "RDWR" and "SHUT_RDWR" are accepted as Socket::SHUT_RDWR.
 
51
 *
 
52
 *   UNIXSocket.pair {|s1, s2|
 
53
 *     s1.puts "ping"
 
54
 *     s1.shutdown(:WR)
 
55
 *     p s2.read          #=> "ping\n"
 
56
 *     s2.puts "pong"
 
57
 *     s2.close
 
58
 *     p s1.read          #=> "pong\n"
 
59
 *   }
 
60
 *
 
61
 */
 
62
static VALUE
 
63
bsock_shutdown(int argc, VALUE *argv, VALUE sock)
 
64
{
 
65
    VALUE howto;
 
66
    int how;
 
67
    rb_io_t *fptr;
 
68
 
 
69
    if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
 
70
        rb_raise(rb_eSecurityError, "Insecure: can't shutdown socket");
 
71
    }
 
72
    rb_scan_args(argc, argv, "01", &howto);
 
73
    if (howto == Qnil)
 
74
        how = SHUT_RDWR;
 
75
    else {
 
76
        how = rsock_shutdown_how_arg(howto);
 
77
        if (how != SHUT_WR && how != SHUT_RD && how != SHUT_RDWR) {
 
78
            rb_raise(rb_eArgError, "`how' should be either :SHUT_RD, :SHUT_WR, :SHUT_RDWR");
 
79
        }
 
80
    }
 
81
    GetOpenFile(sock, fptr);
 
82
    if (shutdown(fptr->fd, how) == -1)
 
83
        rb_sys_fail(0);
 
84
 
 
85
    return INT2FIX(0);
 
86
}
 
87
 
 
88
/*
 
89
 * call-seq:
 
90
 *   basicsocket.close_read => nil
 
91
 *
 
92
 * Disallows further read using shutdown system call.
 
93
 *
 
94
 *   s1, s2 = UNIXSocket.pair
 
95
 *   s1.close_read
 
96
 *   s2.puts #=> Broken pipe (Errno::EPIPE)
 
97
 */
 
98
static VALUE
 
99
bsock_close_read(VALUE sock)
 
100
{
 
101
    rb_io_t *fptr;
 
102
 
 
103
    if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
 
104
        rb_raise(rb_eSecurityError, "Insecure: can't close socket");
 
105
    }
 
106
    GetOpenFile(sock, fptr);
 
107
    shutdown(fptr->fd, 0);
 
108
    if (!(fptr->mode & FMODE_WRITABLE)) {
 
109
        return rb_io_close(sock);
 
110
    }
 
111
    fptr->mode &= ~FMODE_READABLE;
 
112
 
 
113
    return Qnil;
 
114
}
 
115
 
 
116
/*
 
117
 * call-seq:
 
118
 *   basicsocket.close_write => nil
 
119
 *
 
120
 * Disallows further write using shutdown system call.
 
121
 *
 
122
 *   UNIXSocket.pair {|s1, s2|
 
123
 *     s1.print "ping"
 
124
 *     s1.close_write
 
125
 *     p s2.read        #=> "ping"
 
126
 *     s2.print "pong"
 
127
 *     s2.close
 
128
 *     p s1.read        #=> "pong"
 
129
 *   }
 
130
 */
 
131
static VALUE
 
132
bsock_close_write(VALUE sock)
 
133
{
 
134
    rb_io_t *fptr;
 
135
 
 
136
    if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
 
137
        rb_raise(rb_eSecurityError, "Insecure: can't close socket");
 
138
    }
 
139
    GetOpenFile(sock, fptr);
 
140
    if (!(fptr->mode & FMODE_READABLE)) {
 
141
        return rb_io_close(sock);
 
142
    }
 
143
    shutdown(fptr->fd, 1);
 
144
    fptr->mode &= ~FMODE_WRITABLE;
 
145
 
 
146
    return Qnil;
 
147
}
 
148
 
 
149
/*
 
150
 * Document-method: setsockopt
 
151
 * call-seq:
 
152
 *   setsockopt(level, optname, optval)
 
153
 *   setsockopt(socketoption)
 
154
 *
 
155
 * Sets a socket option. These are protocol and system specific, see your
 
156
 * local system documentation for details.
 
157
 *
 
158
 * === Parameters
 
159
 * * +level+ is an integer, usually one of the SOL_ constants such as
 
160
 *   Socket::SOL_SOCKET, or a protocol level.
 
161
 *   A string or symbol of the name, possibly without prefix, is also
 
162
 *   accepted.
 
163
 * * +optname+ is an integer, usually one of the SO_ constants, such
 
164
 *   as Socket::SO_REUSEADDR.
 
165
 *   A string or symbol of the name, possibly without prefix, is also
 
166
 *   accepted.
 
167
 * * +optval+ is the value of the option, it is passed to the underlying
 
168
 *   setsockopt() as a pointer to a certain number of bytes. How this is
 
169
 *   done depends on the type:
 
170
 *   - Fixnum: value is assigned to an int, and a pointer to the int is
 
171
 *     passed, with length of sizeof(int).
 
172
 *   - true or false: 1 or 0 (respectively) is assigned to an int, and the
 
173
 *     int is passed as for a Fixnum. Note that +false+ must be passed,
 
174
 *     not +nil+.
 
175
 *   - String: the string's data and length is passed to the socket.
 
176
 * * +socketoption+ is an instance of Socket::Option
 
177
 *
 
178
 * === Examples
 
179
 *
 
180
 * Some socket options are integers with boolean values, in this case
 
181
 * #setsockopt could be called like this:
 
182
 *   sock.setsockopt(:SOCKET, :REUSEADDR, true)
 
183
 *   sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
 
184
 *   sock.setsockopt(Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true))
 
185
 *
 
186
 * Some socket options are integers with numeric values, in this case
 
187
 * #setsockopt could be called like this:
 
188
 *   sock.setsockopt(:IP, :TTL, 255)
 
189
 *   sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255)
 
190
 *   sock.setsockopt(Socket::Option.int(:INET, :IP, :TTL, 255))
 
191
 *
 
192
 * Option values may be structs. Passing them can be complex as it involves
 
193
 * examining your system headers to determine the correct definition. An
 
194
 * example is an +ip_mreq+, which may be defined in your system headers as:
 
195
 *   struct ip_mreq {
 
196
 *     struct  in_addr imr_multiaddr;
 
197
 *     struct  in_addr imr_interface;
 
198
 *   };
 
199
 *
 
200
 * In this case #setsockopt could be called like this:
 
201
 *   optval = IPAddr.new("224.0.0.251").hton +
 
202
 *            IPAddr.new(Socket::INADDR_ANY, Socket::AF_INET).hton
 
203
 *   sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, optval)
 
204
 *
 
205
*/
 
206
static VALUE
 
207
bsock_setsockopt(int argc, VALUE *argv, VALUE sock)
 
208
{
 
209
    VALUE lev, optname, val;
 
210
    int family, level, option;
 
211
    rb_io_t *fptr;
 
212
    int i;
 
213
    char *v;
 
214
    int vlen;
 
215
 
 
216
    if (argc == 1) {
 
217
        lev = rb_funcall(argv[0], rb_intern("level"), 0);
 
218
        optname = rb_funcall(argv[0], rb_intern("optname"), 0);
 
219
        val = rb_funcall(argv[0], rb_intern("data"), 0);
 
220
    }
 
221
    else {
 
222
        rb_scan_args(argc, argv, "30", &lev, &optname, &val);
 
223
    }
 
224
 
 
225
    rb_secure(2);
 
226
    GetOpenFile(sock, fptr);
 
227
    family = rsock_getfamily(fptr->fd);
 
228
    level = rsock_level_arg(family, lev);
 
229
    option = rsock_optname_arg(family, level, optname);
 
230
 
 
231
    switch (TYPE(val)) {
 
232
      case T_FIXNUM:
 
233
        i = FIX2INT(val);
 
234
        goto numval;
 
235
      case T_FALSE:
 
236
        i = 0;
 
237
        goto numval;
 
238
      case T_TRUE:
 
239
        i = 1;
 
240
      numval:
 
241
        v = (char*)&i; vlen = (int)sizeof(i);
 
242
        break;
 
243
      default:
 
244
        StringValue(val);
 
245
        v = RSTRING_PTR(val);
 
246
        vlen = RSTRING_LENINT(val);
 
247
        break;
 
248
    }
 
249
 
 
250
#define rb_sys_fail_path(path) rb_sys_fail(NIL_P(path) ? 0 : RSTRING_PTR(path))
 
251
 
 
252
    rb_io_check_closed(fptr);
 
253
    if (setsockopt(fptr->fd, level, option, v, vlen) < 0)
 
254
        rb_sys_fail_path(fptr->pathv);
 
255
 
 
256
    return INT2FIX(0);
 
257
}
 
258
 
 
259
#if !defined(__BEOS__)
 
260
/*
 
261
 * Document-method: getsockopt
 
262
 * call-seq:
 
263
 *   getsockopt(level, optname) => socketoption
 
264
 *
 
265
 * Gets a socket option. These are protocol and system specific, see your
 
266
 * local system documentation for details. The option is returned as
 
267
 * a Socket::Option object.
 
268
 *
 
269
 * === Parameters
 
270
 * * +level+ is an integer, usually one of the SOL_ constants such as
 
271
 *   Socket::SOL_SOCKET, or a protocol level.
 
272
 *   A string or symbol of the name, possibly without prefix, is also
 
273
 *   accepted.
 
274
 * * +optname+ is an integer, usually one of the SO_ constants, such
 
275
 *   as Socket::SO_REUSEADDR.
 
276
 *   A string or symbol of the name, possibly without prefix, is also
 
277
 *   accepted.
 
278
 *
 
279
 * === Examples
 
280
 *
 
281
 * Some socket options are integers with boolean values, in this case
 
282
 * #getsockopt could be called like this:
 
283
 *
 
284
 *   reuseaddr = sock.getsockopt(:SOCKET, :REUSEADDR).bool
 
285
 *
 
286
 *   optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR)
 
287
 *   optval = optval.unpack "i"
 
288
 *   reuseaddr = optval[0] == 0 ? false : true
 
289
 *
 
290
 * Some socket options are integers with numeric values, in this case
 
291
 * #getsockopt could be called like this:
 
292
 *
 
293
 *   ipttl = sock.getsockopt(:IP, :TTL).int
 
294
 *
 
295
 *   optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
 
296
 *   ipttl = optval.unpack("i")[0]
 
297
 *
 
298
 * Option values may be structs. Decoding them can be complex as it involves
 
299
 * examining your system headers to determine the correct definition. An
 
300
 * example is a +struct linger+, which may be defined in your system headers
 
301
 * as:
 
302
 *   struct linger {
 
303
 *     int l_onoff;
 
304
 *     int l_linger;
 
305
 *   };
 
306
 *
 
307
 * In this case #getsockopt could be called like this:
 
308
 *
 
309
 *   # Socket::Option knows linger structure.
 
310
 *   onoff, linger = sock.getsockopt(:SOCKET, :LINGER).linger
 
311
 *
 
312
 *   optval =  sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER)
 
313
 *   onoff, linger = optval.unpack "ii"
 
314
 *   onoff = onoff == 0 ? false : true
 
315
*/
 
316
static VALUE
 
317
bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname)
 
318
{
 
319
    int level, option;
 
320
    socklen_t len;
 
321
    char *buf;
 
322
    rb_io_t *fptr;
 
323
    int family;
 
324
 
 
325
    GetOpenFile(sock, fptr);
 
326
    family = rsock_getfamily(fptr->fd);
 
327
    level = rsock_level_arg(family, lev);
 
328
    option = rsock_optname_arg(family, level, optname);
 
329
    len = 256;
 
330
    buf = ALLOCA_N(char,len);
 
331
 
 
332
    rb_io_check_closed(fptr);
 
333
 
 
334
    if (getsockopt(fptr->fd, level, option, buf, &len) < 0)
 
335
        rb_sys_fail_path(fptr->pathv);
 
336
 
 
337
    return rsock_sockopt_new(family, level, option, rb_str_new(buf, len));
 
338
}
 
339
#else
 
340
#define bsock_getsockopt rb_f_notimplement
 
341
#endif
 
342
 
 
343
/*
 
344
 * call-seq:
 
345
 *   basicsocket.getsockname => sockaddr
 
346
 *
 
347
 * Returns the local address of the socket as a sockaddr string.
 
348
 *
 
349
 *   TCPServer.open("127.0.0.1", 15120) {|serv|
 
350
 *     p serv.getsockname #=> "\x02\x00;\x10\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
 
351
 *   }
 
352
 *
 
353
 * If Addrinfo object is preferred over the binary string,
 
354
 * use BasicSocket#local_address.
 
355
 */
 
356
static VALUE
 
357
bsock_getsockname(VALUE sock)
 
358
{
 
359
    struct sockaddr_storage buf;
 
360
    socklen_t len = (socklen_t)sizeof buf;
 
361
    rb_io_t *fptr;
 
362
 
 
363
    GetOpenFile(sock, fptr);
 
364
    if (getsockname(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
 
365
        rb_sys_fail("getsockname(2)");
 
366
    return rb_str_new((char*)&buf, len);
 
367
}
 
368
 
 
369
/*
 
370
 * call-seq:
 
371
 *   basicsocket.getpeername => sockaddr
 
372
 *
 
373
 * Returns the remote address of the socket as a sockaddr string.
 
374
 *
 
375
 *   TCPServer.open("127.0.0.1", 1440) {|serv|
 
376
 *     c = TCPSocket.new("127.0.0.1", 1440)
 
377
 *     s = serv.accept
 
378
 *     p s.getpeername #=> "\x02\x00\x82u\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
 
379
 *   }
 
380
 *
 
381
 * If Addrinfo object is preferred over the binary string,
 
382
 * use BasicSocket#remote_address.
 
383
 *
 
384
 */
 
385
static VALUE
 
386
bsock_getpeername(VALUE sock)
 
387
{
 
388
    struct sockaddr_storage buf;
 
389
    socklen_t len = (socklen_t)sizeof buf;
 
390
    rb_io_t *fptr;
 
391
 
 
392
    GetOpenFile(sock, fptr);
 
393
    if (getpeername(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
 
394
        rb_sys_fail("getpeername(2)");
 
395
    return rb_str_new((char*)&buf, len);
 
396
}
 
397
 
 
398
#if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(HAVE_GETPEERUCRED)
 
399
/*
 
400
 * call-seq:
 
401
 *   basicsocket.getpeereid => [euid, egid]
 
402
 *
 
403
 * Returns the user and group on the peer of the UNIX socket.
 
404
 * The result is a two element array which contains the effective uid and the effective gid.
 
405
 *
 
406
 *   Socket.unix_server_loop("/tmp/sock") {|s|
 
407
 *     begin
 
408
 *       euid, egid = s.getpeereid
 
409
 *
 
410
 *       # Check the connected client is myself or not.
 
411
 *       next if euid != Process.uid
 
412
 *
 
413
 *       # do something about my resource.
 
414
 *
 
415
 *     ensure
 
416
 *       s.close
 
417
 *     end
 
418
 *   }
 
419
 *
 
420
 */
 
421
static VALUE
 
422
bsock_getpeereid(VALUE self)
 
423
{
 
424
#if defined(HAVE_GETPEEREID)
 
425
    rb_io_t *fptr;
 
426
    uid_t euid;
 
427
    gid_t egid;
 
428
    GetOpenFile(self, fptr);
 
429
    if (getpeereid(fptr->fd, &euid, &egid) == -1)
 
430
        rb_sys_fail("getpeereid");
 
431
    return rb_assoc_new(UIDT2NUM(euid), GIDT2NUM(egid));
 
432
#elif defined(SO_PEERCRED) /* GNU/Linux */
 
433
    rb_io_t *fptr;
 
434
    struct ucred cred;
 
435
    socklen_t len = sizeof(cred);
 
436
    GetOpenFile(self, fptr);
 
437
    if (getsockopt(fptr->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
 
438
        rb_sys_fail("getsockopt(SO_PEERCRED)");
 
439
    return rb_assoc_new(UIDT2NUM(cred.uid), GIDT2NUM(cred.gid));
 
440
#elif defined(HAVE_GETPEERUCRED) /* Solaris */
 
441
    rb_io_t *fptr;
 
442
    ucred_t *uc = NULL;
 
443
    VALUE ret;
 
444
    GetOpenFile(self, fptr);
 
445
    if (getpeerucred(fptr->fd, &uc) == -1)
 
446
        rb_sys_fail("getpeerucred");
 
447
    ret = rb_assoc_new(UIDT2NUM(ucred_geteuid(uc)), GIDT2NUM(ucred_getegid(uc)));
 
448
    ucred_free(uc);
 
449
    return ret;
 
450
#endif
 
451
}
 
452
#else
 
453
#define bsock_getpeereid rb_f_notimplement
 
454
#endif
 
455
 
 
456
/*
 
457
 * call-seq:
 
458
 *   bsock.local_address => addrinfo
 
459
 *
 
460
 * Returns an Addrinfo object for local address obtained by getsockname.
 
461
 *
 
462
 * Note that addrinfo.protocol is filled by 0.
 
463
 *
 
464
 *   TCPSocket.open("www.ruby-lang.org", 80) {|s|
 
465
 *     p s.local_address #=> #<Addrinfo: 192.168.0.129:36873 TCP>
 
466
 *   }
 
467
 *
 
468
 *   TCPServer.open("127.0.0.1", 1512) {|serv|
 
469
 *     p serv.local_address #=> #<Addrinfo: 127.0.0.1:1512 TCP>
 
470
 *   }
 
471
 *
 
472
 */
 
473
static VALUE
 
474
bsock_local_address(VALUE sock)
 
475
{
 
476
    struct sockaddr_storage buf;
 
477
    socklen_t len = (socklen_t)sizeof buf;
 
478
    rb_io_t *fptr;
 
479
 
 
480
    GetOpenFile(sock, fptr);
 
481
    if (getsockname(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
 
482
        rb_sys_fail("getsockname(2)");
 
483
    return rsock_fd_socket_addrinfo(fptr->fd, (struct sockaddr *)&buf, len);
 
484
}
 
485
 
 
486
/*
 
487
 * call-seq:
 
488
 *   bsock.remote_address => addrinfo
 
489
 *
 
490
 * Returns an Addrinfo object for remote address obtained by getpeername.
 
491
 *
 
492
 * Note that addrinfo.protocol is filled by 0.
 
493
 *
 
494
 *   TCPSocket.open("www.ruby-lang.org", 80) {|s|
 
495
 *     p s.remote_address #=> #<Addrinfo: 221.186.184.68:80 TCP>
 
496
 *   }
 
497
 *
 
498
 *   TCPServer.open("127.0.0.1", 1728) {|serv|
 
499
 *     c = TCPSocket.new("127.0.0.1", 1728)
 
500
 *     s = serv.accept
 
501
 *     p s.remote_address #=> #<Addrinfo: 127.0.0.1:36504 TCP>
 
502
 *   }
 
503
 *
 
504
 */
 
505
static VALUE
 
506
bsock_remote_address(VALUE sock)
 
507
{
 
508
    struct sockaddr_storage buf;
 
509
    socklen_t len = (socklen_t)sizeof buf;
 
510
    rb_io_t *fptr;
 
511
 
 
512
    GetOpenFile(sock, fptr);
 
513
    if (getpeername(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
 
514
        rb_sys_fail("getpeername(2)");
 
515
    return rsock_fd_socket_addrinfo(fptr->fd, (struct sockaddr *)&buf, len);
 
516
}
 
517
 
 
518
/*
 
519
 * call-seq:
 
520
 *   basicsocket.send(mesg, flags [, dest_sockaddr]) => numbytes_sent
 
521
 *
 
522
 * send _mesg_ via _basicsocket_.
 
523
 *
 
524
 * _mesg_ should be a string.
 
525
 *
 
526
 * _flags_ should be a bitwise OR of Socket::MSG_* constants.
 
527
 *
 
528
 * _dest_sockaddr_ should be a packed sockaddr string or an addrinfo.
 
529
 *
 
530
 *   TCPSocket.open("localhost", 80) {|s|
 
531
 *     s.send "GET / HTTP/1.0\r\n\r\n", 0
 
532
 *     p s.read
 
533
 *   }
 
534
 */
 
535
VALUE
 
536
rsock_bsock_send(int argc, VALUE *argv, VALUE sock)
 
537
{
 
538
    struct rsock_send_arg arg;
 
539
    VALUE flags, to;
 
540
    rb_io_t *fptr;
 
541
    int n;
 
542
    rb_blocking_function_t *func;
 
543
 
 
544
    rb_secure(4);
 
545
    rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);
 
546
 
 
547
    StringValue(arg.mesg);
 
548
    if (!NIL_P(to)) {
 
549
        SockAddrStringValue(to);
 
550
        to = rb_str_new4(to);
 
551
        arg.to = (struct sockaddr *)RSTRING_PTR(to);
 
552
        arg.tolen = (socklen_t)RSTRING_LENINT(to);
 
553
        func = rsock_sendto_blocking;
 
554
    }
 
555
    else {
 
556
        func = rsock_send_blocking;
 
557
    }
 
558
    GetOpenFile(sock, fptr);
 
559
    arg.fd = fptr->fd;
 
560
    arg.flags = NUM2INT(flags);
 
561
    while (rb_thread_fd_writable(arg.fd),
 
562
           (n = (int)BLOCKING_REGION(func, &arg)) < 0) {
 
563
        if (rb_io_wait_writable(arg.fd)) {
 
564
            continue;
 
565
        }
 
566
        rb_sys_fail("send(2)");
 
567
    }
 
568
    return INT2FIX(n);
 
569
}
 
570
 
 
571
/*
 
572
 * call-seq:
 
573
 *   basicsocket.do_not_reverse_lookup => true or false
 
574
 *
 
575
 * Gets the do_not_reverse_lookup flag of _basicsocket_.
 
576
 *
 
577
 *   TCPSocket.open("www.ruby-lang.org", 80) {|sock|
 
578
 *     p sock.do_not_reverse_lookup      #=> false
 
579
 *     p sock.peeraddr                   #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
 
580
 *     sock.do_not_reverse_lookup = true
 
581
 *     p sock.peeraddr                   #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
 
582
 *   }
 
583
 */
 
584
static VALUE
 
585
bsock_do_not_reverse_lookup(VALUE sock)
 
586
{
 
587
    rb_io_t *fptr;
 
588
 
 
589
    GetOpenFile(sock, fptr);
 
590
    return (fptr->mode & FMODE_NOREVLOOKUP) ? Qtrue : Qfalse;
 
591
}
 
592
 
 
593
/*
 
594
 * call-seq:
 
595
 *   basicsocket.do_not_reverse_lookup = bool
 
596
 *
 
597
 * Sets the do_not_reverse_lookup flag of _basicsocket_.
 
598
 *
 
599
 *   BasicSocket.do_not_reverse_lookup = false
 
600
 *   p TCPSocket.new("127.0.0.1", 80).do_not_reverse_lookup #=> false
 
601
 *   BasicSocket.do_not_reverse_lookup = true
 
602
 *   p TCPSocket.new("127.0.0.1", 80).do_not_reverse_lookup #=> true
 
603
 *
 
604
 */
 
605
static VALUE
 
606
bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state)
 
607
{
 
608
    rb_io_t *fptr;
 
609
 
 
610
    rb_secure(4);
 
611
    GetOpenFile(sock, fptr);
 
612
    if (RTEST(state)) {
 
613
        fptr->mode |= FMODE_NOREVLOOKUP;
 
614
    }
 
615
    else {
 
616
        fptr->mode &= ~FMODE_NOREVLOOKUP;
 
617
    }
 
618
    return sock;
 
619
}
 
620
 
 
621
/*
 
622
 * call-seq:
 
623
 *   basicsocket.recv(maxlen) => mesg
 
624
 *   basicsocket.recv(maxlen, flags) => mesg
 
625
 *
 
626
 * Receives a message.
 
627
 *
 
628
 * _maxlen_ is the maximum number of bytes to receive.
 
629
 *
 
630
 * _flags_ should be a bitwise OR of Socket::MSG_* constants.
 
631
 *
 
632
 *   UNIXSocket.pair {|s1, s2|
 
633
 *     s1.puts "Hello World"
 
634
 *     p s2.recv(4)                     #=> "Hell"
 
635
 *     p s2.recv(4, Socket::MSG_PEEK)   #=> "o Wo"
 
636
 *     p s2.recv(4)                     #=> "o Wo"
 
637
 *     p s2.recv(10)                    #=> "rld\n"
 
638
 *   }
 
639
 */
 
640
static VALUE
 
641
bsock_recv(int argc, VALUE *argv, VALUE sock)
 
642
{
 
643
    return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
 
644
}
 
645
 
 
646
/*
 
647
 * call-seq:
 
648
 *      basicsocket.recv_nonblock(maxlen) => mesg
 
649
 *      basicsocket.recv_nonblock(maxlen, flags) => mesg
 
650
 *
 
651
 * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
 
652
 * O_NONBLOCK is set for the underlying file descriptor.
 
653
 * _flags_ is zero or more of the +MSG_+ options.
 
654
 * The result, _mesg_, is the data received.
 
655
 *
 
656
 * When recvfrom(2) returns 0, Socket#recv_nonblock returns
 
657
 * an empty string as data.
 
658
 * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
 
659
 *
 
660
 * === Parameters
 
661
 * * +maxlen+ - the number of bytes to receive from the socket
 
662
 * * +flags+ - zero or more of the +MSG_+ options
 
663
 *
 
664
 * === Example
 
665
 *      serv = TCPServer.new("127.0.0.1", 0)
 
666
 *      af, port, host, addr = serv.addr
 
667
 *      c = TCPSocket.new(addr, port)
 
668
 *      s = serv.accept
 
669
 *      c.send "aaa", 0
 
670
 *      begin # emulate blocking recv.
 
671
 *        p s.recv_nonblock(10) #=> "aaa"
 
672
 *      rescue IO::WaitReadable
 
673
 *        IO.select([s])
 
674
 *        retry
 
675
 *      end
 
676
 *
 
677
 * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
 
678
 * to _recv_nonblock_ fails.
 
679
 *
 
680
 * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
 
681
 * including Errno::EWOULDBLOCK.
 
682
 *
 
683
 * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
 
684
 * it is extended by IO::WaitReadable.
 
685
 * So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
 
686
 *
 
687
 * === See
 
688
 * * Socket#recvfrom
 
689
 */
 
690
 
 
691
static VALUE
 
692
bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
 
693
{
 
694
    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
 
695
}
 
696
 
 
697
/*
 
698
 * call-seq:
 
699
 *   BasicSocket.do_not_reverse_lookup => true or false
 
700
 *
 
701
 * Gets the global do_not_reverse_lookup flag.
 
702
 *
 
703
 *   BasicSocket.do_not_reverse_lookup  #=> false
 
704
 */
 
705
static VALUE
 
706
bsock_do_not_rev_lookup(void)
 
707
{
 
708
    return rsock_do_not_reverse_lookup?Qtrue:Qfalse;
 
709
}
 
710
 
 
711
/*
 
712
 * call-seq:
 
713
 *   BasicSocket.do_not_reverse_lookup = bool
 
714
 *
 
715
 * Sets the global do_not_reverse_lookup flag.
 
716
 *
 
717
 * The flag is used for initial value of do_not_reverse_lookup for each socket.
 
718
 *
 
719
 *   s1 = TCPSocket.new("localhost", 80)
 
720
 *   p s1.do_not_reverse_lookup                 #=> true
 
721
 *   BasicSocket.do_not_reverse_lookup = false
 
722
 *   s2 = TCPSocket.new("localhost", 80)
 
723
 *   p s2.do_not_reverse_lookup                 #=> false
 
724
 *   p s1.do_not_reverse_lookup                 #=> true
 
725
 *
 
726
 */
 
727
static VALUE
 
728
bsock_do_not_rev_lookup_set(VALUE self, VALUE val)
 
729
{
 
730
    rb_secure(4);
 
731
    rsock_do_not_reverse_lookup = RTEST(val);
 
732
    return val;
 
733
}
 
734
 
 
735
/*
 
736
 * BasicSocket is the super class for the all socket classes.
 
737
 */
 
738
void
 
739
rsock_init_basicsocket(void)
 
740
{
 
741
    rb_cBasicSocket = rb_define_class("BasicSocket", rb_cIO);
 
742
    rb_undef_method(rb_cBasicSocket, "initialize");
 
743
 
 
744
    rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup",
 
745
                               bsock_do_not_rev_lookup, 0);
 
746
    rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup=",
 
747
                               bsock_do_not_rev_lookup_set, 1);
 
748
    rb_define_singleton_method(rb_cBasicSocket, "for_fd", bsock_s_for_fd, 1);
 
749
 
 
750
    rb_define_method(rb_cBasicSocket, "close_read", bsock_close_read, 0);
 
751
    rb_define_method(rb_cBasicSocket, "close_write", bsock_close_write, 0);
 
752
    rb_define_method(rb_cBasicSocket, "shutdown", bsock_shutdown, -1);
 
753
    rb_define_method(rb_cBasicSocket, "setsockopt", bsock_setsockopt, -1);
 
754
    rb_define_method(rb_cBasicSocket, "getsockopt", bsock_getsockopt, 2);
 
755
    rb_define_method(rb_cBasicSocket, "getsockname", bsock_getsockname, 0);
 
756
    rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0);
 
757
    rb_define_method(rb_cBasicSocket, "getpeereid", bsock_getpeereid, 0);
 
758
    rb_define_method(rb_cBasicSocket, "local_address", bsock_local_address, 0);
 
759
    rb_define_method(rb_cBasicSocket, "remote_address", bsock_remote_address, 0);
 
760
    rb_define_method(rb_cBasicSocket, "send", rsock_bsock_send, -1);
 
761
    rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
 
762
    rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1);
 
763
    rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
 
764
    rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
 
765
 
 
766
    rb_define_method(rb_cBasicSocket, "sendmsg", rsock_bsock_sendmsg, -1); /* in ancdata.c */
 
767
    rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
 
768
    rb_define_method(rb_cBasicSocket, "recvmsg", rsock_bsock_recvmsg, -1); /* in ancdata.c */
 
769
    rb_define_method(rb_cBasicSocket, "recvmsg_nonblock", rsock_bsock_recvmsg_nonblock, -1); /* in ancdata.c */
 
770
 
 
771
}