Compiled utility programs for rhel7
This commit is contained in:
@ -1,10 +1,10 @@
|
|||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
OBJ=asynnet.o rwpuffer.o pmacterm.o
|
OBJ=asynnet.o rwpuffer.o pmacterm.o strlutil.o
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) -c -g $*.c
|
$(CC) -I. -c -g $*.c
|
||||||
|
|
||||||
all:pmacterm
|
all:pmacterm
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
LIBROOT=/afs/psi.ch/project/sinq/sl6
|
LIBROOT=/usr
|
||||||
|
|
||||||
OBJ=../sicslogquery.o ../approxidate.o sicslogmain.o
|
OBJ=../sicslogquery.o ../approxidate.o sicslogmain.o
|
||||||
CFLAGS=-I$(LIBROOT)/include/libmongoc-1.0 -I../ -I../../sics -I$(LIBROOT)/include/libbson-1.0 -I.
|
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:
|
.c.o:
|
||||||
$(CC) $(CFLAGS) -c -g $*.c
|
$(CC) $(CFLAGS) -c -g $*.c
|
||||||
|
655
utils/asynnet.c
Normal file
655
utils/asynnet.c
Normal 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
218
utils/asynnet.h
Normal 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_ */
|
@ -7,7 +7,7 @@
|
|||||||
# Mark Koennecke, December 2009
|
# Mark Koennecke, December 2009
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
include ../../linux_def
|
include ../../sics/linux_def
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -g -DLINUX $(DFORTIFY) -I../hardsup -I.
|
CFLAGS = -g -DLINUX $(DFORTIFY) -I../hardsup -I.
|
||||||
|
136
utils/rwpuffer.c
Normal file
136
utils/rwpuffer.c
Normal 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
61
utils/rwpuffer.h
Normal 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
112
utils/strlutil.c
Normal 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
18
utils/strlutil.h
Normal 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_ */
|
Reference in New Issue
Block a user