ossp-pkg/l2/l2_sockmon.c
/*
** 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 <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#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 <IPv4-or-IPv6> <TCP-or-UDP> <Port>\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);
}