/* ** L2 - OSSP Logging Library ** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) ** ** This file is part of OSSP L2, a flexible logging library which ** can be found at http://www.ossp.org/pkg/l2/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** l2_sockmon.c: Socket monitor for use with l2_test.c */ #include #include #include #include #include #include #include #include #include #include "l2.h" #include "l2_ut_sa.h" #define BACKLOG 1024 /* max # pending connections */ #define BUFFSIZ 256 /* max string size */ #define L2_SA_SOCKET_TIMEOUT 64 #define L2_SA_SOCKET_BUFSIZE 4096 char *strlowerdup(const char *); /* prototypes */ void dowork(int); int myserver(int, int, int); void die(const char *); void closedie(sa_t *, const char *); void usage(char *); void die(const char *szMsg) { perror(szMsg); exit(EXIT_FAILURE); } void closedie(sa_t *saSock, const char *szMsg) { perror(szMsg); sa_destroy(saSock); /* saSock->destroy would really be nice here */ exit(EXIT_FAILURE); } char *strlowerdup(const char *szIn) { int i = 0; char *szTemp = NULL; assert(szIn != NULL); if ((szTemp = (char *)strdup(szIn)) == NULL) return NULL; else { for (i = 0; *(szTemp + i); i++) if (isupper(*(szTemp + i))) *(szTemp + i) = (char)tolower(*(szTemp + i)); return szTemp; } } void dowork(int iSock) { char szBuf[BUFFSIZ]; int cc; while (1) { /* Exits when read finishes */ cc = read(iSock, szBuf, sizeof (szBuf)); if (cc == -1) die("read()"); if (cc == 0) { /* EOF */ close(iSock); fprintf(stderr, "Connection closed\n"); exit(EXIT_SUCCESS); } szBuf[cc + 1] = '\0'; fprintf(stderr, "Read: %s", szBuf); if (write(iSock, szBuf, cc) == -1) die("write()"); } } int myserver(int iFamily, int iProtocol, int iPort) { sa_type_t saType; sa_addr_t *saAddr; sa_t *saListen, saAccept; int iSock, iSockopt; char szBuf[BUFFSIZ]; char szAddrin4[INET_ADDRSTRLEN]; char szAddrin6[INET6_ADDRSTRLEN]; struct sockaddr_in faddr4, caddr4; struct sockaddr_in6 faddr6, caddr6; int iNewsock; int cc; socklen_t faddrlen; /* Create socket address, the sa_addr object */ /* starts in a state similar to INADDR_ANY */ if (sa_addr_create(&saAddr) != SA_OK) die("sa_addr_create()"); /* Create socket */ if (sa_create(&saListen) != SA_OK) closedie(saListen, "sa_create()"); if (!(iProtocol == IPPROTO_UDP || iProtocol == IPPROTO_TCP)) closedie(saListen, "unknown protocol"); saType = (iProtocol == IPPROTO_UDP) ? SA_TYPE_DATAGRAM : SA_TYPE_STREAM; /* Configure socket parameters */ sa_timeout(saListen, L2_SA_SOCKET_TIMEOUT, 0); sa_buffers(saListen, L2_SA_SOCKET_BUFSIZE, L2_SA_SOCKET_BUFSIZE); sa_type (saListen, saType); /* Allow local addresses to be reused */ if (sa_getfd(saListen, &iSock) != SA_OK) closedie(saListen, "sa_getfd()"); iSockopt = 1; if (setsockopt(iSock, SOL_SOCKET, SO_REUSEADDR, (void *)&iSockopt, sizeof (iSockopt)) == -1) closedie(saListen, "setsockopt()"); if (sa_bind(saListen, saAddr) != SA_OK) closedie(saListen, "sa_bind()"); if (iProtocol == IPPROTO_UDP) { if (iFamily == AF_INET6) { /* initialize address structure */ memset(&caddr6, 0, sizeof(caddr6)); for (;;) { /* Receive messages */ faddrlen = sizeof(caddr6); memset(szBuf, 0x0, BUFFSIZ); /* Init the buffer */ cc = recvfrom(iSock, szBuf, BUFFSIZ, 0, (struct sockaddr *)\ &caddr6, &faddrlen); if (cc == -1) die("recvfrom()"); if (cc == 0) { /* EOF */ close(iSock); fprintf(stderr, "Connection closed\n"); return 0; } if (cc != BUFFSIZ) { szBuf[cc + 1] = '\0'; fprintf(stderr, "Read: %s", szBuf); if (write(iSock, szBuf, cc) == -1) die("write()"); } else return -1; } } else if (iFamily == AF_INET) { /* initialize address structure */ memset(&caddr4, 0, sizeof(caddr4)); for (;;) { /* Receive messages */ faddrlen = sizeof(caddr4); memset(szBuf, 0x0, BUFFSIZ); /* Init the buffer */ cc = recvfrom(iSock, szBuf, BUFFSIZ, 0, (struct sockaddr *)\ &caddr4, &faddrlen); if (cc == -1) die("recvfrom()"); if (cc == 0) { /* EOF */ close(iSock); fprintf(stderr, "Connection closed\n"); return 0; } if (cc != BUFFSIZ) { szBuf[cc + 1] = '\0'; fprintf(stderr, "Read: %s", szBuf); if (write(iSock, szBuf, cc) == -1) die("write()"); } else return -1; } } } else if (iProtocol == IPPROTO_TCP) { /* Only try to listen if we have TCP */ if (sa_listen(saListen, BACKLOG) != SA_OK) closedie(saListen, "sa_listen()"); /* Wait for a connection request */ if (iFamily == AF_INET6) { /* initialize address structure */ memset(&faddr6, 0, sizeof(faddr6)); for (;;) { faddrlen = sizeof (faddr6); if (sa_accept(saListen, &saAddr, &saAccept) != SA_OK) { sa_destroy(saAccept); closedie(saListen, "sa_accept()"); } if (sa_addr_a2u(saAddr, char **uri)) if (inet_ntop(AF_INET6, &faddr6.sin6_addr, szAddrin6, sizeof(szAddrin6)) != NULL) { fprintf(stderr, "Connection from %s/%d\n", szAddrin6, ntohs(faddr6.sin6_port)); dowork(iNewsock); /* do some sockwork */ } else die("inet_ntop()"); } } else if (iFamily == AF_INET) { /* initialize address structure */ memset(&faddr4, 0, sizeof(faddr4)); for (;;) { faddrlen = sizeof (faddr4); iNewsock = accept(iSock, (struct sockaddr *)&faddr4, &faddrlen); if (iNewsock == -1) { if (errno != EINTR && errno != ECONNABORTED) { perror("accept()"); } continue; } inet_ntop(AF_INET6, &faddr4.sin_addr, szAddrin4, sizeof(szAddrin4)); fprintf(stderr, "Connection from %s/%d\n", szAddrin4, ntohs(faddr6.sin6_port)); dowork(iNewsock); /* do some sockwork */ } } } /* NOTREACHED */ return -1; /* Failure due to non UDP/TCP request, or execution flow */ } void usage(char *szApp) { fprintf(stderr, "Usage: %s \n", szApp); exit(EXIT_FAILURE); /* The user doesn't know how to use this */ } int main(int argc, char *argv[]) { int iFam = -1; int iProto = -1; int iPort = 0; if (argc != 4) usage(argv[0]); if (!strcmp(argv[1], "IPv6")) iFam = AF_INET6; else if (!strcmp(argv[1], "IPv4")) iFam = AF_INET; else usage(argv[0]); if (!strcmp(argv[2], "UDP")) iProto = IPPROTO_UDP; else if (!strcmp(argv[2], "TCP")) iProto = IPPROTO_TCP; else usage(argv[0]); iPort = htons(atoi(argv[3])); return myserver(iFam, iProto, iPort); }