/* * Copyright (c) 2000-2004 QoSient, LLC * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * Copyright (c) 1993, 1994 Carnegie Mellon University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation, and that the name of CMU not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL * CMU BE LIABLE FOR ANY SPECIAL, 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. * */ /* ArgusUtil.c */ #ifndef ArgusUtil #define ArgusUtil #endif #include #include #include unsigned long long ArgusAbsTimeDiff (struct timeval *start, struct timeval *stop) { unsigned long long retn = 0; struct timeval *t1 = start, *t2 = stop; int sec, usec; if ((stop->tv_sec < start->tv_sec) || ((stop->tv_sec == start->tv_sec) && (stop->tv_usec < start->tv_usec))) { t2 = start; t1 = stop; } sec = t2->tv_sec - t1->tv_sec; usec = t2->tv_usec - t1->tv_usec; if (usec < 0) { sec--; usec += 1000000; } retn = (unsigned long long) ((sec * 1000000) + usec); return (retn); } struct ArgusListStruct * ArgusNewList () { struct ArgusListStruct *retn = NULL; if ((retn = (struct ArgusListStruct *) ArgusCalloc (1, sizeof (struct ArgusListStruct))) != NULL) { retn->start = NULL; retn->count = 0; } #ifdef ARGUSDEBUG ArgusDebug (4, "ArgusNewList () returning 0x%x\n", retn); #endif return (retn); } void ArgusDeleteList (struct ArgusListStruct *list) { if (list) { while (list->start) ArgusPopFrontList(list); ArgusFree (list); } #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusDeleteList (0x%x) returning\n", list); #endif } int ArgusListEmpty (struct ArgusListStruct *list) { return (list->start == NULL); } int ArgusGetListCount(struct ArgusListStruct *list) { return (list->count); } void ArgusPushFrontList(struct ArgusListStruct *list, void *obj) { struct ArgusListObjectStruct *lobj = NULL; if (list && obj) { if ((lobj = (struct ArgusListObjectStruct *) ArgusCalloc (1, sizeof(*lobj))) != NULL) { lobj->obj = obj; if (list->start) { lobj->nxt = list->start; lobj->prv = list->start->prv; lobj->nxt->prv = lobj; lobj->prv->nxt = lobj; } else { lobj->prv = lobj; lobj->nxt = lobj; } list->start = lobj; list->count++; } } #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusPushFrontList (0x%x, 0x%x) returning 0x%x\n", list, obj); #endif } void ArgusPushBackList(struct ArgusListStruct *list, void *obj) { ArgusPushFrontList(list, obj); list->start = list->start->nxt; #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusPushBackList (0x%x, 0x%x) returning 0x%x\n", list, obj); #endif } void * ArgusFrontList(struct ArgusListStruct *list) { void *retn = NULL; if (list->start) retn = list->start->obj; #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusFrontList (0x%x) returning 0x%x\n", list, retn); #endif return (retn); } void * ArgusBackList(struct ArgusListStruct *list) { void *retn = NULL; if (list->start) retn = list->start->prv->obj; #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusBackList (0x%x) returning 0x%x\n", list, retn); #endif return (retn); } void ArgusPopBackList(struct ArgusListStruct *list) { struct ArgusListObjectStruct *lobj = NULL; if ((lobj = list->start)) { list->start = list->start->prv; ArgusPopFrontList(list); } #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusPopBackList (0x%x) returning\n", list); #endif } void ArgusPopFrontList(struct ArgusListStruct *list) { struct ArgusListObjectStruct *lobj = NULL; if ((lobj = list->start)) { if (--list->count > 0) { if (lobj->prv) lobj->prv->nxt = lobj->nxt; if (lobj->nxt) lobj->nxt->prv = lobj->prv; list->start = lobj->nxt; } else list->start = NULL; ArgusFree(lobj); } #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusPopFrontList (0x%x) returning\n", list); #endif } struct ArgusQueueStruct * ArgusNewQueue () { struct ArgusQueueStruct *retn = NULL; if ((retn = (struct ArgusQueueStruct *) ArgusCalloc (1, sizeof (struct ArgusQueueStruct))) != NULL) { retn->count = 0; retn->start = NULL; } #ifdef ARGUSDEBUG ArgusDebug (4, "ArgusNewQueue () returning 0x%x\n", retn); #endif return (retn); } void ArgusDeleteQueue (struct ArgusQueueStruct *queue) { struct ArgusFlowStruct *obj = NULL; if (queue != NULL) { while ((obj = ArgusPopQueue(queue))) ArgusFree(obj); ArgusFree(queue); } #ifdef ARGUSDEBUG ArgusDebug (4, "ArgusDeleteQueue (0x%x) returning\n", queue); #endif } int ArgusGetQueueCount(struct ArgusQueueStruct *queue) { int retn = 0; if (queue != NULL) retn = queue->count; #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusGetQueueCount (0x%x) returning %d\n", queue, retn); #endif return (retn); } void ArgusPushQueue(struct ArgusQueueStruct *queue, struct ArgusFlowStruct *obj) { int retn = 0; if ((retn = ArgusAddToQueue (queue, obj)) > 0) queue->start = queue->start->prv; #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusPushQueue (0x%x, 0x%x) returning\n", queue, obj); #endif } int ArgusAddToQueue(struct ArgusQueueStruct *queue, struct ArgusFlowStruct *obj) { int retn = 0; if (queue && obj) { if (obj->qhdr.queue == NULL) { if (queue->start != NULL) { obj->qhdr.prv = queue->start->prv; queue->start->prv = &obj->qhdr; obj->qhdr.nxt = queue->start; obj->qhdr.prv->nxt = &obj->qhdr; } else { queue->start = &obj->qhdr; obj->qhdr.nxt = &obj->qhdr; obj->qhdr.prv = &obj->qhdr; } queue->count++; obj->qhdr.queue = queue; retn = 1; } else ArgusLog (LOG_ERR, "ArgusAddToQueue (0x%x, 0x%x) obj in queue 0x%x\n", queue, obj, obj->qhdr.queue); } else ArgusLog (LOG_ERR, "ArgusAddToQueue (0x%x, 0x%x) parameter error\n", queue, obj); #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusAddToQueue (0x%x, 0x%x) returning %d\n", queue, obj, retn); #endif return (retn); } struct ArgusFlowStruct *ArgusFrontQueue (struct ArgusQueueStruct *); struct ArgusFlowStruct * ArgusFrontQueue (struct ArgusQueueStruct *queue) { struct ArgusFlowStruct *retn = NULL; if (queue != NULL) retn = (struct ArgusFlowStruct *) queue->start; #ifdef ARGUSDEBUG ArgusDebug (8, "ArgusFrontQueue (0x%x) returning 0x%x\n", queue, retn); #endif return (retn); } struct ArgusFlowStruct * ArgusPopQueue (struct ArgusQueueStruct *queue) { struct ArgusFlowStruct *retn = NULL; struct ArgusFlowStruct *obj = NULL; if (queue && queue->count) { if ((obj = (struct ArgusFlowStruct *) queue->start) != NULL) retn = ArgusRemoveFromQueue(queue, obj); else ArgusLog (LOG_ERR, "ArgusPopQueue(0x%x) internal queue error count %d start NULL\n", queue, queue->count); } #ifdef ARGUSDEBUG ArgusDebug (8, "ArgusPopQueue (0x%x) returning 0x%x\n", queue, retn); #endif return(retn); } struct ArgusFlowStruct * ArgusRemoveFromQueue(struct ArgusQueueStruct *queue, struct ArgusFlowStruct *obj) { struct ArgusFlowStruct *retn = NULL; if ((queue != NULL) && (obj != NULL)) { if (queue->count && (obj->qhdr.queue == queue)) { queue->count--; if (queue->count) { if (queue->start == &obj->qhdr) queue->start = obj->qhdr.nxt; obj->qhdr.prv->nxt = obj->qhdr.nxt; obj->qhdr.nxt->prv = obj->qhdr.prv; } else queue->start = NULL; obj->qhdr.prv = NULL; obj->qhdr.nxt = NULL; obj->qhdr.queue = NULL; retn = obj; } else ArgusLog (LOG_ERR, "RaRemoveFromQueue(0x%x, 0x%x) obj not in queue\n", queue, obj); } else ArgusLog (LOG_ERR, "RaRemoveFromQueue(0x%x, 0x%x) parameter error\n", queue, obj); #ifdef ARGUSDEBUG ArgusDebug (9, "ArgusRemoveFromQueue (0x%x, 0x%x) returning 0x%x\n", queue, obj, obj); #endif return (retn); } #include #include #define ARGUS_MINQSCAN 256 #define ARGUS_TR1QSCAN 2048 #define ARGUS_TR2QSCAN 16384 #define ARGUS_MAXQSCAN 262144 void ArgusProcessQueue(struct ArgusQueueStruct *queue, unsigned char status) { struct ArgusFlowStruct *obj = NULL; int cnt = 0; switch (status) { case ARGUS_STOP: case ARGUS_SHUTDOWN: while (queue->count) { if ((obj = ArgusPopQueue(queue)) != NULL) { if (obj->FragDSRBuffer != NULL) { if (ArgusUpdateParentFlow(obj)) { ArgusDeleteObject (obj); obj = NULL; } } if (obj) { if ((obj->state.ofragcnt) && (!(obj->qhdr.status & ARGUS_PROCESS_NEXT_PASS))) { obj->qhdr.status |= ARGUS_PROCESS_NEXT_PASS; ArgusAddToQueue(queue, obj); } else { ArgusSendFlowRecord(obj, status); ArgusDeleteObject (obj); } } } } break; default: if (queue->count > 0) { cnt = ((queue->count == 1 ) ? queue->count : ((queue->count < ARGUS_MINQSCAN) ? ((queue->count / 4) + 2): ((queue->count < ARGUS_TR2QSCAN) ? (queue->count / 8) : ((queue->count < ARGUS_MAXQSCAN) ? ARGUS_TR1QSCAN : queue->count / 128)))); if (cnt > 1) { while (cnt--) { if ((obj = ArgusPopQueue(queue)) != NULL) { if (ArgusCheckTimeout(obj)) ArgusTimeOut(obj); else ArgusAddToQueue(queue, obj); } } } else { if ((obj = ArgusFrontQueue(queue)) != NULL) { if (ArgusCheckTimeout(obj)) { ArgusPopQueue(queue); ArgusTimeOut(obj); } } } } break; } #ifdef ARGUSDEBUG ArgusDebug (8, "ArgusProcessQueue (0x%x, %d) returning\n", queue, status); #endif } int ArgusCheckTimeout(struct ArgusFlowStruct *obj) { int retn = 0; unsigned int lapseTime; struct timeval *tvp = NULL, thisTimeout; if (obj->qhdr.lasttime.tv_sec > 0) { lapseTime = obj->qhdr.lasttime.tv_sec + obj->ArgusTimeout; if (((ArgusGlobalTime.tv_sec > lapseTime) || ((ArgusGlobalTime.tv_sec == lapseTime) && (ArgusGlobalTime.tv_usec > obj->qhdr.lasttime.tv_usec))) && (!(obj->state.ofragcnt))) retn++; if ((tvp = getArgusFarReportInterval ()) != NULL) { thisTimeout.tv_sec = tvp->tv_sec + obj->qhdr.logtime.tv_sec; thisTimeout.tv_usec = tvp->tv_usec + obj->qhdr.logtime.tv_usec; if (thisTimeout.tv_usec >= 1000000) { thisTimeout.tv_sec++; thisTimeout.tv_usec -= 1000000; } if ((ArgusGlobalTime.tv_sec > thisTimeout.tv_sec) || ((ArgusGlobalTime.tv_sec == thisTimeout.tv_sec) && (ArgusGlobalTime.tv_usec > thisTimeout.tv_usec))) ArgusSendFlowRecord (obj, ARGUS_STATUS); } } else obj->qhdr.lasttime = ArgusGlobalTime; #ifdef ARGUSDEBUG ArgusDebug (7, "ArgusCheckTimeout (0x%x) returning %d\n", obj, retn); #endif return (retn); } void ArgusEmptyQueue(struct ArgusQueueStruct *queue) { struct ArgusFlowStruct *obj = NULL; while ((obj = ArgusPopQueue(queue)) != NULL) ArgusTimeOut(obj); #ifdef ARGUSDEBUG ArgusDebug (8, "ArgusEmptyQueue (0x%x) returning\n", queue); #endif } void ArgusDeleteObject(struct ArgusFlowStruct *obj) { struct ArgusHashTableHeader *htblhdr; struct ArgusFragExtensionBuffer *fragBuf; struct ArgusFragOffsetStruct *offsets, *nxt; struct ArgusUserObject *user; if (obj->qhdr.queue == ArgusFlowQueue) ArgusRemoveFromQueue (ArgusFlowQueue, obj); if ((htblhdr = obj->htblhdr) != NULL) { ArgusRemoveHashEntry(htblhdr); obj->htblhdr = NULL; } if (obj->MacDSRBuffer) { ArgusFree(obj->MacDSRBuffer); obj->MacDSRBuffer = NULL; } if (obj->VlanDSRBuffer) { ArgusFree(obj->VlanDSRBuffer); obj->VlanDSRBuffer = NULL; } if (obj->MplsDSRBuffer) { ArgusFree(obj->MplsDSRBuffer); obj->MplsDSRBuffer = NULL; } if (obj->NetworkDSRBuffer) { ArgusFree(obj->NetworkDSRBuffer); obj->NetworkDSRBuffer = NULL; } if (obj->ICMPDSRBuffer) { ArgusFree(obj->ICMPDSRBuffer); obj->ICMPDSRBuffer = NULL; } if (obj->FragDSRBuffer) { fragBuf = (struct ArgusFragExtensionBuffer *)obj->FragDSRBuffer; if (fragBuf->user != NULL) { if (fragBuf->user->array != NULL) { ArgusFree(fragBuf->user->array); fragBuf->user->array = NULL; } ArgusFree(fragBuf->user); fragBuf->user = NULL; } if ((offsets = fragBuf->offsets) != NULL) { while (offsets != NULL) { nxt = offsets->nxt; ArgusFree(offsets); offsets = nxt; } fragBuf->offsets = NULL; } ArgusFree(obj->FragDSRBuffer); obj->FragDSRBuffer = NULL; } if (obj->TransportDSRBuffer) { ArgusFree(obj->TransportDSRBuffer); obj->TransportDSRBuffer = NULL; } if (obj->SessionDSRBuffer) { ArgusFree(obj->SessionDSRBuffer); obj->SessionDSRBuffer = NULL; } if (obj->UserDSRBuffer) { user = obj->UserDSRBuffer; if (user->src.array) { ArgusFree(user->src.array); user->src.array = NULL; } if (user->dst.array) { ArgusFree(user->dst.array); user->dst.array = NULL; } ArgusFree(user); obj->UserDSRBuffer = NULL; } ArgusTotalClosedFlows++; ArgusFree(obj); #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusDeleteObject (0x%x) returning\n", obj); #endif } int ArgusUpdateTime () { int retn = 0; if ((ArgusUpdateTimer.tv_sec == 0) || ((ArgusGlobalTime.tv_sec > ArgusUpdateTimer.tv_sec) || ((ArgusGlobalTime.tv_sec == ArgusUpdateTimer.tv_sec) && (ArgusGlobalTime.tv_usec > ArgusUpdateTimer.tv_usec)))) { if (ArgusUpdateTimer.tv_sec) retn = 1; ArgusUpdateTimer = ArgusGlobalTime; ArgusUpdateTimer.tv_sec += ArgusUpdateInterval.tv_sec; ArgusUpdateTimer.tv_usec += ArgusUpdateInterval.tv_usec; if (ArgusUpdateTimer.tv_usec >= 1000000) { ArgusUpdateTimer.tv_sec++; ArgusUpdateTimer.tv_usec -= 1000000; } } #ifdef ARGUSDEBUG ArgusDebug (8, "ArgusUpdateTime () returning %d\n", retn); #endif return (retn); } struct ArgusFlowStruct * ArgusFindFlow () { struct ArgusFlowStruct *retn = NULL; struct ArgusHashTableHeader *hashEntry; unsigned short hash = 0, *ptr = (unsigned short *) ArgusThisFlow; int i, len; for (i = 0, len = (sizeof(*ArgusThisFlow)) / sizeof(unsigned short); i < len; i++) hash += *ptr++; ArgusThisHash = hash; if ((hashEntry = ArgusFindHashObject ()) != NULL) retn = hashEntry->flowobj; #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusFindFlow () returning 0x%x\n", retn); #endif return (retn); } struct ArgusHashTableHeader * ArgusFindHashObject () { struct ArgusHashTableHeader *retn = NULL, *head = NULL, *target; if ((target = ArgusHashTable.array[ArgusThisHash % ArgusHashTable.size]) != NULL) { head = target; do { if (!(bcmp ((char *) ArgusThisFlow, (char *) &target->flow, sizeof(*ArgusThisFlow)))) { retn = target; break; } else target = target->nxt; } while (target != head); } #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusFindHashEntry () returning 0x%x\n", retn); #endif return (retn); } struct ArgusHashTableHeader * ArgusAddHashEntry (struct ArgusFlowStruct *flow) { struct ArgusHashTableHeader *retn = NULL, *start = NULL; if ((retn = (struct ArgusHashTableHeader *) ArgusCalloc (1, sizeof (struct ArgusHashTableHeader))) != NULL) { bcopy((char *) ArgusThisFlow, (char *)&retn->flow, sizeof (*ArgusThisFlow)); retn->flowobj = flow; retn->hash = ArgusThisHash; if ((start = ArgusHashTable.array[ArgusThisHash % ArgusHashTable.size]) != NULL) { retn->nxt = start; retn->prv = start->prv; retn->prv->nxt = retn; retn->nxt->prv = retn; } else retn->prv = retn->nxt = retn; ArgusHashTable.array[ArgusThisHash % ArgusHashTable.size] = retn; } #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusAddHashEntry (0x%x) returning 0x%x\n", flow, retn); #endif return (retn); } void ArgusRemoveHashEntry (struct ArgusHashTableHeader *htblhdr) { unsigned short hash = htblhdr->hash; htblhdr->prv->nxt = htblhdr->nxt; htblhdr->nxt->prv = htblhdr->prv; if (htblhdr == ArgusHashTable.array[hash % ArgusHashTable.size]) { if (htblhdr == htblhdr->nxt) ArgusHashTable.array[hash % ArgusHashTable.size] = NULL; else ArgusHashTable.array[hash % ArgusHashTable.size] = htblhdr->nxt; } ArgusFree (htblhdr); #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusRemoveHashEntry (0x%x) returning\n", htblhdr); #endif } struct ArgusSocketStruct * ArgusNewSocket (int fd) { struct ArgusSocketStruct *retn = NULL; if ((retn = ((struct ArgusSocketStruct *) ArgusCalloc (1, sizeof (struct ArgusSocketStruct)))) != NULL) { if ((retn->ArgusOutputList = ArgusNewList()) != NULL) { retn->fd = fd; fcntl (fd, F_SETFL, O_NONBLOCK); } else { ArgusFree(retn); retn = NULL; } } #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusNewSocket (%d) returning 0x%x\n", fd, retn); #endif return (retn); } void ArgusDeleteSocket (struct ArgusSocketStruct *asock) { while (asock->ArgusOutputList->count) if (ArgusWriteOutSocket(asock) < 0) break; ArgusDeleteList(asock->ArgusOutputList); close(asock->fd); if (asock->filename) free(asock->filename); ArgusFree (asock); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusDeleteSocket (0x%x) returning\n", asock); #endif } #include #include #define ARGUS_MAXERROR 20000 #define ARGUS_MAXWRITENUM 2048 int ArgusMaxListLength = 262144; int ArgusReadSocket (struct ArgusSocketStruct *asock, ArgusHandler ArgusThisHandler, void *data) { int retn = 0, totalbyte = 0; int len = 0; if (asock->cnt == 0) { asock->ptr = asock->buf; asock->ahdr = (struct ArgusRecordHeader *) asock->ptr; } if (asock && (asock->fd >= 0)) { if ((retn = read (asock->fd, (asock->ptr + asock->cnt), (ARGUS_MAXRECORD - asock->cnt))) > 0) { #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusReadSocket(%d, 0x%x, %d) read %d bytes\n", asock->fd, (asock->ptr + asock->cnt), (ARGUS_MAXRECORD - asock->cnt), retn); #endif asock->cnt += retn; totalbyte += retn; } while (asock->cnt > sizeof(struct ArgusRecordHeader)) { len = ntohs(asock->ahdr->length); if (asock->cnt >= len) { ArgusThisHandler (asock, (unsigned char *) asock->ahdr, len, data); bzero (asock->ptr, len); asock->ptr += len; asock->cnt -= len; asock->ahdr = (struct ArgusRecordHeader *)asock->ptr; } else break; } if (asock->cnt && ((unsigned char *)asock->ahdr != asock->buf)) { unsigned char tmpbuf[ARGUS_MAXRECORD]; bcopy (asock->ptr, tmpbuf, asock->cnt); bzero (asock->ptr, asock->cnt); asock->ptr = asock->buf; bcopy (tmpbuf, asock->ptr, asock->cnt); asock->ahdr = (struct ArgusRecordHeader *) asock->ptr; } if ((retn < 0) && ((errno != EAGAIN) || (errno != EINTR))) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusReadSocket() read error %s\n", strerror(errno)); #endif } else retn = totalbyte; } #ifdef ARGUSDEBUG ArgusDebug (5, "ArgusReadSocket(0x%x, 0x%x) returning %d\n", asock, ArgusThisHandler, retn); #endif return (retn); } int ArgusWriteSocket (struct ArgusSocketStruct *asock, unsigned char *buf, int cnt) { struct ArgusListStruct *list = asock->ArgusOutputList; struct ArgusRecordStruct *rec; struct stat statbuf; int retn = -1; if (asock->fd != -1) { if (ArgusListEmpty (list)) { if (asock->filename) { if ((stat (asock->filename, &statbuf)) < 0) { close(asock->fd); if ((asock->fd = open (asock->filename, O_WRONLY|O_APPEND|O_CREAT|O_NONBLOCK, 0644)) >= 0) { ArgusGenerateInitialMar(); ArgusSendOutputData(asock->fd, ArgusSystemMar); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusWriteSocket: created outfile %s\n", asock->filename); #endif } else return (retn); } } if (((retn = write (asock->fd, buf, cnt)) < cnt)) { if (retn < 0) { if ((errno == EAGAIN) || (errno == EINTR) || ((errno == EPIPE) && !(asock->status & ARGUS_WAS_FUNCTIONAL))) retn = 0; else { ArgusLog (LOG_WARNING, "ArgusWriteSocket(0x%x, 0x%x, %d) error %s\n", asock, buf, cnt, strerror(errno)); return (retn); } } } else asock->status |= ARGUS_WAS_FUNCTIONAL; if (retn != cnt) { #ifdef ARGUSDEBUG struct ArgusRecordHeader *ahdr = (struct ArgusRecordHeader *) buf; ArgusDebug (5, "ArgusWriteSocket(0x%x, 0x%x, %d) queuing record %d\n", asock, buf, cnt, ntohl(ahdr->seqNumber)); #endif if ((rec = (struct ArgusRecordStruct *) ArgusCalloc (1, sizeof (*rec))) != NULL) { if ((rec->buf = ArgusCalloc (1, cnt)) != NULL) { bcopy((char *) buf, (char *) rec->buf, cnt); if ((rec->written = retn) < 0) rec->written = 0; rec->length = cnt; ArgusPushBackList (list, rec); } else ArgusLog (LOG_ERR, "ArgusWriteSocket(0x%x, 0x%x, %d) ArgusCalloc returned error %s\n", asock, buf, cnt, strerror(errno)); } else ArgusLog (LOG_ERR, "ArgusWriteSocket(0x%x, 0x%x, %d) ArgusCalloc returned error %s\n", asock, buf, cnt, strerror(errno)); } else { #ifdef ARGUSDEBUG struct ArgusRecordHeader *ahdr = (struct ArgusRecordHeader *) buf; ArgusDebug (5, "ArgusWriteSocket(0x%x, 0x%x, %d) wrote record %d\n", asock, buf, cnt, ntohl(ahdr->seqNumber)); #endif } } else { if (list->count >= ArgusMaxListLength) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusWriteSocket(0x%x, 0x%x, %d) queue full\n", asock, buf, cnt); #endif if (ArgusWriteOutSocket(asock) < 0) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusWriteSocket: ArgusWriteOutSocket(0x%x, 0x%x, %d) tossing records\n", asock, buf, cnt); #endif #define ARGUS_DROPRECORDNUM 4096 if (list->count >= ArgusMaxListLength) { struct ArgusRecordStruct *rec; int i; for (i = 0; i < ARGUS_DROPRECORDNUM; i++) { if ((rec = ArgusBackList(list)) != NULL) { ArgusPopBackList(list); if (rec->buf) { ArgusFree(rec->buf); rec->buf = NULL; } ArgusFree(rec); } } } } } if ((rec = (struct ArgusRecordStruct *) ArgusCalloc (1, sizeof (*rec))) != NULL) { if ((rec->buf = ArgusCalloc (1, cnt)) != NULL) { #ifdef ARGUSDEBUG struct ArgusRecordHeader *ahdr = (struct ArgusRecordHeader *) buf; ArgusDebug (5, "ArgusWriteSocket(0x%x, 0x%x, %d) queue record %d\n", asock, buf, cnt, ntohl(ahdr->seqNumber)); #endif retn = 0; bcopy((char *) buf, (char *) rec->buf, cnt); rec->written = 0; rec->length = cnt; ArgusPushBackList (list, rec); } else ArgusLog (LOG_ERR, "ArgusWriteSocket(0x%x, 0x%x, %d) ArgusCalloc returned error %s\n", asock, buf, cnt, strerror(errno)); } else ArgusLog (LOG_ERR, "ArgusWriteSocket(0x%x, 0x%x, %d) ArgusCalloc returned error %s\n", asock, buf, cnt, strerror(errno)); } } else { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusWriteSocket (0x%x, 0x%x, %d) fd == %d\n", asock, buf, cnt, asock->fd); #endif } #ifdef ARGUSDEBUG ArgusDebug (5, "ArgusWriteSocket (0x%x, 0x%x, %d) returning %d\n", asock, buf, cnt, retn); #endif return (retn); } #define ARGUS_LISTREPORTLEN 50000 #define ARGUS_LISTREPORTTIME 30 int ArgusWriteOutSocket (struct ArgusSocketStruct *asock) { struct ArgusListStruct *list = NULL; struct ArgusRecordStruct *rec; int retn = 0, count = ARGUS_MAXWRITENUM, totalbytes = 0, len; struct stat statbuf; unsigned char *ptr; if (asock && ((list = asock->ArgusOutputList) != NULL)) { if ((count = ArgusGetListCount(list)) > 0) { if (count > ARGUS_LISTREPORTLEN) { unsigned int reportime = list->reportTime.tv_sec + ARGUS_LISTREPORTTIME; if ((list->reportTime.tv_sec == 0) || ((reportime < ArgusGlobalTime.tv_sec) || ((reportime == ArgusGlobalTime.tv_sec) && ((list->reportTime.tv_usec) < ArgusGlobalTime.tv_usec)))) { list->reportTime = ArgusGlobalTime; ArgusLog (LOG_WARNING, "ArgusWriteOutSocket(0x%x) Queue Count %d\n", asock, count); } } if (count > ARGUS_MAXWRITENUM) count = ARGUS_MAXWRITENUM; while ((asock->fd != -1 ) && count--) { if ((rec = ArgusFrontList (list)) != NULL) { if ((ptr = (unsigned char *) rec->buf) != NULL) { if (!(rec->written)) { if (asock->filename) { if ((stat (asock->filename, &statbuf)) < 0) { close(asock->fd); if ((asock->fd = open (asock->filename, O_WRONLY|O_APPEND|O_CREAT|O_NONBLOCK, 0644)) >= 0) { ArgusGenerateInitialMar(); ArgusSendOutputData(asock->fd, ArgusSystemMar); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusWriteSocket: created outfile %s\n", asock->filename); #endif } else ArgusLog (LOG_ERR, "ArgusWriteOutSocket(0x%x) failed to create file %s\n", asock, strerror(errno)); } } } len = rec->length - rec->written; if ((rec->written < rec->length) && ( rec->written >= 0)) { if ((retn = write(asock->fd, (unsigned char *)&ptr[rec->written], len)) >= 0) { asock->errornum = 0; totalbytes += retn; rec->written += retn; } else { if ((retn < 0) && !((errno == EAGAIN) || (errno == EINTR))) { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusWriteOutSocket: write() failed\n", strerror(errno)); #endif } else { if (asock->errornum++ < ARGUS_MAXERROR) { if (asock->errornum > (ARGUS_MAXERROR >> 1)) usleep(2000); retn = 0; } } break; } } else if (rec->written < 0) rec->written = 0; if (rec->written >= rec->length) { #ifdef ARGUSDEBUG struct ArgusRecordHeader *ahdr = (struct ArgusRecordHeader *)rec->buf; if (ahdr) ArgusDebug (7, "ArgusWriteOutSocket: write (%d, 0x%x, %d) record %d complete\n", asock->fd, rec->buf, rec->length, ntohl(ahdr->seqNumber)); #endif list->outputTime = ArgusGlobalTime; ArgusPopFrontList (list); ArgusFree (rec->buf); ArgusFree (rec); rec = NULL; } } else { ArgusPopFrontList (list); ArgusFree (rec); rec = NULL; } } else { #ifdef ARGUSDEBUG ArgusDebug (7, "ArgusWriteOutSocket(0x%x): queue empty\n", asock); #endif break; } if (asock->errornum >= ARGUS_MAXERROR) { ArgusLog (LOG_WARNING, "ArgusWriteOutSocket(0x%x) Exceeded Maximum Errors\n", asock); retn = -1; break; } } if ((count = ArgusGetListCount(list)) > ArgusMaxListLength) { ArgusLog (LOG_WARNING, "ArgusWriteOutSocket(0x%x) Queue Exceeded Maximum Limit\n", asock); retn = -1; } } else { #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusWriteOutSocket(0x%x): queue empty\n"); #endif } } else { #ifdef ARGUSDEBUG ArgusDebug (3, "ArgusWriteOutSocket(0x%x): asock or asock->ArgusOutputList NULL\n"); #endif retn = -1; } #ifdef ARGUSDEBUG if (list) ArgusDebug (5, "ArgusWriteOutSocket (0x%x) %d records waiting. returning %d\n", asock, list->count, retn); else ArgusDebug (5, "ArgusWriteOutSocket (0x%x) no list. returning %d\n", asock, list->count, retn); #endif return retn; }