WvStreams
|
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Device-independent and device-specific hardware/protocol address 00006 * classes that can store themselves efficiently as well as create a 00007 * printable string version of themselves. 00008 */ 00009 #ifndef _WIN32 00010 #include <netdb.h> 00011 #include <sys/socket.h> 00012 #include <sys/un.h> 00013 #include <net/if_arp.h> 00014 #endif 00015 00016 #include "wvaddr.h" 00017 #include <assert.h> 00018 00019 #ifndef ARPHRD_IPSEC 00020 // From ipsec_tunnel 00021 #define ARPHRD_IPSEC 31 00022 #endif 00023 00024 // workaround for functions called sockaddr() -- oops. 00025 typedef struct sockaddr sockaddr_bin; 00026 00027 /* A list of Linux ARPHRD_* types, one for each element of CapType. */ 00028 int WvEncap::extypes[] = { 00029 #ifdef _WIN32 00030 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 00031 #else 00032 // hardware encapsulation 00033 0, // Unknown 00034 ARPHRD_LOOPBACK, 00035 0, // Ethertap 00036 ARPHRD_ETHER, 00037 ARPHRD_ARCNET, 00038 ARPHRD_SLIP, 00039 ARPHRD_CSLIP, 00040 ARPHRD_PPP, 00041 ARPHRD_IPSEC, 00042 00043 // protocol encapsulation 00044 AF_INET, // IPv4 00045 AF_UNIX // Unix domain socket 00046 #endif 00047 }; 00048 00049 00050 /* Printable strings corresponding to each element of CapType */ 00051 const char WvEncap::strings[][20] = { 00052 // hardware encapsulation 00053 "Unknown", 00054 "Loopback", 00055 "Ethertap", 00056 "Ethernet", 00057 "ARCnet", 00058 "SLIP", 00059 "CSLIP", 00060 "PPP", 00061 "IPsec", 00062 00063 // protocol encapsulation 00064 "IP", // IPv4 00065 "Unix", // Unix domain socket 00066 }; 00067 00068 00069 /* Figure out the CapType corresponding to a Linux ARPHRD_* type or 00070 * sockaddr sa_family type. 00071 */ 00072 WvEncap::WvEncap(int extype) 00073 { 00074 for (int count=0; count < NUM_ENCAP_TYPES; count++) 00075 { 00076 if (extype == extypes[count]) 00077 { 00078 cap = (CapType)count; 00079 return; 00080 } 00081 } 00082 cap = Unknown; 00083 } 00084 00085 00086 /* Find the hash value of a WvAddr, for use with WvHashTable */ 00087 unsigned WvHash(const WvAddr &addr) 00088 { 00089 return addr.WvHash(); 00090 } 00091 00092 00093 /* Create an object of the appropriate WvAddr-derived class based on the 00094 * address and type stored in 'addr'. 00095 */ 00096 WvAddr *WvAddr::gen(struct sockaddr *addr) 00097 { 00098 WvEncap encap(addr->sa_family); 00099 00100 switch (encap.cap) 00101 { 00102 case WvEncap::Loopback: 00103 return new WvStringAddr("Loopback", WvEncap::Loopback); 00104 00105 case WvEncap::IPv4: 00106 return new WvIPPortAddr((sockaddr_in *)addr); 00107 #ifndef _WIN32 00108 case WvEncap::ARCnet: 00109 return new WvARCnetAddr(addr); 00110 00111 case WvEncap::Ethertap: 00112 case WvEncap::Ethernet: 00113 return new WvEtherAddr(addr); 00114 00115 case WvEncap::IPsec: 00116 return new WvStringAddr("IPsec", WvEncap::IPsec); 00117 #endif 00118 default: 00119 return new WvStringAddr("Unknown", WvEncap::Unknown); 00120 } 00121 } 00122 00123 00124 bool WvAddr::isbroadcast() const 00125 { 00126 return false; // default is no support for broadcasts 00127 } 00128 00129 00130 const unsigned char *WvAddr::rawdata() const 00131 { 00132 return NULL; 00133 } 00134 00135 00136 size_t WvAddr::rawdata_len() const 00137 { 00138 return 0; 00139 } 00140 00141 00142 unsigned WvAddr::WvHash() const 00143 { 00144 unsigned hash = 0; 00145 const unsigned char *cptr, *raw = rawdata(); 00146 int len = rawdata_len(), width; 00147 00148 if (!raw || !len) return 0; 00149 width = (sizeof(hash)*8 / len) + 1; 00150 00151 for (cptr = raw; len; len--) 00152 hash = (hash << width) ^ *(cptr++); 00153 return hash; 00154 } 00155 00156 00157 bool WvAddr::comparator(const WvAddr *a2, bool first_pass) const 00158 { 00159 if (type() != a2->type()) return false; 00160 00161 const unsigned char *raw1, *raw2; 00162 size_t len; 00163 00164 len = rawdata_len(); 00165 if (len != a2->rawdata_len()) 00166 return false; 00167 00168 raw1 = rawdata(); 00169 raw2 = a2->rawdata(); 00170 00171 if (!raw1 && !raw2) return true; 00172 if (!raw1 || !raw2) return false; 00173 00174 return !memcmp(raw1, raw2, len); 00175 } 00176 00177 00178 WvStringAddr::WvStringAddr(WvStringParm s, const WvEncap &_cap) 00179 : addr(s), cap(_cap) 00180 { 00181 } 00182 00183 00184 WvStringAddr::WvStringAddr(const struct sockaddr *_addr) 00185 : addr((char *)_addr->sa_data), cap(_addr->sa_family) 00186 { 00187 } 00188 00189 00190 WvStringAddr::~WvStringAddr() 00191 { 00192 // nothing to do 00193 } 00194 00195 00196 WvEncap WvStringAddr::encap() const 00197 { 00198 return cap; 00199 } 00200 00201 00202 const unsigned char *WvStringAddr::rawdata() const 00203 { 00204 return (const unsigned char *)(const char *)addr; 00205 } 00206 00207 00208 size_t WvStringAddr::rawdata_len() const 00209 { 00210 return strlen(addr); 00211 } 00212 00213 00214 sockaddr_bin *WvStringAddr::sockaddr() const 00215 { 00216 sockaddr_bin *sa = new sockaddr_bin; 00217 memset(sa, 0, sizeof(*sa)); 00218 strncpy(sa->sa_data, addr, sizeof(sa->sa_data)); 00219 return sa; 00220 } 00221 00222 00223 size_t WvStringAddr::sockaddr_len() const 00224 { 00225 return sizeof(sockaddr_bin); 00226 } 00227 00228 00229 WvString WvStringAddr::printable() const 00230 { 00231 return addr; 00232 } 00233 00234 00235 #ifndef _WIN32 00236 /* create a WvEtherAddr from a printable string in the format: 00237 * AA:BB:CC:DD:EE:FF (six hex numbers, separated by colons) 00238 */ 00239 void WvEtherAddr::string_init(char const string[]) 00240 { 00241 char *endptr = NULL; 00242 unsigned char *cptr = binaddr; 00243 00244 memset(binaddr, 0, ETHER_ADDR_LEN); 00245 for (unsigned int count=0; count < ETHER_ADDR_LEN; count++) 00246 { 00247 *cptr++ = strtoul(endptr ? endptr : string, &endptr, 16); 00248 if (!endptr || !*endptr || endptr==string) break; 00249 endptr++; 00250 } 00251 } 00252 00253 00254 WvEtherAddr::~WvEtherAddr() 00255 { 00256 // nothing to do 00257 } 00258 00259 00260 /* Generate a printable version of an ethernet address. */ 00261 WvString WvEtherAddr::printable() const 00262 { 00263 char s[ETHER_ADDR_LEN*3], *cptr = s; 00264 00265 for (unsigned int count = 0; count < ETHER_ADDR_LEN; count++) 00266 { 00267 if (cptr > s) 00268 *cptr++ = ':'; 00269 sprintf(cptr, "%02X", binaddr[count]); 00270 cptr += 2; 00271 } 00272 *cptr = 0; 00273 00274 return WvString("%s", s); // create a dynamic WvString 00275 } 00276 00277 00278 WvEncap WvEtherAddr::encap() const 00279 { 00280 return WvEncap(WvEncap::Ethernet); 00281 } 00282 00283 00284 // FF:FF:FF:FF:FF:FF is the ethernet broadcast address. 00285 bool WvEtherAddr::isbroadcast() const 00286 { 00287 for (unsigned int count = 0; count < ETHER_ADDR_LEN; count++) 00288 if (binaddr[count] != 0xFF) 00289 return false; 00290 return true; 00291 } 00292 00293 00294 const unsigned char *WvEtherAddr::rawdata() const 00295 { 00296 return binaddr; 00297 } 00298 00299 00300 size_t WvEtherAddr::rawdata_len() const 00301 { 00302 return ETHER_ADDR_LEN; 00303 } 00304 00305 00306 sockaddr_bin *WvEtherAddr::sockaddr() const 00307 { 00308 sockaddr_bin *sa = new sockaddr_bin; 00309 memset(sa, 0, sizeof(*sa)); 00310 sa->sa_family = ARPHRD_ETHER; 00311 memcpy(sa->sa_data, binaddr, ETHER_ADDR_LEN); 00312 return sa; 00313 } 00314 00315 00316 size_t WvEtherAddr::sockaddr_len() const 00317 { 00318 return sizeof(sockaddr_bin); 00319 } 00320 00321 00322 WvARCnetAddr::~WvARCnetAddr() 00323 { 00324 // nothing to do 00325 } 00326 00327 00328 WvString WvARCnetAddr::printable() const 00329 { 00330 WvString s(" "); 00331 sprintf(s.edit(), "%02X", binaddr); 00332 return s; 00333 } 00334 00335 00336 WvEncap WvARCnetAddr::encap() const 00337 { 00338 return WvEncap(WvEncap::ARCnet); 00339 } 00340 00341 00342 const unsigned char *WvARCnetAddr::rawdata() const 00343 { 00344 return &binaddr; 00345 } 00346 00347 00348 size_t WvARCnetAddr::rawdata_len() const 00349 { 00350 return 1; 00351 } 00352 00353 00354 sockaddr_bin *WvARCnetAddr::sockaddr() const 00355 { 00356 sockaddr_bin *sa = new sockaddr_bin; 00357 memset(sa, 0, sizeof(*sa)); 00358 sa->sa_family = ARPHRD_ARCNET; 00359 sa->sa_data[0] = binaddr; 00360 return sa; 00361 } 00362 00363 00364 size_t WvARCnetAddr::sockaddr_len() const 00365 { 00366 return sizeof(sockaddr_bin); 00367 } 00368 00369 #endif //_WIN32 00370 00371 /* create an IP address from a dotted-quad string. We don't support 00372 * gethostname()-style lookups here, because they happen only synchronously. 00373 * Streams that need hostname lookups will have to do it themselves. 00374 */ 00375 void WvIPAddr::string_init(const char string[]) 00376 { 00377 const char *iptr, *nptr; 00378 unsigned char *cptr = binaddr; 00379 00380 memset(binaddr, 0, 4); 00381 nptr = string; 00382 for (int count=0; count < 4 && nptr; count++) 00383 { 00384 iptr = nptr; 00385 nptr = strchr(iptr, '.'); 00386 if (nptr) nptr++; 00387 *cptr++ = strtol(iptr, NULL, 10); 00388 if (!nptr) break; 00389 } 00390 } 00391 00392 WvIPAddr::~WvIPAddr() 00393 { 00394 // nothing to do 00395 } 00396 00397 bool WvIPAddr::comparator(const WvAddr *a2, bool first_pass) const 00398 { 00399 if (a2->type() == WVIPADDR) 00400 return !memcmp(binaddr, ((WvIPAddr *)a2)->binaddr, sizeof(binaddr)); 00401 else if (first_pass) 00402 return a2->comparator(this, false); 00403 else 00404 { 00405 const unsigned char *raw1, *raw2; 00406 size_t len; 00407 00408 len = rawdata_len(); 00409 if (len != a2->rawdata_len()) 00410 return false; 00411 00412 raw1 = rawdata(); 00413 raw2 = a2->rawdata(); 00414 00415 if (!raw1 && !raw2) return true; 00416 if (!raw1 || !raw2) return false; 00417 00418 return !memcmp(raw1, raw2, len); 00419 } 00420 } 00421 00422 00423 /* Generate a printable version of an IP address. */ 00424 WvString WvIPAddr::printable() const 00425 { 00426 return WvString("%s.%s.%s.%s", 00427 binaddr[0], binaddr[1], binaddr[2], binaddr[3]); 00428 } 00429 00430 00431 /* AND two IP addresses together (handle netmasks) */ 00432 WvIPAddr WvIPAddr::operator& (const WvIPAddr &a2) const 00433 { 00434 unsigned char obin[4]; 00435 00436 for (int count=0; count<4; count++) 00437 obin[count] = binaddr[count] & a2.binaddr[count]; 00438 return WvIPAddr(obin); 00439 } 00440 00441 00442 /* OR two IP addresses together (for broadcasts, etc) */ 00443 WvIPAddr WvIPAddr::operator| (const WvIPAddr &a2) const 00444 { 00445 unsigned char obin[4]; 00446 00447 for (int count=0; count<4; count++) 00448 obin[count] = binaddr[count] | a2.binaddr[count]; 00449 return WvIPAddr(obin); 00450 } 00451 00452 00453 /* XOR two IP addresses together (for binary operations) */ 00454 WvIPAddr WvIPAddr::operator^ (const WvIPAddr &a2) const 00455 { 00456 unsigned char obin[4]; 00457 00458 for (int count=0; count<4; count++) 00459 obin[count] = binaddr[count] ^ a2.binaddr[count]; 00460 return WvIPAddr(obin); 00461 } 00462 00463 00464 /* invert all the bits of an IP address (for useful binary operations) */ 00465 WvIPAddr WvIPAddr::operator~ () const 00466 { 00467 unsigned char obin[4]; 00468 00469 for (int count=0; count<4; count++) 00470 obin[count] = ~binaddr[count]; 00471 return WvIPAddr(obin); 00472 } 00473 00474 00475 /* add an integer value to an IP address: 00476 * eg. 192.168.42.255 + 1 == 192.168.43.0 00477 */ 00478 WvIPAddr WvIPAddr::operator+ (int n) const 00479 { 00480 uint32_t newad = htonl(ntohl(addr()) + n); 00481 return WvIPAddr((unsigned char *)&newad); 00482 } 00483 00484 00485 WvIPAddr WvIPAddr::operator- (int n) const 00486 { 00487 uint32_t newad = htonl(ntohl(addr()) - n); 00488 return WvIPAddr((unsigned char *)&newad); 00489 } 00490 00491 00492 WvEncap WvIPAddr::encap() const 00493 { 00494 return WvEncap(WvEncap::IPv4); 00495 } 00496 00497 00498 const unsigned char *WvIPAddr::rawdata() const 00499 { 00500 return binaddr; 00501 } 00502 00503 00504 size_t WvIPAddr::rawdata_len() const 00505 { 00506 return 4; 00507 } 00508 00509 00510 /* Generate a struct sockaddr (suitable for sendto()) from this IP 00511 * address. Don't forget to delete it after you're done! 00512 */ 00513 sockaddr_bin *WvIPAddr::sockaddr() const 00514 { 00515 sockaddr_in *sin = new sockaddr_in; 00516 00517 memset(sin, 0, sizeof(*sin)); 00518 sin->sin_family = AF_INET; 00519 sin->sin_addr.s_addr = addr(); 00520 sin->sin_port = 0; 00521 return (sockaddr_bin *)sin; 00522 } 00523 00524 00525 size_t WvIPAddr::sockaddr_len() const 00526 { 00527 return sizeof(sockaddr_in); 00528 } 00529 00530 00531 WvIPNet::WvIPNet() { } 00532 00533 00534 WvIPNet::WvIPNet(const WvIPNet &_net) 00535 : WvIPAddr(_net), mask(_net.netmask()) { } 00536 00537 00538 // If the netmask is not specified, it will default to all 1's. 00539 void WvIPNet::string_init(const char string[]) 00540 { 00541 char *maskptr; 00542 int bits; 00543 uint32_t imask; 00544 00545 maskptr = (char*)strchr(string, '/'); 00546 if (!maskptr) 00547 { 00548 mask = WvIPAddr("255.255.255.255"); 00549 return; 00550 } 00551 00552 maskptr++; 00553 00554 if (strchr(maskptr, '.')) 00555 mask = WvIPAddr(maskptr); 00556 else 00557 { 00558 bits = atoi(maskptr); 00559 if (bits > 0) 00560 imask = htonl(~(((uint32_t)1 << (32-bits)) - 1)); // see below 00561 else 00562 imask = 0; 00563 mask = WvIPAddr((unsigned char *)&imask); 00564 } 00565 } 00566 00567 00568 WvIPNet::WvIPNet(const WvIPAddr &base, const WvIPAddr &_mask) 00569 : WvIPAddr(base), mask(_mask) { } 00570 00571 00572 WvIPNet::WvIPNet(const WvIPAddr &base, int bits) 00573 : WvIPAddr(base) 00574 { 00575 uint32_t imask; 00576 if (bits > 0) // <<32 is a bad idea! 00577 imask = htonl(~(((uint32_t)1 << (32-bits)) - 1)); 00578 else 00579 imask = 0; 00580 mask = WvIPAddr((unsigned char *)&imask); 00581 } 00582 00583 WvIPNet::~WvIPNet() 00584 { 00585 // nothing to do 00586 } 00587 00588 00589 WvString WvIPNet::printable() const 00590 { 00591 if (bits() < 32) 00592 return WvString("%s/%s", network(), bits()); 00593 else 00594 return WvIPAddr::printable(); 00595 } 00596 00597 00598 unsigned WvIPNet::WvHash() const 00599 { 00600 return WvIPAddr::WvHash() + mask.WvHash(); 00601 } 00602 00603 00604 bool WvIPNet::comparator(const WvAddr *a2, bool first_pass) const 00605 { 00606 if (a2->type() == WVIPNET) 00607 return WvIPAddr::comparator(a2, false) && mask == ((WvIPNet *)a2)->mask; 00608 else if (first_pass) 00609 return a2->comparator(this, false); 00610 else 00611 return WvIPAddr::comparator(a2, false); 00612 00613 } 00614 00615 00616 void WvIPNet::include(const WvIPNet &addr) 00617 { 00618 mask = mask & addr.mask & ~(*this ^ addr); 00619 } 00620 00621 00622 bool WvIPNet::includes(const WvIPNet &addr) const 00623 { 00624 return (addr.base() & netmask()) == network() && 00625 (addr.netmask() & netmask()) == netmask(); 00626 } 00627 00628 00629 int WvIPNet::bits() const 00630 { 00631 int bits = 0; 00632 uint32_t val = ntohl(mask.addr()); 00633 00634 do 00635 { 00636 bits += val >> 31; 00637 } while ((val <<= 1) & (1 << 31)); 00638 00639 return bits; 00640 } 00641 00642 00643 void WvIPNet::normalize() 00644 { 00645 if (bits() > 0) 00646 { 00647 uint32_t val = htonl(~(((uint32_t)1 << (32-bits())) - 1)); 00648 mask = WvIPAddr((unsigned char *)&val); 00649 } 00650 else 00651 mask = WvIPAddr(); // empty netmask 00652 } 00653 00654 00655 WvIPPortAddr::WvIPPortAddr() 00656 { 00657 port = 0; 00658 } 00659 00660 00661 WvIPPortAddr::WvIPPortAddr(const WvIPAddr &_ipaddr, uint16_t _port) 00662 : WvIPAddr(_ipaddr) 00663 { 00664 port = _port; 00665 } 00666 00667 00668 static bool all_digits(const char *s) 00669 { 00670 for (; *s; s++) 00671 if (!isdigit((unsigned char)*s)) 00672 return false; 00673 return true; 00674 } 00675 00676 00677 // If no port is specified (after a ':' or a space or a tab) it defaults to 0. 00678 void WvIPPortAddr::string_init(const char string[]) 00679 { 00680 // special case for an all-numeric string: it must be just a port, 00681 // with default address 0.0.0.0. 00682 if (all_digits(string)) 00683 { 00684 *this = WvIPAddr(); 00685 port = atoi(string); 00686 return; 00687 } 00688 00689 const char *cptr = strchr(string, ':'); 00690 if (!cptr) 00691 cptr = strchr(string, ' '); 00692 if (!cptr) 00693 cptr = strchr(string, '\t'); 00694 00695 // avoid calling getservbyname() if we can avoid it, since it's really 00696 // slow and people like to create WvIPPortAddr objects really often. 00697 if (cptr && strcmp(cptr+1, "0")) 00698 { 00699 port = atoi(cptr+1); 00700 if (!port) 00701 { 00702 struct servent *serv = getservbyname(cptr+1, NULL); 00703 if (serv) 00704 port = ntohs(serv->s_port); 00705 } 00706 } 00707 else 00708 port = 0; 00709 } 00710 00711 00712 WvIPPortAddr::WvIPPortAddr(uint16_t _port) 00713 : WvIPAddr("0.0.0.0") 00714 { 00715 port = _port; 00716 } 00717 00718 00719 WvIPPortAddr::WvIPPortAddr(const char string[], uint16_t _port) 00720 : WvIPAddr(string) 00721 { 00722 port = _port; 00723 } 00724 00725 00726 WvIPPortAddr::~WvIPPortAddr() 00727 { 00728 // nothing to do 00729 } 00730 00731 00732 /* Generate a printable version of an IP+Port Address. */ 00733 WvString WvIPPortAddr::printable() const 00734 { 00735 return WvString("%s:%s", WvIPAddr::printable(), WvString(port)); 00736 } 00737 00738 00739 /* Generate a struct sockaddr (suitable for sendto()) from this IP+Port 00740 * address. Don't forget to delete it after you're done! 00741 */ 00742 sockaddr_bin *WvIPPortAddr::sockaddr() const 00743 { 00744 sockaddr_in *sin = (sockaddr_in *)WvIPAddr::sockaddr(); 00745 sin->sin_port = htons(port); 00746 return (sockaddr_bin *)sin; 00747 } 00748 00749 00750 unsigned WvIPPortAddr::WvHash() const 00751 { 00752 return WvIPAddr::WvHash() + port; 00753 } 00754 00755 bool WvIPPortAddr::comparator(const WvAddr *a2, bool first_pass) const 00756 { 00757 if (a2->type() == WVIPPORTADDR) 00758 return WvIPAddr::comparator(a2, false) 00759 && port == ((WvIPPortAddr *)a2)->port; 00760 else if (first_pass) 00761 return a2->comparator(this, false); 00762 else 00763 return WvIPAddr::comparator(a2, false); 00764 00765 } 00766 00767 #ifndef _WIN32 00768 WvUnixAddr::WvUnixAddr(const char *_sockname) 00769 : sockname(_sockname) 00770 { 00771 if (!sockname) 00772 sockname = "/"; 00773 } 00774 00775 00776 WvUnixAddr::WvUnixAddr(WvStringParm _sockname) 00777 : sockname(_sockname) 00778 { 00779 if (!sockname) 00780 sockname = "/"; 00781 } 00782 00783 00784 WvUnixAddr::WvUnixAddr(const WvUnixAddr &_addr) 00785 : sockname(_addr.sockname) 00786 { 00787 // nothing else needed 00788 } 00789 00790 00791 WvUnixAddr::~WvUnixAddr() 00792 { 00793 // nothing special 00794 } 00795 00796 00797 WvString WvUnixAddr::printable() const 00798 { 00799 return sockname; 00800 } 00801 00802 00803 WvEncap WvUnixAddr::encap() const 00804 { 00805 return WvEncap::Unix; 00806 } 00807 00808 00809 /* don't forget to delete the returned object when you're done! */ 00810 sockaddr_bin *WvUnixAddr::sockaddr() const 00811 { 00812 sockaddr_un *addr = new sockaddr_un; 00813 00814 memset(addr, 0, sizeof(*addr)); 00815 addr->sun_family = AF_UNIX; 00816 size_t max = strlen(sockname); 00817 if (max > sizeof(addr->sun_path) - 2) // appease valgrind 00818 max = sizeof(addr->sun_path) - 2; 00819 strncpy(addr->sun_path, sockname, max); 00820 if (addr->sun_path[0] == '@') // user wants an "abstract" socket 00821 addr->sun_path[0] = 0; // leading byte should be nul 00822 return (sockaddr_bin *)addr; 00823 } 00824 00825 00826 size_t WvUnixAddr::sockaddr_len() const 00827 { 00828 sockaddr_un *fake; 00829 size_t max = sizeof(fake->sun_path); 00830 size_t val = strlen(sockname); 00831 if (val > max) 00832 val = max; 00833 return sizeof(fake->sun_family) + val; 00834 } 00835 00836 00837 const unsigned char *WvUnixAddr::rawdata() const 00838 { 00839 return (const unsigned char *)(const char *)sockname; 00840 } 00841 00842 00843 size_t WvUnixAddr::rawdata_len() const 00844 { 00845 return strlen(sockname); 00846 } 00847 #endif // _WIN32