00001 #include "rubysocket.h"
00002
00003 #ifdef HAVE_GETIFADDRS
00004
00005
00006
00007
00008
00009 #ifdef HAVE_LONG_LONG
00010 typedef unsigned LONG_LONG ifa_flags_t;
00011 #define PRIxIFAFLAGS PRI_LL_PREFIX"x"
00012 #define IFAFLAGS2NUM(flags) ULL2NUM(flags)
00013 #else
00014 typedef unsigned int ifa_flags_t;
00015 #define PRIxIFAFLAGS "x"
00016 #define IFAFLAGS2NUM(flags) UINT2NUM(flags)
00017 #endif
00018
00019 VALUE rb_cSockIfaddr;
00020
00021 typedef struct rb_ifaddr_tag rb_ifaddr_t;
00022 typedef struct rb_ifaddr_root_tag rb_ifaddr_root_t;
00023
00024 struct rb_ifaddr_tag {
00025 int ord;
00026 struct ifaddrs *ifaddr;
00027 rb_ifaddr_root_t *root;
00028 };
00029
00030 struct rb_ifaddr_root_tag {
00031 int refcount;
00032 int numifaddrs;
00033 rb_ifaddr_t ary[1];
00034 };
00035
00036 static rb_ifaddr_root_t *
00037 get_root(const rb_ifaddr_t *ifaddr)
00038 {
00039 return (rb_ifaddr_root_t *)((char *)&ifaddr[-ifaddr->ord] -
00040 offsetof(rb_ifaddr_root_t, ary));
00041 }
00042
00043 static void
00044 ifaddr_mark(void *ptr)
00045 {
00046 }
00047
00048 static void
00049 ifaddr_free(void *ptr)
00050 {
00051 rb_ifaddr_t *ifaddr = ptr;
00052 rb_ifaddr_root_t *root = get_root(ifaddr);
00053 root->refcount--;
00054 if (root->refcount == 0) {
00055 freeifaddrs(root->ary[0].ifaddr);
00056 xfree(root);
00057 }
00058 }
00059
00060 static size_t
00061 ifaddr_memsize(const void *ptr)
00062 {
00063 const rb_ifaddr_t *ifaddr;
00064 const rb_ifaddr_root_t *root;
00065 if (ptr == NULL)
00066 return 0;
00067 ifaddr = ptr;
00068 root = get_root(ifaddr);
00069 return sizeof(rb_ifaddr_root_t) + (root->numifaddrs - 1) * sizeof(rb_ifaddr_t);
00070 }
00071
00072 static const rb_data_type_t ifaddr_type = {
00073 "socket/ifaddr",
00074 {ifaddr_mark, ifaddr_free, ifaddr_memsize,},
00075 };
00076
00077 #define IS_IFADDRS(obj) rb_typeddata_is_kind_of((obj), &ifaddr_type)
00078 static inline rb_ifaddr_t *
00079 check_ifaddr(VALUE self)
00080 {
00081 return rb_check_typeddata(self, &ifaddr_type);
00082 }
00083
00084 static rb_ifaddr_t *
00085 get_ifaddr(VALUE self)
00086 {
00087 rb_ifaddr_t *rifaddr = check_ifaddr(self);
00088
00089 if (!rifaddr) {
00090 rb_raise(rb_eTypeError, "uninitialized ifaddr");
00091 }
00092 return rifaddr;
00093 }
00094
00095 static VALUE
00096 rsock_getifaddrs(void)
00097 {
00098 int ret;
00099 int numifaddrs, i;
00100 struct ifaddrs *ifaddrs, *ifa;
00101 rb_ifaddr_root_t *root;
00102 VALUE result;
00103
00104 ret = getifaddrs(&ifaddrs);
00105 if (ret == -1)
00106 rb_sys_fail("getifaddrs");
00107
00108 if (!ifaddrs) {
00109 return rb_ary_new();
00110 }
00111
00112 numifaddrs = 0;
00113 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
00114 numifaddrs++;
00115
00116 root = xmalloc(sizeof(rb_ifaddr_root_t) + (numifaddrs-1) * sizeof(rb_ifaddr_t));
00117 root->refcount = root->numifaddrs = numifaddrs;
00118
00119 ifa = ifaddrs;
00120 for (i = 0; i < numifaddrs; i++) {
00121 root->ary[i].ord = i;
00122 root->ary[i].ifaddr = ifa;
00123 root->ary[i].root = root;
00124 ifa = ifa->ifa_next;
00125 }
00126
00127 result = rb_ary_new2(numifaddrs);
00128 for (i = 0; i < numifaddrs; i++) {
00129 rb_ary_push(result, TypedData_Wrap_Struct(rb_cSockIfaddr, &ifaddr_type, &root->ary[i]));
00130 }
00131
00132 return result;
00133 }
00134
00135
00136
00137
00138
00139
00140
00141
00142 static VALUE
00143 ifaddr_name(VALUE self)
00144 {
00145 rb_ifaddr_t *rifaddr = get_ifaddr(self);
00146 struct ifaddrs *ifa = rifaddr->ifaddr;
00147 return rb_str_new_cstr(ifa->ifa_name);
00148 }
00149
00150 #ifdef HAVE_IF_NAMETOINDEX
00151
00152
00153
00154
00155
00156
00157
00158 static VALUE
00159 ifaddr_ifindex(VALUE self)
00160 {
00161 rb_ifaddr_t *rifaddr = get_ifaddr(self);
00162 struct ifaddrs *ifa = rifaddr->ifaddr;
00163 unsigned int ifindex = if_nametoindex(ifa->ifa_name);
00164 if (ifindex == 0) {
00165 rb_raise(rb_eArgError, "invalid interface name: %s", ifa->ifa_name);
00166 }
00167 return UINT2NUM(ifindex);
00168 }
00169 #else
00170 #define ifaddr_ifindex rb_f_notimplement
00171 #endif
00172
00173
00174
00175
00176
00177
00178
00179
00180 static VALUE
00181 ifaddr_flags(VALUE self)
00182 {
00183 rb_ifaddr_t *rifaddr = get_ifaddr(self);
00184 struct ifaddrs *ifa = rifaddr->ifaddr;
00185 return IFAFLAGS2NUM(ifa->ifa_flags);
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 static VALUE
00197 ifaddr_addr(VALUE self)
00198 {
00199 rb_ifaddr_t *rifaddr = get_ifaddr(self);
00200 struct ifaddrs *ifa = rifaddr->ifaddr;
00201 if (ifa->ifa_addr)
00202 return rsock_sockaddr_obj(ifa->ifa_addr, rsock_sockaddr_len(ifa->ifa_addr));
00203 return Qnil;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 static VALUE
00215 ifaddr_netmask(VALUE self)
00216 {
00217 rb_ifaddr_t *rifaddr = get_ifaddr(self);
00218 struct ifaddrs *ifa = rifaddr->ifaddr;
00219 if (ifa->ifa_netmask)
00220 return rsock_sockaddr_obj(ifa->ifa_netmask, rsock_sockaddr_len(ifa->ifa_netmask));
00221 return Qnil;
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 static VALUE
00233 ifaddr_broadaddr(VALUE self)
00234 {
00235 rb_ifaddr_t *rifaddr = get_ifaddr(self);
00236 struct ifaddrs *ifa = rifaddr->ifaddr;
00237 if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr)
00238 return rsock_sockaddr_obj(ifa->ifa_broadaddr, rsock_sockaddr_len(ifa->ifa_broadaddr));
00239 return Qnil;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 static VALUE
00251 ifaddr_dstaddr(VALUE self)
00252 {
00253 rb_ifaddr_t *rifaddr = get_ifaddr(self);
00254 struct ifaddrs *ifa = rifaddr->ifaddr;
00255 if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr)
00256 return rsock_sockaddr_obj(ifa->ifa_dstaddr, rsock_sockaddr_len(ifa->ifa_dstaddr));
00257 return Qnil;
00258 }
00259
00260 static void
00261 ifaddr_inspect_flags(ifa_flags_t flags, VALUE result)
00262 {
00263 const char *sep = " ";
00264 #define INSPECT_BIT(bit, name) \
00265 if (flags & (bit)) { rb_str_catf(result, "%s" name, sep); flags &= ~(ifa_flags_t)(bit); sep = ","; }
00266 #ifdef IFF_UP
00267 INSPECT_BIT(IFF_UP, "UP")
00268 #endif
00269 #ifdef IFF_BROADCAST
00270 INSPECT_BIT(IFF_BROADCAST, "BROADCAST")
00271 #endif
00272 #ifdef IFF_DEBUG
00273 INSPECT_BIT(IFF_DEBUG, "DEBUG")
00274 #endif
00275 #ifdef IFF_LOOPBACK
00276 INSPECT_BIT(IFF_LOOPBACK, "LOOPBACK")
00277 #endif
00278 #ifdef IFF_POINTOPOINT
00279 INSPECT_BIT(IFF_POINTOPOINT, "POINTOPOINT")
00280 #endif
00281 #ifdef IFF_RUNNING
00282 INSPECT_BIT(IFF_RUNNING, "RUNNING")
00283 #endif
00284 #ifdef IFF_NOARP
00285 INSPECT_BIT(IFF_NOARP, "NOARP")
00286 #endif
00287 #ifdef IFF_PROMISC
00288 INSPECT_BIT(IFF_PROMISC, "PROMISC")
00289 #endif
00290 #ifdef IFF_NOTRAILERS
00291 INSPECT_BIT(IFF_NOTRAILERS, "NOTRAILERS")
00292 #endif
00293 #ifdef IFF_ALLMULTI
00294 INSPECT_BIT(IFF_ALLMULTI, "ALLMULTI")
00295 #endif
00296 #ifdef IFF_MASTER
00297 INSPECT_BIT(IFF_MASTER, "MASTER")
00298 #endif
00299 #ifdef IFF_SLAVE
00300 INSPECT_BIT(IFF_SLAVE, "SLAVE")
00301 #endif
00302 #ifdef IFF_MULTICAST
00303 INSPECT_BIT(IFF_MULTICAST, "MULTICAST")
00304 #endif
00305 #ifdef IFF_PORTSEL
00306 INSPECT_BIT(IFF_PORTSEL, "PORTSEL")
00307 #endif
00308 #ifdef IFF_AUTOMEDIA
00309 INSPECT_BIT(IFF_AUTOMEDIA, "AUTOMEDIA")
00310 #endif
00311 #ifdef IFF_DYNAMIC
00312 INSPECT_BIT(IFF_DYNAMIC, "DYNAMIC")
00313 #endif
00314 #ifdef IFF_LOWER_UP
00315 INSPECT_BIT(IFF_LOWER_UP, "LOWER_UP")
00316 #endif
00317 #ifdef IFF_DORMANT
00318 INSPECT_BIT(IFF_DORMANT, "DORMANT")
00319 #endif
00320 #ifdef IFF_ECHO
00321 INSPECT_BIT(IFF_ECHO, "ECHO")
00322 #endif
00323 #undef INSPECT_BIT
00324 if (flags) {
00325 rb_str_catf(result, "%s%#"PRIxIFAFLAGS, sep, flags);
00326 }
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336 static VALUE
00337 ifaddr_inspect(VALUE self)
00338 {
00339 rb_ifaddr_t *rifaddr = get_ifaddr(self);
00340 struct ifaddrs *ifa;
00341 VALUE result;
00342
00343 ifa = rifaddr->ifaddr;
00344
00345 result = rb_str_new_cstr("#<");
00346
00347 rb_str_append(result, rb_class_name(CLASS_OF(self)));
00348 rb_str_cat2(result, " ");
00349 rb_str_cat2(result, ifa->ifa_name);
00350
00351 if (ifa->ifa_flags)
00352 ifaddr_inspect_flags(ifa->ifa_flags, result);
00353
00354 if (ifa->ifa_addr) {
00355 rb_str_cat2(result, " ");
00356 rsock_inspect_sockaddr(ifa->ifa_addr,
00357 rsock_sockaddr_len(ifa->ifa_addr),
00358 result);
00359 }
00360 if (ifa->ifa_netmask) {
00361 rb_str_cat2(result, " netmask=");
00362 rsock_inspect_sockaddr(ifa->ifa_netmask,
00363 rsock_sockaddr_len(ifa->ifa_netmask),
00364 result);
00365 }
00366
00367 if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) {
00368 rb_str_cat2(result, " broadcast=");
00369 rsock_inspect_sockaddr(ifa->ifa_broadaddr,
00370 rsock_sockaddr_len(ifa->ifa_broadaddr),
00371 result);
00372 }
00373
00374 if ((ifa->ifa_flags & IFF_POINTOPOINT) && ifa->ifa_dstaddr) {
00375 rb_str_cat2(result, " dstaddr=");
00376 rsock_inspect_sockaddr(ifa->ifa_dstaddr,
00377 rsock_sockaddr_len(ifa->ifa_dstaddr),
00378 result);
00379 }
00380
00381 rb_str_cat2(result, ">");
00382 return result;
00383 }
00384 #endif
00385
00386 #ifdef HAVE_GETIFADDRS
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 static VALUE
00428 socket_s_getifaddrs(VALUE self)
00429 {
00430 return rsock_getifaddrs();
00431 }
00432 #else
00433 #define socket_s_getifaddrs rb_f_notimplement
00434 #endif
00435
00436 void
00437 rsock_init_sockifaddr(void)
00438 {
00439 #ifdef HAVE_GETIFADDRS
00440
00441
00442
00443
00444
00445 rb_cSockIfaddr = rb_define_class_under(rb_cSocket, "Ifaddr", rb_cData);
00446 rb_define_method(rb_cSockIfaddr, "inspect", ifaddr_inspect, 0);
00447 rb_define_method(rb_cSockIfaddr, "name", ifaddr_name, 0);
00448 rb_define_method(rb_cSockIfaddr, "ifindex", ifaddr_ifindex, 0);
00449 rb_define_method(rb_cSockIfaddr, "flags", ifaddr_flags, 0);
00450 rb_define_method(rb_cSockIfaddr, "addr", ifaddr_addr, 0);
00451 rb_define_method(rb_cSockIfaddr, "netmask", ifaddr_netmask, 0);
00452 rb_define_method(rb_cSockIfaddr, "broadaddr", ifaddr_broadaddr, 0);
00453 rb_define_method(rb_cSockIfaddr, "dstaddr", ifaddr_dstaddr, 0);
00454 #endif
00455
00456 rb_define_singleton_method(rb_cSocket, "getifaddrs", socket_s_getifaddrs, 0);
00457 }
00458