00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "rubysocket.h"
00012
00013 struct inetsock_arg
00014 {
00015 VALUE sock;
00016 struct {
00017 VALUE host, serv;
00018 struct rb_addrinfo *res;
00019 } remote, local;
00020 int type;
00021 int fd;
00022 };
00023
00024 static VALUE
00025 inetsock_cleanup(struct inetsock_arg *arg)
00026 {
00027 if (arg->remote.res) {
00028 rb_freeaddrinfo(arg->remote.res);
00029 arg->remote.res = 0;
00030 }
00031 if (arg->local.res) {
00032 rb_freeaddrinfo(arg->local.res);
00033 arg->local.res = 0;
00034 }
00035 if (arg->fd >= 0) {
00036 close(arg->fd);
00037 }
00038 return Qnil;
00039 }
00040
00041 static VALUE
00042 init_inetsock_internal(struct inetsock_arg *arg)
00043 {
00044 int type = arg->type;
00045 struct addrinfo *res, *lres;
00046 int fd, status = 0, local = 0;
00047 const char *syscall = 0;
00048
00049 arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM,
00050 (type == INET_SERVER) ? AI_PASSIVE : 0);
00051
00052
00053
00054
00055 if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
00056 arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv, SOCK_STREAM, 0);
00057 }
00058
00059 arg->fd = fd = -1;
00060 for (res = arg->remote.res->ai; res; res = res->ai_next) {
00061 #if !defined(INET6) && defined(AF_INET6)
00062 if (res->ai_family == AF_INET6)
00063 continue;
00064 #endif
00065 lres = NULL;
00066 if (arg->local.res) {
00067 for (lres = arg->local.res->ai; lres; lres = lres->ai_next) {
00068 if (lres->ai_family == res->ai_family)
00069 break;
00070 }
00071 if (!lres) {
00072 if (res->ai_next || status < 0)
00073 continue;
00074
00075
00076 lres = arg->local.res->ai;
00077 }
00078 }
00079 status = rsock_socket(res->ai_family,res->ai_socktype,res->ai_protocol);
00080 syscall = "socket(2)";
00081 fd = status;
00082 if (fd < 0) {
00083 continue;
00084 }
00085 arg->fd = fd;
00086 if (type == INET_SERVER) {
00087 #if !defined(_WIN32) && !defined(__CYGWIN__)
00088 status = 1;
00089 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
00090 (char*)&status, (socklen_t)sizeof(status));
00091 #endif
00092 status = bind(fd, res->ai_addr, res->ai_addrlen);
00093 syscall = "bind(2)";
00094 }
00095 else {
00096 if (lres) {
00097 status = bind(fd, lres->ai_addr, lres->ai_addrlen);
00098 local = status;
00099 syscall = "bind(2)";
00100 }
00101
00102 if (status >= 0) {
00103 status = rsock_connect(fd, res->ai_addr, res->ai_addrlen,
00104 (type == INET_SOCKS));
00105 syscall = "connect(2)";
00106 }
00107 }
00108
00109 if (status < 0) {
00110 close(fd);
00111 arg->fd = fd = -1;
00112 continue;
00113 } else
00114 break;
00115 }
00116 if (status < 0) {
00117 VALUE host, port;
00118
00119 if (local < 0) {
00120 host = arg->local.host;
00121 port = arg->local.serv;
00122 } else {
00123 host = arg->remote.host;
00124 port = arg->remote.serv;
00125 }
00126
00127 rsock_sys_fail_host_port(syscall, host, port);
00128 }
00129
00130 arg->fd = -1;
00131
00132 if (type == INET_SERVER) {
00133 status = listen(fd, SOMAXCONN);
00134 if (status < 0) {
00135 close(fd);
00136 rb_sys_fail("listen(2)");
00137 }
00138 }
00139
00140
00141 return rsock_init_sock(arg->sock, fd);
00142 }
00143
00144 VALUE
00145 rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
00146 VALUE local_host, VALUE local_serv, int type)
00147 {
00148 struct inetsock_arg arg;
00149 arg.sock = sock;
00150 arg.remote.host = remote_host;
00151 arg.remote.serv = remote_serv;
00152 arg.remote.res = 0;
00153 arg.local.host = local_host;
00154 arg.local.serv = local_serv;
00155 arg.local.res = 0;
00156 arg.type = type;
00157 arg.fd = -1;
00158 return rb_ensure(init_inetsock_internal, (VALUE)&arg,
00159 inetsock_cleanup, (VALUE)&arg);
00160 }
00161
00162 static ID id_numeric, id_hostname;
00163
00164 int
00165 rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
00166 {
00167 #define return_norevlookup(x) {*norevlookup = (x); return 1;}
00168 ID id;
00169
00170 switch (revlookup) {
00171 case Qtrue: return_norevlookup(0);
00172 case Qfalse: return_norevlookup(1);
00173 case Qnil: break;
00174 default:
00175 Check_Type(revlookup, T_SYMBOL);
00176 id = SYM2ID(revlookup);
00177 if (id == id_numeric) return_norevlookup(1);
00178 if (id == id_hostname) return_norevlookup(0);
00179 rb_raise(rb_eArgError, "invalid reverse_lookup flag: :%s", rb_id2name(id));
00180 }
00181 return 0;
00182 #undef return_norevlookup
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 static VALUE
00209 ip_addr(int argc, VALUE *argv, VALUE sock)
00210 {
00211 rb_io_t *fptr;
00212 union_sockaddr addr;
00213 socklen_t len = (socklen_t)sizeof addr;
00214 int norevlookup;
00215
00216 GetOpenFile(sock, fptr);
00217
00218 if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
00219 norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
00220 if (getsockname(fptr->fd, &addr.addr, &len) < 0)
00221 rb_sys_fail("getsockname(2)");
00222 return rsock_ipaddr(&addr.addr, len, norevlookup);
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 static VALUE
00250 ip_peeraddr(int argc, VALUE *argv, VALUE sock)
00251 {
00252 rb_io_t *fptr;
00253 union_sockaddr addr;
00254 socklen_t len = (socklen_t)sizeof addr;
00255 int norevlookup;
00256
00257 GetOpenFile(sock, fptr);
00258
00259 if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
00260 norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
00261 if (getpeername(fptr->fd, &addr.addr, &len) < 0)
00262 rb_sys_fail("getpeername(2)");
00263 return rsock_ipaddr(&addr.addr, len, norevlookup);
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 static VALUE
00288 ip_recvfrom(int argc, VALUE *argv, VALUE sock)
00289 {
00290 return rsock_s_recvfrom(sock, argc, argv, RECV_IP);
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303 static VALUE
00304 ip_s_getaddress(VALUE obj, VALUE host)
00305 {
00306 union_sockaddr addr;
00307 struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, SOCK_STREAM, 0);
00308 socklen_t len = res->ai->ai_addrlen;
00309
00310
00311 memcpy(&addr, res->ai->ai_addr, len);
00312 rb_freeaddrinfo(res);
00313
00314 return rsock_make_ipaddr(&addr.addr, len);
00315 }
00316
00317 void
00318 rsock_init_ipsocket(void)
00319 {
00320
00321
00322
00323
00324
00325 rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket);
00326 rb_define_method(rb_cIPSocket, "addr", ip_addr, -1);
00327 rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, -1);
00328 rb_define_method(rb_cIPSocket, "recvfrom", ip_recvfrom, -1);
00329 rb_define_singleton_method(rb_cIPSocket, "getaddress", ip_s_getaddress, 1);
00330 rb_undef_method(rb_cIPSocket, "getpeereid");
00331
00332 id_numeric = rb_intern_const("numeric");
00333 id_hostname = rb_intern_const("hostname");
00334 }
00335