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