/*
* packetq - packet queue management. try to send packets several times before discarding.
* Copyright 2005 Renzo Davoli
* Licensed under the GPLv2
*/
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <consmgmt.h>
#include <vde.h>
#ifdef VDE_PQ
#include "packetq.h"
int packetq_timeout= -1;
static int countq;
#define TIMEOUT 5
#define TIMES 10
#define MAXQLEN 4192
struct packetqq {
int (*sender)(int fd, int fd_ctl, void *packet, int len, void *data, int port);
int fd;
int fd_ctl;
void *packet;
int len;
void *data;
int port;
int times;
struct packetqq *next;
};
static struct packetqq *pqh=NULL;
static struct packetqq *pqt=NULL;
static struct timeval last_try;
void packetq_add(int (*sender)(int fd, int fd_ctl, void *packet, int len, void *data, int port),
int fd, int fd_ctl, void *packet, int len, void *data, int port)
{
if (countq < MAXQLEN) {
struct packetqq *new=malloc(sizeof(struct packetqq));
void *packetcopy=malloc(len);
if (new != NULL && packetcopy != NULL && len > 0) {
countq++;
new->sender=sender;
new->fd=fd;
new->fd_ctl=fd_ctl;
memcpy(packetcopy,packet,len);
new->packet=packetcopy;
new->len=len;
new->data=data;
new->port=port;
new->times=TIMES;
new->next=NULL;
if (pqh==NULL) {
gettimeofday(&last_try,NULL);
packetq_timeout=TIMEOUT;
pqh=pqt=new;
} else {
pqt->next=new;
pqt=new;
}
} else {
if (new != NULL) free(new);
if (packetcopy != NULL) free(packetcopy);
}
}
}
static struct packetqq *packetq_scantry(struct packetqq *h,struct packetqq **t,fd_set *fds)
{
if (h != NULL) {
int sendrv=!(FD_ISSET(h->fd,fds));
h->times--;
if ((sendrv && (sendrv=h->sender(h->fd,h->fd_ctl,h->packet,h->len,h->data,h->port)) == 0) /*send OK*/
|| h->times<=0) { /*or max number of attempts reached*/
struct packetqq *next;
#if 0
/* this error code is unreachable! (sendrv==0 here) */
if (sendrv != 0) {
if (sendrv < 0)
printlog(LOG_WARNING,"packetqueue port %d: %s",h->port,strerror(-sendrv));
else
printlog(LOG_WARNING,"packetqueue port %d: partial send (%d bytes lost)",h->port,sendrv);
}
#endif
next=h->next;
countq--;
free(h->packet);
free(h);
return packetq_scantry(next,t,fds);
} else {
FD_SET(h->fd,fds);
h->next=packetq_scantry(h->next,t,fds);
if (h->next == NULL) *t=h;
return h;
}
} else
return NULL;
}
void packetq_try(void)
{
if (pqh != NULL) {
struct timeval this_try;
gettimeofday(&this_try,NULL);
packetq_timeout=TIMEOUT - ((this_try.tv_sec-last_try.tv_sec) * 1000 +
(this_try.tv_usec-last_try.tv_usec) / 1000);
if (packetq_timeout <= 0) {
fd_set fds;
FD_ZERO(&fds);
pqh=packetq_scantry(pqh,&pqt,&fds);
if (pqh != NULL) {
gettimeofday(&last_try,NULL);
packetq_timeout=TIMEOUT;
} else
packetq_timeout = -1;
}
}
}
static struct packetqq *packetq_scandelfd(int fd,struct packetqq *h,struct packetqq **t)
{
if (h != NULL) {
if (fd == h->fd) {
struct packetqq *next=h->next;
countq--;
free(h->packet);
free(h);
return packetq_scandelfd(fd,next,t);
} else {
h->next=packetq_scandelfd(fd,h->next,t);
if (h->next == NULL) *t=h;
return h;
}
} else
return NULL;
}
void packetq_delfd(int fd)
{
pqh=packetq_scandelfd(fd,pqh,&pqt);
if (pqh == NULL)
packetq_timeout = -1;
}
int packetq_count()
{
return countq;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1