Compiled utility programs for rhel7

This commit is contained in:
2017-01-25 11:37:53 +01:00
parent 6762b0d437
commit 5ed400e2ff
9 changed files with 1205 additions and 5 deletions

View File

@ -1,10 +1,10 @@
.SUFFIXES:
.SUFFIXES: .c .o
OBJ=asynnet.o rwpuffer.o pmacterm.o
OBJ=asynnet.o rwpuffer.o pmacterm.o strlutil.o
.c.o:
$(CC) -c -g $*.c
$(CC) -I. -c -g $*.c
all:pmacterm

View File

@ -1,11 +1,11 @@
.SUFFIXES:
.SUFFIXES: .c .o
LIBROOT=/afs/psi.ch/project/sinq/sl6
LIBROOT=/usr
OBJ=../sicslogquery.o ../approxidate.o sicslogmain.o
CFLAGS=-I$(LIBROOT)/include/libmongoc-1.0 -I../ -I../../sics -I$(LIBROOT)/include/libbson-1.0 -I.
LIBFLAGS=-L$(LIBROOT)/lib -lmongoc-1.0 -lbson-1.0
LIBFLAGS=-L$(LIBROOT)/lib64 -lmongoc-1.0 -lbson-1.0 -lm
.c.o:
$(CC) $(CFLAGS) -c -g $*.c

655
utils/asynnet.c Normal file
View File

@ -0,0 +1,655 @@
/**
* Asynchronous networking for SICS and other programs. This module centrally manages
* a number of network connections for a client program. It is a layer between the
* program and the network which manages non blocking network I/O. To this purpose, the
* client program has to call ANETprocess at convenient intervalls. This module
* has a couple of features:
* - Connections are abstracted to handles which are guranteed to be unique
* rather then socket numbers. Socket numbers may be reused by the OS.
* - This module allows upper level code to figure out if a connection is still
* connected or not.
* - This module introduces a buffer layer between the socket and the application.
* Thus the upper layer does not have to worry much about I/O blocking. This
* is taken care of by this module both for reading and writing.
* - All I/O is non blocking.
* - This module can detect if a client is hanging and close the connection then.
* Hanging is detected by not being able to write to the client for some period
* of time.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, January 2009
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <strlutil.h>
#include "asynnet.h"
#include "rwpuffer.h"
/*--------------------------------------------------------------------------*/
#define SERVERSOCKET 0
#define DATASOCKET 1
#define MAXCONNECTIONS 1024
#define RBUFFERSIZE 262144 /* 256kb */
#define WBUFFERSIZE 20*262144
/* #define WBUFFERSIZE 100*262144 */
#define MAXWBUFFERSIZE 128*1000*1024
/*--------------------------------------------------------------------------*/
typedef struct {
int socket;
int handle;
int type;
prwBuffer readBuffer;
prwBuffer writeBuffer;
time_t lastOpenForWrite;
ANETcallback readCallback;
void *userData;
ANETkill killUser;
char host[132];
} SocketDescriptor, *pSocketDescriptor;
static SocketDescriptor connections[MAXCONNECTIONS];
static int noConnections = 0;
static unsigned int handleID = 0;
/*------------------------------------------------------------------------*/
static int SocketCompare(const void *s1, const void *s2)
{
pSocketDescriptor socke1, socke2;
socke1 = (pSocketDescriptor) s1;
socke2 = (pSocketDescriptor) s2;
return socke1->handle - socke2->handle;
}
/*------------------------------------------------------------------------*/
static void sortConnections()
{
qsort(connections, noConnections,
sizeof(SocketDescriptor), SocketCompare);
}
/*------------------------------------------------------------------------*/
static pSocketDescriptor findSocketDescriptor(int handle)
{
SocketDescriptor key;
pSocketDescriptor result;
key.handle = handle;
result = bsearch(&key, connections, noConnections,
sizeof(SocketDescriptor), SocketCompare);
return result;
}
/*------------------------------------------------------------------------*/
static ANETlog logOutput = NULL;
static void *logUserData = NULL;
/*------------------------------------------------------------------------*/
static void anetLog(int level, char *fmt, ...)
{
va_list ap;
char buf[256];
char *text = NULL;
int l;
if (logOutput == NULL) {
return;
}
va_start(ap, fmt);
l = vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
if (l < sizeof buf) {
text = buf;
logOutput(level, text, logUserData);
} else {
/* assuming we have a C99 conforming snprintf and need a larger buffer */
text = calloc(l, 1);
va_start(ap, fmt);
vsnprintf(text, l, fmt, ap);
va_end(ap);
logOutput(level, text, logUserData);
free(text);
}
}
/*============= public interface =========================================*/
void ANETsetLog(ANETlog lcb, void *userData)
{
logOutput = lcb;
logUserData = userData;
}
/*------------------------------------------------------------------------*/
int ANETopenServerPort(int iPort, ANETcallback cb, void *userData)
{
SocketDescriptor socke;
int i = 1, status;
struct sockaddr_in addresse;
assert(iPort > 0);
assert(cb != NULL);
memset(&socke, 0, sizeof(SocketDescriptor));
socke.socket = socket(AF_INET, SOCK_STREAM, 0);
if (socke.socket < 0) {
anetLog(ANETERROR, "Failed to open server port: socket: %d", iPort);
return ANETOPENFAIL;
}
status =
setsockopt(socke.socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(int));
if (status < 0) {
anetLog(ANETERROR,
"Failed to open server port: setsockopt: %d, errno = %d",
iPort, errno);
return ANETOPENFAIL;
}
memset(&addresse, 0, sizeof(struct sockaddr_in));
addresse.sin_family = AF_INET;
addresse.sin_addr.s_addr = htonl(INADDR_ANY);
addresse.sin_port = htons(iPort);
status = bind(socke.socket, (struct sockaddr *) &addresse,
sizeof(struct sockaddr_in));
if (status < 0) {
anetLog(ANETERROR, "Failed to open server port: bind: %d, errno = %d",
iPort, errno);
return ANETOPENFAIL;
}
status = listen(socke.socket, 8);
if (status < 0) {
anetLog(ANETERROR, "Failed to open server port: listen: %d", iPort);
return ANETOPENFAIL;
}
socke.type = SERVERSOCKET;
socke.handle = handleID;
handleID++;
socke.readCallback = cb;
socke.userData = userData;
socke.lastOpenForWrite = time(NULL);
connections[noConnections] = socke;
noConnections++;
sortConnections();
anetLog(ANETCON, "Opened server port %d", iPort);
return socke.handle;
}
/*-----------------------------------------------------------------------*/
int ANETregisterSocket(int socket)
{
SocketDescriptor socke;
int flags, status;
if (noConnections >= MAXCONNECTIONS) {
anetLog(ANETERROR, "Maximum number of connections exceeded");
return ANETOUTOFSOCKETS;
}
memset(&socke, 0, sizeof(SocketDescriptor));
flags = fcntl(socket, F_GETFL, 0);
status = fcntl(socket, F_SETFL, flags | O_NONBLOCK);
if (status < 0) {
return ANETSOCKERROR;
}
flags =1;
setsockopt(socket,IPPROTO_TCP,TCP_NODELAY,(char *) &flags, sizeof(int));
socke.readBuffer = MakeRWPuffer(RBUFFERSIZE);
socke.writeBuffer = MakeBigRWPuffer(WBUFFERSIZE, MAXWBUFFERSIZE);
if (socke.readBuffer == NULL || socke.writeBuffer == NULL) {
return ANETMEM;
}
socke.socket = socket;
socke.handle = handleID;
handleID++;
socke.type = DATASOCKET;
socke.lastOpenForWrite = time(NULL);
connections[noConnections] = socke;
noConnections++;
sortConnections();
return socke.handle;
}
/*-------------------------------------------------------------------------*/
int ANETconnect(char *name, int iPort)
{
struct in_addr addr;
struct sockaddr_in addresse;
struct hostent *host;
int socke, status;
memset(&addresse, 0, sizeof(struct sockaddr_in));
addresse.sin_family = AF_INET;
addresse.sin_port = htons((unsigned short)(iPort &0xFFFF));
host = gethostbyname(name);
if (host != NULL) {
memcpy((char *) &addr,
(char *)host->h_addr_list[0], (size_t)host->h_length);
} else {
/* check for aaa.bbbb.ccc.dddd */
addr.s_addr = inet_addr(name);
if(addr.s_addr == (unsigned int) -1) {
anetLog(ANETERROR, "Failed to locate host: %s", name);
return ANETOPENFAIL;
}
}
addresse.sin_addr.s_addr = addr.s_addr;
socke = socket(AF_INET, SOCK_STREAM, 0);
status = connect(socke, (struct sockaddr *) &addresse,
sizeof(struct sockaddr_in));
if (status < 0) {
close(socke);
anetLog(ANETERROR, "Failed to open socket to %s:%d", name, iPort);
return ANETOPENFAIL;
}
anetLog(ANETCON, "Opened socket %d to %s:%d", socke, name, iPort);
return ANETregisterSocket(socke);
}
/*--------------------------------------------------------------------------*/
void ANETclose(int handle)
{
pSocketDescriptor socke = NULL;
socke = findSocketDescriptor(handle);
if (socke == NULL) {
return;
}
close(socke->socket);
anetLog(ANETCON, "Closed socket %d", socke->socket);
if (socke->readBuffer != NULL) {
KillRWBuffer(socke->readBuffer);
}
if (socke->writeBuffer != NULL) {
KillRWBuffer(socke->writeBuffer);
}
if (socke->userData && socke->killUser) {
socke->killUser(socke->userData);
}
if (noConnections > 1) {
*socke = connections[noConnections - 1];
noConnections--;
sortConnections();
} else {
noConnections = 0;
}
}
/*--------------------------------------------------------------------------*/
static int anetWrite(SocketDescriptor con)
{
int status, length;
void *pPtr;
pPtr = GetRWBufferData(con.writeBuffer, &length);
if (length > 0) {
status = send(con.socket, pPtr, length, 0);
if (status < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
return 1;
}
ANETclose(con.handle);
return 0;
}
RemoveRWBufferData(con.writeBuffer, status);
}
return 1;
}
/*--------------------------------------------------------------------------
* I have seen that select did not report the write possibility set,
* though the send buffer was empty. Thus I try to write if data is there
* and leave the lastOpenForWrite flag only when the socket would block
* on write.
*--------------------------------------------------------------------------*/
static int anetTestWrite(SocketDescriptor con)
{
int status, length;
void *pPtr;
time_t lastTime;
if(con.type != DATASOCKET){
return 1;
}
lastTime = con.lastOpenForWrite;
con.lastOpenForWrite = time(NULL);
pPtr = GetRWBufferData(con.writeBuffer, &length);
if (length > 0) {
status = send(con.socket, pPtr, length, 0);
if (status < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
con.lastOpenForWrite = lastTime;
return 1;
}
ANETclose(con.handle);
return 0;
}
RemoveRWBufferData(con.writeBuffer, status);
}
return 1;
}
/*--------------------------------------------------------------------------
There is something implicit in the return here: anetRead must return 0
when the list of sockets changes. Otherwise ANETprocess cannot detect that it has
an invalid socket list and jump out. In all other cases anetRead must return 1
-------------------------------------------------------------------------------*/
static int anetRead(SocketDescriptor con)
{
int socke, handle, status;
unsigned int len;
struct sockaddr addresse;
char buffer[8192];
switch (con.type) {
case SERVERSOCKET:
len = sizeof(struct sockaddr);
socke = accept(con.socket, &addresse, &len);
if (socke < 0) {
return 1;
}
handle = ANETregisterSocket(socke);
if (handle > 0) {
status = con.readCallback(handle, con.userData);
if (status != 1) {
ANETclose(handle);
return 0;
}
}
anetLog(ANETCON, "Accepted socket %d on port %d, handle %d",
socke, con.socket, handle);
break;
case DATASOCKET:
memset(buffer, 0, 8192);
status = recv(con.socket, buffer, 8192, 0);
if (status < 0) {
if (errno == EAGAIN) {
return 1;
}
ANETclose(con.handle);
return 0;
} else if (status == 0) {
/* this means EOF */
ANETclose(con.handle);
return 0;
} else {
status = StoreRWBuffer(con.readBuffer, buffer, status);
if (status != 1) {
anetLog(ANETERROR, "Read buffer overrun at handle %d, socket %d",
con.handle, con.socket);
}
if (con.readCallback != NULL) {
con.readCallback(con.handle, con.userData);
}
}
break;
}
return 1;
}
/*---------------------------------------------------------------------------*/
void ANETprocess(void)
{
int i, status, count = 0, socke = 0, length;
fd_set readMask, writeMask;
struct timeval tmo = { 0, 10000 };
FD_ZERO(&readMask);
FD_ZERO(&writeMask);
for (i = 0; i < noConnections; i++) {
socke = connections[i].socket;
FD_SET(socke, &readMask);
if (connections[i].writeBuffer != NULL) {
GetRWBufferData(connections[i].writeBuffer, &length);
if (length > 0)
FD_SET(socke, &writeMask);
else
connections[i].lastOpenForWrite = time(NULL);
}
if (socke > count) {
count = socke;
}
}
count++;
status = select(count, &readMask, &writeMask, NULL, &tmo);
if (status < 0) {
if (errno == EINTR) {
return;
}
return;
}
/**
* I always jump out of this loop when a socket is created or closed
* because then the order in the connections array is no longer valid.
* Try again the next time round.
*/
for (i = 0; i < noConnections; i++) {
socke = connections[i].socket;
if (FD_ISSET(socke, &readMask)) {
if (anetRead(connections[i]) == 0) {
return;
}
}
if (FD_ISSET(socke, &writeMask)) {
/*
* This has to be here, as I found out tracing a subtle bug:
* If the time is set in writeANET the modification will not
* propagate into the array as C copies the structure for the function call.
*/
connections[i].lastOpenForWrite = time(NULL);
if (anetWrite(connections[i]) == 0) {
return;
}
} else {
/*
* If I could not write to the socket for 5 minutes,
* the socket is considered broken and is closed.
*/
if (time(NULL) > connections[i].lastOpenForWrite + 300 &&
connections[i].type == DATASOCKET) {
GetRWBufferData(connections[i].writeBuffer, &length);
anetLog(ANETCON, "Closing socket because of time overrun: %d, delay = %d, bytes to be written = %d, write bit = %d\n", connections[i].socket,
(int)(time(NULL) - connections[i].lastOpenForWrite), length, FD_ISSET(connections[i].socket, &writeMask) );
ANETclose(connections[i].handle);
return;
}
}
}
}
/*--------------------------------------------------------------------------*/
int ANETvalidHandle(int handle)
{
pSocketDescriptor con = NULL;
con = findSocketDescriptor(handle);
if (con != NULL) {
return ANETOK;
} else {
return 0;
}
}
/*---------------------------------------------------------------------------*/
int ANETinfo(int handle, char *hostname, int hostnameLen)
{
pSocketDescriptor con = NULL;
struct sockaddr_in sin;
struct hostent *host;
socklen_t len;
con = findSocketDescriptor(handle);
if (con == NULL) {
return ANETDISCONNECTED;
} else {
if(strlen(con->host) < 3){
len = sizeof sin;
if (getpeername(con->socket, (struct sockaddr *) &sin, &len) < 0) {
return ANETSOCKERROR;
}
if ((host = gethostbyaddr((char *) &sin.sin_addr,
sizeof(sin.sin_addr), AF_INET)) == NULL) {
return ANETSOCKERROR;
}
strlcpy(con->host,host->h_name, 132);
}
memset(hostname, 0, hostnameLen);
strlcpy(hostname, con->host, hostnameLen);
}
return 1;
}
/*---------------------------------------------------------------------------*/
int ANETcanWrite(int handle, void *buffer, int count)
{
pSocketDescriptor con = NULL;
int status;
con = findSocketDescriptor(handle);
if (con == NULL) {
return ANETDISCONNECTED;
} else {
ANETprocess();
return CanStoreRWBuffer(con->writeBuffer, buffer, count);
}
}
/*---------------------------------------------------------------------------*/
int ANETwrite(int handle, void *buffer, int count)
{
pSocketDescriptor con = NULL;
int status;
con = findSocketDescriptor(handle);
if (con == NULL) {
return ANETDISCONNECTED;
} else {
status = StoreRWBuffer(con->writeBuffer, buffer, count);
/*
first try if ANETprocess can write some and free the buffer
before giving up
*/
if (status != 1) {
ANETprocess();
status = StoreRWBuffer(con->writeBuffer, buffer, count);
}
if (status != 1) {
anetLog(ANETERROR, "Write buffer overrun on handle %d, socket %d, trying to write %d bytes",
con->handle, con->socket, count);
return ANETWRITEBUFFERFULL;
}
}
return ANETOK;
}
/*---------------------------------------------------------------------------*/
int ANETread(int handle, void *buffer, int bufferLength)
{
pSocketDescriptor con = NULL;
int status, length, len;
void *data = NULL;
con = findSocketDescriptor(handle);
if (con == NULL) {
return ANETDISCONNECTED;
} else {
data = GetRWBufferData(con->readBuffer, &length);
if (length == 0) {
len = 0;
} else if (length >= bufferLength) {
len = bufferLength;
} else {
len = length;
}
if (len > 0) {
memcpy(buffer, data, len);
}
}
return len;
}
/*---------------------------------------------------------------------------*/
void *ANETreadPtr(int handle, int *length)
{
pSocketDescriptor con = NULL;
void *data = NULL;
con = findSocketDescriptor(handle);
if (con == NULL) {
*length = 0;
return NULL;
} else {
data = GetRWBufferData(con->readBuffer, length);
return data;
}
}
/*---------------------------------------------------------------------------*/
void ANETreadConsume(int handle, int count)
{
pSocketDescriptor con = NULL;
con = findSocketDescriptor(handle);
if (con == NULL) {
return;
} else {
RemoveRWBufferData(con->readBuffer, count);
}
}
/*---------------------------------------------------------------------------*/
void ANETsetReadCallback(int handle, ANETcallback cb,
void *userData, ANETkill killUser)
{
pSocketDescriptor con = NULL;
con = findSocketDescriptor(handle);
if (con == NULL) {
return;
} else {
con->readCallback = cb;
con->userData = userData;
con->killUser = killUser;
}
}
/*----------------------------------------------------------------------------*/
int ANETreadTillTerm(int handle,
ANETtermCallback tcb, void *termData,
ANETwait wcb, void *waitData, char **buffer)
{
pSocketDescriptor con = NULL;
char *data;
int length, status;
while (wcb(waitData) > 0) {
ANETprocess();
con = findSocketDescriptor(handle);
if (con == NULL) {
return ANETDISCONNECTED;
}
data = GetRWBufferData(con->readBuffer, &length);
if (length > 0) {
status = tcb(data, length, termData);
if (status > 0) {
*buffer = malloc(status * sizeof(char));
if (*buffer != NULL) {
memcpy(*buffer, data, status);
}
RemoveRWBufferData(con->readBuffer, status);
return ANETOK;
}
}
}
return ANETTIMEOUT;
}

218
utils/asynnet.h Normal file
View File

@ -0,0 +1,218 @@
/**
* Asynchronous networking for SICS and other programs. This module centrally manages
* a number of network connections for a client program. It is a layer between the
* program and the network which manages non blocking network I/O. To this purpose, the
* client program has to call ANETprocess at convenient intervals. This module
* has a couple of features:
* - Connections are abstracted to handles which are guaranteed to be unique
* rather then socket numbers. Socket numbers may be reused by the OS.
* - This module allows upper level code to figure out if a connection is still
* connected or not.
* - This module introduces a buffer layer between the socket and the application.
* Thus the upper layer does not have to worry much about I/O blocking. This
* is taken care of by this module both for reading and writing.
* - All I/O is non blocking.
* - This module can detect if a client is hanging and close the connection then.
* Hanging is detected by not being able to write to the client for some period
* of time.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, January 2009
*/
#ifndef ASYNNET_H_
#define ASYNNET_H_
/*=================== error codes ========================================*/
#define ANETOK 1
#define ANETDISCONNECTED -10000
#define ANETWRITEBUFFERFULL -10001
#define ANETTIMEOUT -10002
#define ANETOPENFAIL -10003
#define ANETSOCKERROR -10004
#define ANETMEM -10005
#define ANETOUTOFSOCKETS -10006
/*================== log levels ==========================================*/
#define ANETNONE 0
#define ANETERROR 1
#define ANETIO 2
#define ANETCON 3
/*================== callback functions ==================================*/
/**
* \brief Callback called when a connection has been accepted on a
* port or data is ready.
* \param handle The handle of the new network connection
* \return 1 if the new connection can be accepted or 0 if not.
* Same for data.
*/
typedef int (*ANETcallback) (int handle, void *userData);
/**
* \brief a callback which is called in order to determine if a
* a terminator is present in the data.
* \param data The data to inspect
* \param length The length of the data to inspect
* \param userData An opaque pointer passed through to this
* function
* \return -1 when no terminator is in the data, an integer pointing
* to after the terminator in data (in bytes).
*/
typedef int (*ANETtermCallback) (void *data, int length, void *userData);
/**
* \brief a callback function for waiting on some event.
* This is typically called to do something else while waiting
* for data to arrive. It can also return a negative return value,
* which will effectively implement a timeout.
* \param userData An opaque pointer passed through to this callback
* \return 1 to continue waiting, -1 for a timeout.
*/
typedef int (*ANETwait) (void *userData);
/**
* \brief callback to log events in ANET
* \param level The level of the logging message
* \param txt The logging data
* \param userData An opaque pointer passed through to ANETlog
*/
typedef void (*ANETlog) (int level, char *txt, void *userData);
/**
* \brief a callback for killing userdata associated with a read callback.
* This is called in ANETclose, if defined.
* \param userData The user data to kill.
*/
typedef void (*ANETkill) (void *userData);
/*===================== open/close functions =============================*/
/**
* * \brief open a server port
* \param iPort The port number at which to listen for
* connections.
* \param cb A callback which will be called whenever a new connection
* has been accepted on this port.
* \prama userData An opaque pointer to be passed as an argument to the
* callback function.
* \return A handle for the server port or a negative error code.
*/
int ANETopenServerPort(int iPort, ANETcallback cb, void *userData);
/**
* \brief open a client connection to a server.
* \param name the computer name of the server
* \param iPort The port number at which the server is listening
* \return A handle to the open port or a negative error code.
*/
int ANETconnect(char *name, int iPort);
/**
* \brief register a socket to be managed by this module. The socket
* may have been obtained by any means.
* \param socket The file descriptor of the socket
* \return A handle to use for this socket later on.
*/
int ANETregisterSocket(int socket);
/**
* \brief close a connection
* \param handle The handle of the connection
*/
void ANETclose(int handle);
/**
* \brief This function drives I/O processing, i.e. reading and writing.
* This has to be called by the client of this module at regular intervalls.
*/
void ANETprocess(void);
/**
* \brief tests if a handle is still a valid connection
* \param handle The handle to test.
* \return 1 if this is still a connected socket, 0 else.
*/
int ANETvalidHandle(int handle);
/**
* \brief figure out to which host we are connected.
* \param handle The connection handle
* \param hostname a buffer to copy the hostname into
* \param hostNameLen the length of the hostname buffer
* \return 1 on success, a negative error code else.
*/
int ANETinfo(int handle, char *hostname, int hostNameLen);
/*=================== I/O functions ===========================================
* For reading there are possibilities:
* - Raw reading happens through the combination of
* ANETread and ANETreadConsume.
* - Another way for raw reading is to register a read callback which is
* called anytime new data arrives.
* - The usual case is to wait for a line of terminated command input. This is
* done through ANETreadTillterm.
* ==========================================================================*/
/**
* \brief write to the network
* \param handle The handle for the connection
* \param buffer A pointer to the data to write
* \param count The number of bytes to write.
* \return 1 on success, 0 on failure
*/
int ANETwrite(int handle, void *buffer, int count);
/**
* \brief Test if the buffer can be written to the network
* \param handle The handle for the connection
* \param buffer A pointer to the data to write
* \param count The number of bytes to write.
* \return 1 when possible, 0 when buffer overrun
*/
int ANETcanWrite(int handle, void *buffer, int count);
/**
* \brief copy at max bufferLength bytes into buffer. The data is not deleted from
* the read buffer yet.
* \param handle The handle of the connection to read from
* \param buffer a pointer to an area for holding the data
* \param bufferLength The maximum number of bytes which can be copied into
* the buffer.
* \return The number of bytes copied. Can be 0 if no data is available. On
* errors a negative error code is returned.
*/
int ANETread(int handle, void *buffer, int bufferLength);
/**
* \brief Get a pointer to the data which has been read up to now.
* Do not mess with the data!! Else the result may be badly defined!
* \param handle The handle for the connection
* \param length will be set to the length of the data read so far.
* \return NULL when the socket is disconnected, a pointer else.
*/
void *ANETreadPtr(int handle, int *length);
/**
* \brief remove count bytes from the read buffer.
* \param handle The handle for the connection.
* \param count The number of bytes which can be removed from the
* read buffer.
*/
void ANETreadConsume(int handle, int count);
/**
* \brief set a callback to be called when data is available at the port.
* \param handle The handle of the connection
* \param cb The callback function to call
* \param userData An opaque pointer passed on as a parameter to the
* callback function.
*/
void ANETsetReadCallback(int handle, ANETcallback cb, void *userData,
ANETkill killUser);
/**
* \brief wait for terminated data to arrive.
* \param handle The connection handle to read from
* \param tcb a callback function which determines if a terminator is in the
* data.
* \param termData An opaque data pointer passed on to tcb
* \param wcb A callback function called while waiting for data
* to arrive.
* \param waitData An opaque pointer passed on to wcb
* \param buffer A newly allocated buffer holding the data as read
* including the terminator.
* \return 1 on success, a negative error code else.
*/
int ANETreadTillTerm(int handle,
ANETtermCallback tcb, void *termData,
ANETwait wcb, void *waitData, char **buffer);
/**
* Note to Markus: suitable callbacks for the standard case: waiting for \n and
* TaskYield for waiting to a timeout will become part of nread.h, .c.
*/
/*========================== system ====================================*/
/**
* \brief install a logging function
* \param lcb The logging function to install
* \param userData An opaque pointer with data for lcb
*/
void ANETsetLog(ANETlog lcb, void *userData);
#endif /*ASYNNET_H_ */

View File

@ -7,7 +7,7 @@
# Mark Koennecke, December 2009
#--------------------------------------------------------------------------
include ../../linux_def
include ../../sics/linux_def
CC = gcc
CFLAGS = -g -DLINUX $(DFORTIFY) -I../hardsup -I.

136
utils/rwpuffer.c Normal file
View File

@ -0,0 +1,136 @@
/**
* This is a buffer to store bytes for reading and writing.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, January 2009
*
* added resizing option and MakeBigRWPuffer in order to support transfer
* of large amounts of image data on few connections
*
* Mark Koennecke, August 2014
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "rwpuffer.h"
/*----------------------------------------------------------------------*/
typedef struct __RWBuffer {
char *data;
int length;
int startPtr;
int endPtr;
int maxSize;
} RWBuffer;
/*----------------------------------------------------------------------*/
prwBuffer MakeRWPuffer(int size)
{
prwBuffer self = NULL;
self = malloc(sizeof(RWBuffer));
if (self == NULL) {
return NULL;
}
self->data = calloc(size, sizeof(char));
if (self->data == NULL) {
return NULL;
}
self->length = size;
self->startPtr = 0;
self->endPtr = 0;
self->maxSize = size;
return self;
}
/*------------------------------------------------------------------------*/
prwBuffer MakeBigRWPuffer(int size, int maxSize)
{
prwBuffer result = MakeRWPuffer(size);
if(result != NULL){
result->maxSize = maxSize;
}
return result;
}
/*------------------------------------------------------------------------*/
void KillRWBuffer(prwBuffer self)
{
if (self == NULL) {
return;
}
if (self->data != NULL) {
free(self->data);
}
free(self);
}
/*------------------------------------------------------------------------*/
int CanStoreRWBuffer(prwBuffer self, void *data, int count)
{
int length;
char *ptr;
length = self->endPtr - self->startPtr;
if (count + length >= self->length ) {
if(self->length < self->maxSize){
ptr = calloc(self->maxSize,sizeof(char));
if(ptr == NULL) {
return 0;
}
memcpy(ptr,self->data, length*sizeof(char));
free(self->data);
self->data = ptr;
self->length = self->maxSize;
} else {
return 0;
}
}
return 1;
}
/*------------------------------------------------------------------------*/
int StoreRWBuffer(prwBuffer self, void *data, int count)
{
int length;
char *ptr;
length = self->endPtr - self->startPtr;
if (count + length >= self->length ) {
if(self->length < self->maxSize){
ptr = calloc(self->maxSize,sizeof(char));
if(ptr == NULL) {
printf("HELP: RWBuffer overrun!!!!\n");
return 0;
}
memcpy(ptr,self->data, length*sizeof(char));
free(self->data);
self->data = ptr;
self->length = self->maxSize;
} else {
printf("HELP: RWBuffer overrun!!!!\n");
return 0;
}
}
if (count + self->endPtr > self->length) {
memmove(self->data, self->data + self->startPtr, length);
self->startPtr = 0;
self->endPtr = length;
}
memcpy(self->data + self->endPtr, data, count);
self->endPtr += count;
return 1;
}
/*------------------------------------------------------------------------*/
void *GetRWBufferData(prwBuffer self, int *length)
{
*length = self->endPtr - self->startPtr;
return (void *) self->data + self->startPtr;
}
/*-------------------------------------------------------------------------*/
void RemoveRWBufferData(prwBuffer self, int count)
{
self->startPtr += count;
if (self->startPtr >= self->endPtr) {
self->startPtr = 0;
self->endPtr = 0;
memset(self->data,0,self->length*sizeof(char));
}
}

61
utils/rwpuffer.h Normal file
View File

@ -0,0 +1,61 @@
/**
* This is a buffer to store bytes for reading and writing.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, January 2009
*/
#ifndef RWPUFFER_H_
#define RWPUFFER_H_
typedef struct __RWBuffer *prwBuffer;
/**
* \brief create a RW buffer.
* \param size The size of the buffer.
* \return NULL on success, else a pointer to t a new rwPuffer
*/
prwBuffer MakeRWPuffer(int size);
/**
* \brief create a RW buffer which can grow.
* \param size The size of the buffer.
* \param maxSize The maximum size of the buffer.
* \return NULL on success, else a pointer to t a new rwPuffer
*/
prwBuffer MakeBigRWPuffer(int size, int maxSize);
/**
* \brief delete a rw buffer.
* \param self The rwPuffer to delete.
*/
void KillRWBuffer(prwBuffer self);
/**
* \brief store some data in the RW buffer
* \param self The rw buffer to store the data in
* \param data pointer to the data to store
* \param count The number of bytes to store
* \return 1 on success, 0 on failure
*/
int StoreRWBuffer(prwBuffer self, void *data, int count);
/**
* \brief Test if the data can be stored in the rwBuffer
* \param self The rw buffer to store the data in
* \param data pointer to the data to store
* \param count The number of bytes to store
* \return 1 when OK, 0 when buffer full
*/
int CanStoreRWBuffer(prwBuffer self, void *data, int count);
/**
* \brief Get a pointer to the current buffer data
* \param self the buffer to get the data from
* \param length Will be set to the number of available bytes.
* \return A pointer to the data
*/
void *GetRWBufferData(prwBuffer self, int *length);
/**
* \brief remove data from the buffer
* \param self the buffer to remove data from
* \param count The number of bytes to remove
*/
void RemoveRWBufferData(prwBuffer self, int count);
#endif /*RWPUFFER_H_ */

112
utils/strlutil.c Normal file
View File

@ -0,0 +1,112 @@
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
/* only compile if no system supplied version */
#ifndef strlcpy
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif

18
utils/strlutil.h Normal file
View File

@ -0,0 +1,18 @@
/*
* strlutil.h
* Provide strcpy, strlcat when not provided by ssystem
*
* Created on: Mar 25, 2010
* Author: koennecke
*/
#ifndef STRLUTIL_H_
#define STRLUTIL_H_
#ifndef strlcpy
size_t strlcat(char *dst, const char *src, size_t siz);
size_t strlcpy(char *dst, const char *src, size_t siz);
#endif
#endif /* STRLUTIL_H_ */