/*
* Copyright (C) 2001, Shilad Sen, Sourcelight Technologies, Inc.
* See xmlrpc.h or the README for more copyright information.
*/
#include <assert.h>
#include <math.h>
#include "xmlrpc.h"
#include "rpcInternal.h"
#ifdef MSWINDOWS
#include <sys/types.h>
#include <sys/timeb.h>
#include <winsock2.h>
#define USE_FTIME
#else
#include <unistd.h>
#include <sys/time.h>
#endif /* MSWINDOWS */
#define INIT_SOURCES 64
static bool dispNextEv(rpcDisp *dp, double timeOut);
static int dispHandleError(rpcSource *srcp);
static double get_time(void);
rpcDisp *
rpcDispNew(void)
{
rpcDisp *dp;
dp = PyObject_NEW(rpcDisp, &rpcDispType);
if (dp == NULL)
return NULL;
dp->maxid = 1;
dp->scard = 0;
dp->salloc = INIT_SOURCES;
dp->etime = -1.0;
dp->srcs = alloc(dp->salloc * sizeof(*dp->srcs));
if (dp->srcs == NULL)
return NULL;
memset(dp->srcs, 0, dp->salloc * sizeof(*dp->srcs));
return dp;
}
void
rpcDispClear(rpcDisp *dp)
{
uint i;
for (i = 0; i < dp->scard; ++i)
Py_DECREF(dp->srcs[i]);
dp->scard = 0;
}
void
rpcDispDealloc(rpcDisp *dp)
{
if (dp->srcs) {
rpcDispClear(dp);
free(dp->srcs);
}
PyMem_DEL(dp);
}
bool
rpcDispAddSource(rpcDisp *dp, rpcSource *sp)
{
if (dp->scard + 1 > dp->salloc) {
dp->salloc *= 2;
dp->srcs = ralloc(dp->srcs, dp->salloc * sizeof(*dp->srcs));
if (dp->srcs == NULL)
return false;
memset(dp->srcs + dp->scard, 0,
(dp->salloc - dp->scard) * sizeof(*dp->srcs));
}
Py_INCREF(sp);
sp->id = dp->maxid;
dp->srcs[dp->scard] = sp;
dp->scard++;
dp->maxid++;
return true;
}
/*
* the only way this can fail is if we can't find the source
*/
bool
rpcDispDelSource(rpcDisp *dp, rpcSource *sp)
{
bool found;
uint i;
found = false;
for (i = 0; i < dp->scard; ++i)
if (found)
dp->srcs[i - 1] = dp->srcs[i];
else if (dp->srcs[i]->id == sp->id)
found = true;
if (not found)
return false;
Py_DECREF(sp);
dp->scard--;
dp->srcs[dp->scard] = NULL;
return true;
}
/*
* return a list of important filenos
*/
PyObject *
rpcDispActiveFds(rpcDisp *dp)
{
PyObject *inp,
*out,
*exc,
*fd,
*res;
rpcSource *src;
uint i;
inp = PyList_New(0);
out = PyList_New(0);
exc = PyList_New(0);
if (inp == NULL || out == NULL || exc == NULL)
return NULL;
for (i = 0; i < dp->scard; ++i) {
src = dp->srcs[i];
fd = PyInt_FromLong((long)src->fd);
if (fd == NULL)
return NULL;
if ((src->actImp & ACT_INPUT)
and (PyList_Append(inp, fd)))
return NULL;
if ((src->actImp & ACT_OUTPUT)
and (PyList_Append(out, fd)))
return NULL;
if ((src->actImp & ACT_EXCEPT)
and (PyList_Append(exc, fd)))
return NULL;
Py_DECREF(fd);
}
res = Py_BuildValue("(O,O,O)", inp, out, exc);
Py_DECREF(inp);
Py_DECREF(out);
Py_DECREF(exc);
return res;
}
/*
* dispatch events on the active file descriptors for some length of time
*/
bool
rpcDispWork(rpcDisp *dp, double timeout, bool *timedOut)
{
rpcSource **srcs,
*sp,
tp;
double ct;
bool found;
uint i,
j,
scard;
int res;
*timedOut = false;
ct = 0.0; /* to appease the compiler */
if (timeout >= 0.0) {
ct = get_time();
if (ct < 0) {
PyErr_SetFromErrno(rpcError);
return false;
}
dp->etime = ct + timeout;
} else
dp->etime = -1.0;
while (dp->scard != 0) {
unless (dispNextEv(dp, (dp->etime - ct)))
return false;
scard = dp->scard;
srcs = alloc(scard * sizeof(*srcs));
memcpy(srcs, dp->srcs, scard * sizeof(*srcs));
for (i = 0; i < scard; ++i) {
sp = srcs[i];
unless (sp->actOcc)
continue;
found = false;
for (j = 0; dp->scard; ++j)
if (dp->srcs[j]->id == sp->id) {
found = true;
break;
}
/* if nothing changed out from under us... */
/* fix: otherwise log an error?? */
unless (found and (sp->actImp & sp->actOcc))
continue;
Py_INCREF(sp);
rpcDispDelSource(dp, sp);
/* copy the source so we can reset the original */
/* and call the copied version */
memcpy(&tp, sp, sizeof(*sp));
sp->id = -1;
sp->actImp = 0;
sp->actOcc = 0;
sp->params = NULL;
sp->func = NULL;
unless ((tp.func)(dp, sp, tp.actOcc, tp.params)) {
Py_DECREF(tp.params);
res = dispHandleError(sp);
unless (res & ONERR_KEEP_WORK) {
Py_DECREF(sp);
return false;
}
} else
Py_DECREF(tp.params);
Py_DECREF(sp);
}
free(srcs);
if (dp->etime >= 0.0) {
ct = get_time();
if (ct < 0) {
PyErr_SetFromErrno(rpcError);
return false;
}
if (dp->etime < ct) {
*timedOut = true;
break;
}
}
}
return true;
}
static int
dispHandleError(rpcSource *srcp)
{
int (*cfunc)(rpcSource *),
res;
PyObject *pyfunc,
*pyres,
*tuple,
*exc,
*v,
*tb,
*nexc,
*nv,
*ntb;
nexc = NULL;
nv = NULL;
ntb = NULL;
PyErr_Fetch(&exc, &v, &tb);
PyErr_NormalizeException(&exc, &v, &tb);
PyErr_Clear();
res = ONERR_KEEP_DEF;
if (srcp->onErr == NULL)
/* do nothing */;
else if (srcp->onErrType == ONERR_TYPE_C) {
cfunc = srcp->onErr;
res = cfunc(srcp);
} else {
nexc = exc;
nv = v;
ntb = tb;
Py_XINCREF(nexc);
Py_XINCREF(nv);
Py_XINCREF(ntb);
if (nexc == NULL) {
Py_INCREF(Py_None);
nexc = Py_None;
}
if (nv == NULL) {
Py_INCREF(Py_None);
nv = Py_None;
}
if (ntb == NULL) {
Py_INCREF(Py_None);
ntb = Py_None;
}
pyfunc = srcp->onErr;
assert(PyCallable_Check(pyfunc));
tuple = Py_BuildValue("(O,(O,O,O))", srcp, nexc, nv, ntb);
if (tuple == NULL) {
fprintf(rpcLogger, "BAD ERROR HANDLER ERROR!!\n");
PyErr_Print();
} else {
pyres = PyObject_CallObject(pyfunc, tuple);
if (pyres == NULL) {
fprintf(rpcLogger, "ERROR HANDLER FAILED!!\n");
PyErr_Print();
} else if (PyInt_Check(pyres)) {
res = (int)PyInt_AS_LONG(pyres);
} else {
fprintf(rpcLogger, "Error handler returned:");
PyObject_Print(pyres, rpcLogger, 0);
fprintf(rpcLogger, "\n");
fprintf(rpcLogger, "Defaulting to %d\n",
ONERR_KEEP_DEF);
}
Py_DECREF(tuple);
Py_XDECREF(pyres);
}
Py_DECREF(nexc);
Py_DECREF(nv);
Py_DECREF(ntb);
}
if (res & ONERR_KEEP_DEF) {
if (srcp->doClose and srcp->fd >= 0) {
close(srcp->fd);
srcp->fd = -1;
}
if (srcp->desc == NULL)
fprintf(rpcLogger, "Error from source <fd %d>:\n",
srcp->fd);
else
fprintf(rpcLogger, "Error from source <%s, fd %d>:\n",
srcp->desc, srcp->fd);
PyErr_Restore(exc, v, tb);
} else if (! res & ONERR_KEEP_WORK) {
PyErr_Restore(exc, v, tb);
} else {
Py_XDECREF(exc);
Py_XDECREF(v);
Py_XDECREF(tb);
}
return res;
}
/*
* find the next events
*/
static bool
dispNextEv(rpcDisp *dp, double timeout)
{
rpcSource *src;
struct timeval tv;
fd_set inFd,
outFd,
excFd;
int i,
nEvents,
maxFd;
bool hasImm;
maxFd = -1;
hasImm = false;
FD_ZERO(&inFd);
FD_ZERO(&outFd);
FD_ZERO(&excFd);
for (i = 0; i < (int)dp->scard; ++i) {
src = dp->srcs[i];
src->actOcc = 0;
unless (src->actImp)
continue;
if (src->actImp & ACT_IMMEDIATE) {
src->actOcc |= ACT_IMMEDIATE;
hasImm = true;
} else if (src->fd < 0) {
fprintf(rpcLogger, "BAD FD!!: %d\n", src->fd);
continue;
} else {
if (src->actImp & ACT_INPUT)
FD_SET((uint)src->fd, &inFd);
if (src->actImp & ACT_OUTPUT)
FD_SET((uint)src->fd, &outFd);
if (src->actImp & ACT_EXCEPT)
FD_SET((uint)src->fd, &excFd);
if (src->fd > maxFd)
maxFd = src->fd;
}
}
if (hasImm)
timeout = 0.0;
if (maxFd != -1) {
Py_BEGIN_ALLOW_THREADS
if (timeout < 0.0)
nEvents = select(maxFd+1, &inFd, &outFd, &excFd, NULL);
else {
tv.tv_sec = (int)floor(timeout);
tv.tv_usec = ((int)floor(1000000.0 *
(timeout-floor(timeout)))) % 1000000;
nEvents = select(maxFd+1, &inFd, &outFd, &excFd, &tv);
}
Py_END_ALLOW_THREADS
if (nEvents < 0) {
PyErr_SetFromErrno(rpcError);
return false;
}
}
for (i = 0; i < (int)dp->scard; ++i) {
src = dp->srcs[i];
if (src->actImp & ACT_IMMEDIATE)
continue;
if (FD_ISSET(src->fd, &inFd))
src->actOcc |= ACT_INPUT;
if (FD_ISSET(src->fd, &outFd))
src->actOcc |= ACT_OUTPUT;
if (FD_ISSET(src->fd, &excFd))
src->actOcc |= ACT_EXCEPT;
}
return true;
}
/*
* os independent funtion to get current time
*/
static double
get_time(void)
{
#ifdef USE_FTIME
struct _timeb tbuff;
_ftime(&tbuff);
return ((double) tbuff.time + ((double)tbuff.millitm / 1000.0) + \
((double) tbuff.timezone * 60));
#else
struct timeval tv;
struct timezone tz;
if (gettimeofday(&tv, &tz) < 0) {
PyErr_SetFromErrno(rpcError);
return -1;
}
return (tv.tv_sec + tv.tv_usec / 1000000.0);
#endif /* USE_FTIME */
}
/*
* map characterstics of a client object
*/
PyTypeObject rpcDispType = {
PyObject_HEAD_INIT(0)
0,
"rpcDisp",
sizeof(rpcDisp),
0,
(destructor)rpcDispDealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
0, /* tp_xxx4 */
0, /* tp_doc */
};
syntax highlighted by Code2HTML, v. 0.9.1