📄 netutils.c
字号:
ZFREE(status.closed_conns); ZFREE(status.conn_user_data); sigaction(SIGPIPE, &org_sigact, NULL); return(r);}/* * Use configured name services to get our official host name. Returns * a malloc'd string on success, NULL on failure. */UChar *get_my_off_hn(){ struct utsname unamb; struct hostent *hp; if(uname(&unamb) < 0) return(NULL); hp = get_host_by_name(unamb.nodename); if(!hp) return(NULL); return(strdup(hp->h_name));}Int8same_host(UChar * hn1, UChar * hn2){ struct hostent *hep1, *hep2; Int32 i, j, n1, n2, l1, l2; Int8 r = 0, ce; char *addresses1 = NULL, *addresses2 = NULL; if(! hn1 || ! hn2){ errno = EINVAL; return(-1); } ce = (strcmp(hn1, hn2) ? 0 : 2); if(ce) return(ce); hep1 = get_host_by_name(hn1); if(!hep1) return(ce); l1 = hep1->h_length; for(n1 = 0; hep1->h_addr_list[n1]; n1++); addresses1 = NEWP(UChar, n1 * l1); if(!addresses1){ r = - errno; GETOUT; } for(i = 0; i < n1; i++) memcpy(addresses1 + i * l1, hep1->h_addr_list[i], l1); hep2 = get_host_by_name(hn2); if(!hep2){ r = ce; CLEANUP; } l2 = hep2->h_length; for(n2 = 0; hep2->h_addr_list[n2]; n2++); addresses2 = NEWP(UChar, n2 * l2); if(!addresses2){ r = - errno; GETOUT; } for(i = 0; i < n2; i++) memcpy(addresses2 + i * l2, hep2->h_addr_list[i], l2); if(l1 != l2){ r = ce; CLEANUP; } for(i = 0; i < n1; i++){ for(j = 0; j < n2; j++){ if(! memcmp(addresses1 + i * l1, addresses2 + j * l2, l1)){ r = 1; i = n1; break; } } } cleanup: ZFREE(addresses1); ZFREE(addresses2); return(r); getout: CLEANUP;}/* * Takes <servicename>, which may either be a number or a name as specified * in /etc/services or in a name service (according to /etc/nsswitch.conf), * and returns the associated port number as an int, always for protocol TCP * Returns a value < 0 on error. */intget_tcp_portnum(UChar * servicename){ struct servent *se; int n, p, len, l; UChar *sn_cp; if(!servicename){ errno = EINVAL; return(-1); } sn_cp = strdup(servicename); if(!sn_cp) return(-1); massage_string(sn_cp); len = strlen(sn_cp); l = -1; n = sscanf(sn_cp, "%d%n", &p, &l); free(sn_cp); if(n > 0 && len == l) return(p); se = getservbyname(servicename, "tcp"); if(!se) return(-1); return(ntohs(se->s_port));}Int32anon_tcp_sockaddr( struct sockaddr *addr, Int32 *sockaddrsize, int addrfamily){ if(addrfamily != AF_INET#ifdef HAVE_IP6 && addrfamily != AF_INET6#endif ) return(-5); if(addrfamily == AF_INET){ if(addr){ SETZERO(((struct sockaddr_in *)addr)[0]); ((struct sockaddr_in *)addr)->sin_port = htons(0); } if(sockaddrsize) *sockaddrsize = sizeof(struct sockaddr_in); }#ifdef HAVE_IP6 if(addrfamily == AF_INET6){ if(addr){ SETZERO(((struct sockaddr_in6 *)addr)[0]); ((struct sockaddr_in6 *)addr)->sin6_port = htons(0); } if(sockaddrsize) *sockaddrsize = sizeof(struct sockaddr_in6); }#endif if(addr) addr->sa_family = addrfamily; return(0);}void *inaddr_from_sockaddr(struct sockaddr * sockaddr, Int32 * addrsize)
{ void *retaddr = NULL; if(sockaddr->sa_family != AF_INET#ifdef HAVE_IP6 && sockaddr->sa_family != AF_INET6#endif ) return(NULL); if(sockaddr->sa_family == AF_INET){ retaddr = &(((struct sockaddr_in *)sockaddr)->sin_addr); if(addrsize) *addrsize = sizeof(struct in_addr); }#ifdef HAVE_IP6 if(sockaddr->sa_family == AF_INET6){ retaddr = &(((struct sockaddr_in6 *)sockaddr)->sin6_addr); if(addrsize) *addrsize = sizeof(struct in6_addr); }#endif return(retaddr);}Int32set_tcp_sockaddr_hp( struct sockaddr *addr, struct hostent *hp, int portnum){ if(hp->h_addrtype != AF_INET#ifdef HAVE_IP6 && hp->h_addrtype != AF_INET6#endif ) return(-5); addr->sa_family = hp->h_addrtype; if(hp->h_addrtype == AF_INET){ if(hp) memcpy(&(((struct sockaddr_in *)addr)->sin_addr), hp->h_addr, hp->h_length); if(portnum >= 0) ((struct sockaddr_in *)addr)->sin_port = htons(portnum); }#ifdef HAVE_IP6 if(hp->h_addrtype == AF_INET6){ if(hp) memcpy(&(((struct sockaddr_in6 *)addr)->sin6_addr), hp->h_addr, hp->h_length); if(portnum >= 0) ((struct sockaddr_in6 *)addr)->sin6_port = htons(portnum); }#endif return(0);}/* return value <= - 128: may be a temporary resource shortage */intopen_tcpip_conn(UChar * hostname, UChar * servname, Int32 fallback_port){ nodeaddr addr; struct hostent *hp; struct linger linger; int sockfd, fl; Int32 sock_typesize, i, portnum; if(!servname && fallback_port < 0){ errno = EINVAL; return(-1); } hp = get_host_by_name(hostname); if(!hp) return(-2); if(!servname){ portnum = fallback_port; } else{ portnum = get_tcp_portnum(servname); if(portnum < 0) return(-3); } if( (i = set_tcp_sockaddr_hp((struct sockaddr *)(&addr), hp, portnum)) ) return(i); if( (i = anon_tcp_sockaddr((struct sockaddr *)(&addr), &sock_typesize, hp->h_addrtype)) ) return(i); sockfd = socket(hp->h_addrtype, SOCK_STREAM, 0); if(sockfd < 0) return(-4 - 128); i = bind(sockfd, (struct sockaddr *)(&addr), sock_typesize); if(i){ close(sockfd); return(-5 - 128); } set_tcp_sockaddr_hp((struct sockaddr *)(&addr), hp, portnum); if(connect(sockfd, (struct sockaddr *)(&addr), sock_typesize) < 0){ close(sockfd); i = 128; if(errno == EACCES || errno == EPERM#ifdef ENETUNREACH || errno == ENETUNREACH#endif#ifdef EADDRNOTAVAIL || errno == EADDRNOTAVAIL#endif ) i = 0; return(-6 - i); } linger.l_onoff = 1; linger.l_linger = 60; i = setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof (linger)); fl = fcntl(sockfd, F_GETFL); fcntl(sockfd, F_SETFL, fl & INV_NONBLOCKING_FLAGS); return(sockfd);}Int32set_ip_throughput(int sockfd){ int sock_optval; Int32 r, i; r = 0;#if defined(IP_TOS) && defined(IPTOS_THROUGHPUT) sock_optval = IPTOS_THROUGHPUT; if( (i = setsockopt(sockfd, IPPROTO_IP, IP_TOS, (char *) &sock_optval, sizeof(int))) < 0) r -= 1;#endif return(r);}Int32set_tcp_nodelay(int sockfd, Flag turn_on){ int sock_optval, sockfd_socktype; Int32 sock_optlen[2], r, i; r = 0; /* I use 32 Bit int for sock_optlen. See server.c for a *comment* */ *((int *) &(sock_optlen[0])) = sizeof(int); i = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (char *) &sockfd_socktype, (int *) &(sock_optlen[0])); if(i){ r -= 1; sockfd_socktype = -1; }#ifdef TCP_NODELAY sock_optval = (turn_on ? 1 : 0); if(sockfd_socktype == SOCK_STREAM){ if( (i = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &sock_optval, sizeof(int))) < 0) r -= 2; }#endif return(r);}Int32set_socket_keepalive(int sockfd){ int sock_optval; Int32 r, i; r = 0;#ifdef SO_KEEPALIVE sock_optval = 1; if( (i = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &sock_optval, sizeof(int))) < 0) r -= 1;#endif return(r);}UChar *addr_to_string(int socktype, void * addr){ UChar *ascaddr = NULL; if(socktype != AF_INET#ifdef HAVE_IP6 && socktype != AF_INET6#endif ) return(NULL);#ifdef HAVE_INET_NTOP /* this should work, if IP6 is present */ ascaddr = NEWP(UChar, 256); if(ascaddr){ if(inet_ntop(socktype, addr, ascaddr, 256)) ascaddr = ZRENEWP(ascaddr, UChar, strlen(ascaddr) + 1); else ZFREE(ascaddr); }#else if(socktype == AF_INET){#ifdef HAVE_INET_NTOA ascaddr = strdup(inet_ntoa(*((struct in_addr *) addr)));#else { char naddr[30]; /* manually: assuming IP-V4-address */ unsigned long laddr; laddr = ntohl(addr); sprintf(naddr, "%u.%u.%u.%u", laddr >> 24, (laddr >> 16) & 0xff, (laddr >> 8) & 0xff, laddr & 0xff); ascaddr = strdup(naddr); } #endif /* defined(HAVE_INET_NTOA) */ }#endif /* defined(HAVE_INET_NTOP) */ return(ascaddr);}UChar *get_hostnamestr(struct sockaddr * peeraddr){ struct hostent *hp; UChar *hostname = NULL; void *addr; Int32 alen; if(!peeraddr) return(get_my_off_hn()); if(peeraddr->sa_family == AF_UNIX) return(strdup("localhost")); if(peeraddr->sa_family == AF_INET){ addr = &(((struct sockaddr_in *)peeraddr)->sin_addr); alen = sizeof(struct in_addr); }#ifdef HAVE_IP6 else if(peeraddr->sa_family == AF_INET6){ addr = &(((struct sockaddr_in6 *) peeraddr)->sin6_addr); alen = sizeof(struct in6_addr); }#endif else return(NULL); hp = get_host_by_addr(addr, alen, peeraddr->sa_family); if(hp) hostname = strdup(hp->h_name); else hostname = addr_to_string(peeraddr->sa_family, addr); return(hostname);}UChar *get_connected_peername(int sock){ int i; nodeaddr peeraddr; Int32 len[2]; len[0] = len[1] = 0; *((int *) &(len[0])) = sizeof(peeraddr); i = getpeername(sock, (struct sockaddr *) &peeraddr, (int *) &(len[0])); if(i){ return(NULL); } return(get_hostnamestr((struct sockaddr *)(&peeraddr)));}/* *comment* on getsockopt argument 5: * The IBM had the *great* idea to change the type of argument 5 of * getsockopt (and BTW argument 3 of getpeername) to size_t *. On the * Digital Unix size_t is an 8 Byte unsigned integer. Therefore the * safety belt * int sock_optlen[2]. * I tried to find a workaround using autoconfig. Parsing the Headers * using cpp and perl or awk does not lead to satisfying results. Using * the TRY_COMPILE macro of autoconfig fails sometimes. E.G. the DEC * C-compiler does not complain on wrong re-declarations (neither via * error-message nor by the exit status). Try yourself, if you don't * believe. Furthermore there are 4 ways of declaration i found on * several systems. 4th argument as char * or void *, 5th arg as * explained of type int * or size_t *. Testing all these is annoying. * Maybe some other vendors have other ideas, how getsockopt should * be declared (sigh). Therefore i use two 32-Bit integers. Even if * a system call thinks, it must put there a 64-Bit int, the program * does not fail. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -