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