- Fixed a core dump in the sycamore protocol
- Added missing files aynnet.* - Fixed the addition to root issue in scriptcontex
This commit is contained in:
576
asynnet.c
Normal file
576
asynnet.c
Normal file
@ -0,0 +1,576 @@
|
||||
/**
|
||||
* 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 <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include "asynnet.h"
|
||||
#include "rwpuffer.h"
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define SERVERSOCKET 0
|
||||
#define DATASOCKET 1
|
||||
#define MAXCONNECTIONS 1024
|
||||
#define RBUFFERSIZE 262144 /* 256kb */
|
||||
#define WBUFFERSIZE 2*262144 /* 512kb */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
int socket;
|
||||
int handle;
|
||||
int type;
|
||||
prwBuffer readBuffer;
|
||||
prwBuffer writeBuffer;
|
||||
time_t lastOpenForWrite;
|
||||
ANETcallback readCallback;
|
||||
void *userData;
|
||||
ANETkill killUser;
|
||||
} 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;
|
||||
}
|
||||
socke.readBuffer = MakeRWPuffer(RBUFFERSIZE);
|
||||
socke.writeBuffer = MakeRWPuffer(WBUFFERSIZE);
|
||||
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;
|
||||
|
||||
/* check for aaa.bbb.ccc.ddd first */
|
||||
addr.s_addr = inet_addr(name);
|
||||
if (addr.s_addr < 0) {
|
||||
host = gethostbyname(name);
|
||||
if (host == NULL) {
|
||||
anetLog(ANETERROR, "Failed to locate host: %s", name);
|
||||
return ANETOPENFAIL;
|
||||
}
|
||||
memcpy(&addr, host->h_addr_list, sizeof(struct in_addr));
|
||||
}
|
||||
memset(&addresse, 0, sizeof(struct sockaddr_in));
|
||||
addresse.sin_family = AF_INET;
|
||||
addresse.sin_port = iPort;
|
||||
addresse.sin_addr = addr;
|
||||
socke = socket(AF_INET, SOCK_STREAM, 0);
|
||||
status = connect(socke, (struct sockaddr *) &addresse,
|
||||
sizeof(struct sockaddr_in));
|
||||
if (status < 0) {
|
||||
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;
|
||||
|
||||
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) {
|
||||
return 1;
|
||||
}
|
||||
ANETclose(con.handle);
|
||||
return 0;
|
||||
}
|
||||
RemoveRWBufferData(con.writeBuffer, status);
|
||||
}
|
||||
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;
|
||||
fd_set readMask, writeMask;
|
||||
struct timeval tmo = { 0, 10 };
|
||||
|
||||
FD_ZERO(&readMask);
|
||||
FD_ZERO(&writeMask);
|
||||
for (i = 0; i < noConnections; i++) {
|
||||
socke = connections[i].socket;
|
||||
FD_SET(socke, &readMask);
|
||||
FD_SET(socke, &writeMask);
|
||||
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])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(socke, &writeMask)) {
|
||||
if (!anetWrite(connections[i])) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* if I could not write to the socket for three minutes,
|
||||
* the socket is considered broken and is closed
|
||||
*/
|
||||
if (time(NULL) > connections[i].lastOpenForWrite + 180 &&
|
||||
connections[i].type == DATASOCKET) {
|
||||
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 (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;
|
||||
}
|
||||
memset(hostname, 0, hostnameLen);
|
||||
strncpy(hostname, host->h_name, hostnameLen);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
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",
|
||||
con->handle, con->socket);
|
||||
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) {
|
||||
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;
|
||||
}
|
209
asynnet.h
Normal file
209
asynnet.h
Normal file
@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
#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.
|
||||
*/
|
||||
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 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_ */
|
11
protocol.c
11
protocol.c
@ -476,7 +476,7 @@ void sycformat(char *tag, OutCode msgFlag, pDynString msgString,
|
||||
int SCWriteSycamore(SConnection * pCon, char *pBuffer, int iOut)
|
||||
{
|
||||
int iRet;
|
||||
char pBueffel[MAXMSG], *pBufferFrom, *pBufferTo;
|
||||
char pBueffel[MAXMSG];
|
||||
long taskID = 0;
|
||||
/* char pPrefix[40];*/
|
||||
pDynString pMsg = NULL;
|
||||
@ -487,15 +487,6 @@ int SCWriteSycamore(SConnection * pCon, char *pBuffer, int iOut)
|
||||
if (strlen(pBuffer) == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* Strip \r and \n */
|
||||
for (pBufferFrom = pBufferTo = pBuffer;; pBufferFrom++) {
|
||||
if (*pBufferFrom == '\r' || *pBufferFrom == '\n')
|
||||
continue;
|
||||
*pBufferTo = *pBufferFrom;
|
||||
if (*pBufferTo == '\0')
|
||||
break;
|
||||
pBufferTo++;
|
||||
}
|
||||
|
||||
if (!SCVerifyConnection(pCon)) {
|
||||
return 0;
|
||||
|
@ -1005,9 +1005,17 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install into the Hipadaba when full path given
|
||||
*/
|
||||
if(strstr(argv[1],"/") != NULL){
|
||||
parent = FindHdbParent(NULL, argv[1], &nodeName, con);
|
||||
if (parent == NULL)
|
||||
return 0; /* error message already written */
|
||||
} else {
|
||||
nodeName = argv[1];
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
controller = calloc(1, sizeof(*controller));
|
||||
assert(controller);
|
||||
@ -1022,7 +1030,9 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
|
||||
ccmd->pPrivate = controller;
|
||||
ccmd->KillPrivate = SctKillController;
|
||||
|
||||
if(parent != NULL){
|
||||
AddHipadabaChild(parent, controller->node, con);
|
||||
}
|
||||
|
||||
controller->devser = DevMake(con, argc - 2, argv + 2);
|
||||
if (!controller->devser)
|
||||
|
@ -3310,7 +3310,7 @@ static int GetSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
}
|
||||
status = GetHdbProperty(targetNode, argv[2], buffer, 511);
|
||||
if (status != 1) {
|
||||
SCPrintf(pCon, eValue, "ERROR: property %s not found", argv[2]);
|
||||
SCPrintf(pCon, eError, "ERROR: property %s not found", argv[2]);
|
||||
return 0;
|
||||
}
|
||||
SCPrintf(pCon, eValue, "%s.%s = %s", argv[1], argv[2], buffer);
|
||||
|
Reference in New Issue
Block a user