📄 netutils.c
字号:
/****************** Start of $RCSfile: netutils.c,v $ ****************** $Source: /home/alb/afbackup/afbackup-3.3.8.1/RCS/netutils.c,v $* $Id: netutils.c,v 1.6 2005/01/15 08:54:32 alb Exp alb $* $Date: 2005/01/15 08:54:32 $* $Author: alb $********* description *********************************************************************************************************************/#include <conf.h>#include <version.h> static char * fileversion = "$RCSfile: netutils.c,v $ $Source: /home/alb/afbackup/afbackup-3.3.8.1/RCS/netutils.c,v $ $Id: netutils.c,v 1.6 2005/01/15 08:54:32 alb Exp alb $ " PACKAGE " " VERSION_STRING;#include <stdio.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <sys/utsname.h>#include <sys/types.h>#include <sys/socket.h>#include <signal.h>#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#include <netinet/in.h>#include <netdb.h>#ifdef HAVE_NETINET_IN_SYSTM_H#include <netinet/in_systm.h>#endif#ifdef HAVE_NETINET_IP_H#include <netinet/ip.h>#endif#ifdef HAVE_NETINET_TCP_H#include <netinet/tcp.h>#endif#ifdef HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#include <x_types.h>#include <sysutils.h>#include <netutils.h>#include <fileutil.h>#include <genutils.h>#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#define CLEANUPR(ret) { r = (ret); goto cleanup; }#define CLEANUP { goto cleanup; }#define GETOUT { goto getout; }#define EMPTY_USER_DATA ((void *) 1)typedef struct _tcpmux_status { int listensock; int unixsock; Int32 maxconn; Int32 num_conns; void **conn_user_data; int *conns; FILE **conn_fps; fd_set allfds; int maxfd; Flag *closed_conns; Flag have_closed_conns; void (*failed_conn_func)(int, void *, void *); void *(*conn_init_func)(int, Int32, void *, struct sockaddr *, void *, TcpMuxCallbDoneActions *); void *data; Uns32 flags; void *conn_user_data_to_be_freed;} TcpMuxStatus;struct hostent *get_host_by_name(UChar * name){#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_IP6) int error_num; struct hostent *he; /* None of the flags (arg 3) does, what i consider appropriate. */ /* i guess, most of the networks will move from IP4 to IP6, thus */ /* introduce new IP6 nodes, that should be able to communicate */ /* with old and existing IP4 nodes. If there are new IP6 nodes, */ /* having also a IP4 address, the latter one can happily be used. */ /* If others should use IP6 to communicate with the host, that */ /* still has also an IP4 entry, the administrator should gefaelligst */ /* delete the IP4 entry, because then it makes no sense any more. */ /* Thus i implement it explicitely requiring 2 lookups :-( */ he = getipnodebyname(name, AF_INET, 0, &error_num); if(!he){ he = getipnodebyname(name, AF_INET6, 0, &error_num); errno = error_num; } return(he);#else return(gethostbyname(name));#endif}struct hostent *get_host_by_addr(void * addr, int len, int type){#if defined(HAVE_GETIPNODEBYADDR) && defined(HAVE_IP6) int error_num; struct hostent *he; he = getipnodebyaddr(addr, len, type, &error_num); if(!he) errno = error_num; return(he);#else return(gethostbyaddr(addr, len, type));#endif}struct hostent *get_host_by_sockaddr(struct sockaddr * addr){ if(((struct sockaddr *)addr)->sa_family == AF_INET) return(get_host_by_addr(&(((struct sockaddr_in *)addr)->sin_addr), sizeof(struct in_addr), AF_INET));#ifdef HAVE_IP6 if(((struct sockaddr *)addr)->sa_family == AF_INET6) return(get_host_by_addr(&(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr), AF_INET6));#endif return(NULL);}static Flagaccept_connection(TcpMuxStatus * status, Flag in_subr, Flag uxsock){ int fl, fd, sock; Flag end = NO; Int32 sock_optlen[2];#define addr_len sock_optlen nodeaddr peeraddr; TcpMuxCallbDoneActions init_done_actions; sock = (uxsock ? status->unixsock : status->listensock); fl = fcntl(sock, F_GETFL); fcntl(sock, F_SETFL, fl | NONBLOCKING_FLAGS); *((int *) &(addr_len[0])) = sizeof(peeraddr); fd = accept(sock, (struct sockaddr *)(&peeraddr), (int *) &(addr_len[0])); if(fd < 0 || (status->maxconn > 0 && status->num_conns + 1 > status->maxconn)){ if(status->failed_conn_func) status->failed_conn_func(fd >= 0 ? fd : sock, status->data, status); if(fd >= 0) close(fd); } else{ fcntl(sock, F_SETFL, fl & INV_NONBLOCKING_FLAGS); fl = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, fl & INV_NONBLOCKING_FLAGS); fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | 1); if(in_subr && ! status->conn_user_data_to_be_freed){ /* the memory space must be valid until exit from input_proc_func, */ /* cause it might be in use by that function, so we store it in a */ /* status field and free it later */ status->conn_user_data_to_be_freed = status->conn_user_data; status->conn_user_data = NEWP(void *, status->num_conns + 2); memcpy(status->conn_user_data, status->conn_user_data_to_be_freed, sizeof(void *) * (status->num_conns + 1)); } else{ status->conn_user_data = ZRENEWP(status->conn_user_data, void *, status->num_conns + 2); } status->conns = ZRENEWP(status->conns, int, status->num_conns + 1); status->closed_conns = ZRENEWP(status->closed_conns, Flag, status->num_conns + 1); status->conn_fps = ZRENEWP(status->conn_fps, FILE *, status->num_conns + 1); status->closed_conns[status->num_conns] = NO; status->conn_user_data[status->num_conns + 1] = NULL; if(status->conn_init_func){ SETZERO(init_done_actions); init_done_actions.conns_to_close = status->closed_conns; status->conn_user_data[status->num_conns] = (*status->conn_init_func)(fd, status->num_conns, &status->conn_user_data, (struct sockaddr *)(&peeraddr), status->data, &init_done_actions); if(!status->conn_user_data[status->num_conns]){ close(fd); fd = -1; if(status->num_conns < 1 && (status->flags & TCPMUX_STOP_ON_LAST_CLOSE)) end = YES; } if(init_done_actions.have_conns_to_close) status->have_closed_conns = YES; } else status->conn_user_data[status->num_conns] = EMPTY_USER_DATA; if(fd >= 0){ set_socket_keepalive(fd); status->conns[status->num_conns] = fd; status->conn_fps[status->num_conns] = fdopen(fd, "r+"); FD_SET(fd, &status->allfds); if(fd > status->maxfd) status->maxfd = fd; status->num_conns++; } } return(end);}Int32tcp_mux_long_io( void * tmstatptr, int fd, UChar * data, Int32 num, Int32 do_write, Int32 (*rw_func)(int, UChar *, Int32)){ fd_set rfds, wfds; int sock, uxsock; Int32 i, n; TcpMuxStatus *tcpmux_status; Flag lastconn; if(!tmstatptr) return((*rw_func)(fd, data, num)); tcpmux_status = (TcpMuxStatus *) tmstatptr; sock = tcpmux_status->listensock; uxsock = tcpmux_status->unixsock; n = MAX(fd, sock) + 1; forever{ FD_ZERO(&rfds); FD_ZERO(&wfds); if(sock >= 0) FD_SET(sock, &rfds); if(uxsock >= 0) FD_SET(uxsock, &rfds); FD_SET(fd, (do_write ? (&wfds) : (&rfds))); i = select(n, &rfds, &wfds, NULL, NULL); if(i <= 0) return(i); if(FD_ISSET(fd, (do_write ? (&wfds) : (&rfds)))) return((*rw_func)(fd, data, num)); lastconn = NO; if(sock >= 0) if(FD_ISSET(sock, &rfds)) lastconn = (lastconn || accept_connection(tmstatptr, YES, NO)); if(uxsock >= 0) if(FD_ISSET(uxsock, &rfds)) lastconn = (lastconn || accept_connection(tmstatptr, YES, YES)); if(lastconn) fprintf(stderr, "Internal error in netutils.c, 1.\n"); }}Int32tcp_mux_service( int port, UChar *ux_socket, void *(*conn_init_func)(int, Int32, void *, struct sockaddr *, void *, TcpMuxCallbDoneActions *), Int32 (*input_proc_func)(int, void *, Int32, void *, TcpMuxCallbDoneActions *, void *), Int32 (*conn_deinit_func)(int, void *, Int32, void *, void *), Int32 maxconn, void (*failed_conn_func)(int, void *, void *), Uns32 flags, void *data){ Int32 i, j; Int32 r = 0; Int32 actconn; nodeaddr addr; int sock_optval, sockfd_socktype; int sock_typesize, sock_family; Int32 sock_optlen[2]; Flag end = NO; fd_set tmpfds; TcpMuxStatus status; TcpMuxCallbDoneActions input_done_actions; struct sigaction pipe_sigact, org_sigact; SETZERO(status); status.maxconn = maxconn; status.failed_conn_func = failed_conn_func; status.conn_init_func = conn_init_func; status.data = data; status.flags = flags; status.listensock = -1; status.unixsock = -1; SETZERO(pipe_sigact); pipe_sigact.sa_handler = SIG_IGN;#ifdef SA_RESTART pipe_sigact.sa_flags = SA_RESTART;#endif sigaction(SIGPIPE, &pipe_sigact, &org_sigact); if(flags & TCPMUX_INETD_STARTED){ status.listensock = 0; } else{#ifdef HAVE_IP6 status.listensock = socket(sock_family = AF_INET6, SOCK_STREAM, 0); if(status.listensock < 0)#endif status.listensock = socket(sock_family = AF_INET, SOCK_STREAM, 0); if(status.listensock >= 0){ *((int *) &(sock_optlen[0])) = sizeof(int); i = getsockopt(status.listensock, SOL_SOCKET, SO_TYPE, (char *) &sockfd_socktype, (int *) &(sock_optlen[0])); if(i) sockfd_socktype = -1; sock_optval = 1; if(sockfd_socktype == SOCK_STREAM){ i = setsockopt(status.listensock, SOL_SOCKET, SO_REUSEADDR, (char *) &sock_optval, sizeof(int)); /* i is not evaluated: if set REUSEADDR fails, the bind below fails. That's sufficient */ }#ifdef HAVE_IP6 i = -1; if(sock_family == AF_INET6){ ((struct sockaddr *)(&addr))->sa_family = AF_INET6; ((struct sockaddr_in6 *)(&addr))->sin6_port = htons(port); SETZERO(((struct sockaddr_in6 *)(&addr))->sin6_addr.s6_addr); sock_typesize = sizeof(struct sockaddr_in6); i = bind(status.listensock, (struct sockaddr *)(&addr), sock_typesize); } if(i){#endif ((struct sockaddr *)(&addr))->sa_family = AF_INET; ((struct sockaddr_in *)(&addr))->sin_port = htons(port); SETZERO(((struct sockaddr_in *)(&addr))->sin_addr.s_addr); sock_typesize = sizeof(struct sockaddr_in); if( (i = bind(status.listensock, (struct sockaddr *)(&addr), sock_typesize)) ){ close(status.listensock); status.listensock = -1; } #ifdef HAVE_IP6 }#endif if(!i){ if(listen(status.listensock, 64)){ close(status.listensock); status.listensock = -1; } } } } if(ux_socket){ status.unixsock = create_unix_socket(ux_socket); if(status.unixsock >= 0){ fcntl(status.unixsock, F_SETFD, fcntl(status.unixsock, F_GETFD) | 1); i = listen(status.unixsock, 64); if(i){ close(status.unixsock); status.unixsock = -1; } } } if(status.listensock < 0 && status.unixsock < 0) CLEANUPR(-1); if(status.listensock >= 0) fcntl(status.listensock, F_SETFD, fcntl(status.listensock, F_GETFD) | 1); FD_ZERO(&status.allfds); if(status.listensock >= 0) FD_SET(status.listensock, &status.allfds); if(status.unixsock >= 0) FD_SET(status.unixsock, &status.allfds); status.maxfd = MAX(status.listensock, status.unixsock); actconn = status.num_conns; /* force accept first */ do{ status.have_closed_conns = NO; COPYVAL(tmpfds, status.allfds); i = select(status.maxfd + 1, &tmpfds, NULL, NULL, 0); memset(status.closed_conns, 0, status.num_conns * sizeof(status.closed_conns[0])); for(i = -1; i < status.num_conns; i++){ /* one more because of */ if(actconn >= status.num_conns){ /* rotating accept and */ if(status.listensock >= 0){ if(FD_ISSET(status.listensock, &tmpfds)){ /* continue */ if(accept_connection(&status, NO, NO)) end = YES; } } if(status.unixsock >= 0){ if(FD_ISSET(status.unixsock, &tmpfds)){ /* continue */ if(accept_connection(&status, NO, YES)) end = YES; } } actconn = 0; continue; } if(FD_ISSET(status.conns[actconn], &tmpfds)){ if(input_proc_func){ SETZERO(input_done_actions); input_done_actions.conns_to_close = status.closed_conns; j = (*input_proc_func)(status.conns[actconn], status.conn_user_data + actconn, actconn, data, &input_done_actions, &status); if(j) status.closed_conns[actconn] = status.have_closed_conns = YES; ZFREE(status.conn_user_data_to_be_freed); if(input_done_actions.have_conns_to_close) status.have_closed_conns = YES; } } actconn++; } if(status.have_closed_conns){ for(i = 0; i < status.num_conns; i++){ if(status.closed_conns[i]){ if(conn_deinit_func){ j = (*conn_deinit_func)(status.conns[i], status.conn_user_data + i, i, data, &status); } FD_CLR(status.conns[i], &status.allfds); if(status.conn_fps[i]) fclose(status.conn_fps[i]); else close(status.conns[i]); if(status.conns[i] == status.maxfd) status.maxfd--; memmove(status.conns + i, status.conns + i + 1, (status.num_conns - i - 1) * sizeof(status.conns[0])); memmove(status.conn_fps + i, status.conn_fps + i + 1, (status.num_conns - i - 1) * sizeof(status.conn_fps[0])); memmove(status.closed_conns + i, status.closed_conns + i + 1, (status.num_conns - i - 1) * sizeof(status.closed_conns[0])); memmove(status.conn_user_data + i, status.conn_user_data + i + 1, (status.num_conns - i) * sizeof(status.conn_user_data[0])); i--; status.num_conns--; if(status.num_conns < 1 && (flags & TCPMUX_STOP_ON_LAST_CLOSE)){ end = YES; break; } } } } } while(! end); cleanup: if(status.listensock >= 0) close(status.listensock); if(status.unixsock >= 0) close(status.unixsock); ZFREE(status.conns); ZFREE(status.conn_fps);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -