/****************************************************************************
* Copyright (C) 1998 WIDE Project. All rights reserved.
* Copyright (C) 1999,2000,2001,2002 University of Tromso. All rights reserved.
* Copyright (C) 2002 Invenia Innovation AS. All rights reserved.
*
* Author: Feike W. Dillema, feico@pasta.cs.uit.no.
* based on newbie code by Yusuke DOI, Keio Univ. Murai Lab.
****************************************************************************/
/*
* <$Id: ev_udp_in.c,v 3.38 2002/03/06 14:56:02 dillema Exp $>
*/
#include "totd.h"
static G_List *UDPL_head; /* UDP head */
static G_List *UDPL_tail; /* tail */
int ev_udp_in_eq (void *arg1, void *arg2) {
Ev_UDP_In_Data *e1;
Ev_UDP_In_Data *e2;
int len1, len2;
e1 = (Ev_UDP_In_Data *) arg1;
e2 = (Ev_UDP_In_Data *) arg2;
if (!e1 || !e2 || !e1->sa_p || !e2->sa_p)
return -1;
len1 = SOCKADDR_SIZEOF (*(e1->sa_p));
len2 = SOCKADDR_SIZEOF (*(e2->sa_p));
if (e1->id == e2->id && len1 == len2 &&
!memcmp (e1->sa_p, e2->sa_p, len1))
return 0; /* equality */
else
return 1;
}
void ev_udp_in_data_free (Ev_UDP_In_Data *euid_p) {
if (euid_p) {
if (euid_p->sa_p)
free (euid_p->sa_p);
free (euid_p);
}
return;
}
void ev_udp_in_data_free_v (void *euid_vp) {
ev_udp_in_data_free ((Ev_UDP_In_Data *) euid_vp);
return;
}
int ev_udp_in_init (void) {
if (UDPL_head)
return -1;
UDPL_head = list_init ();
if (!UDPL_head)
return -1;
UDPL_tail = UDPL_head;
UDPL_head->list_data = NULL;
return 0;
}
void ev_udp_in_finish (void) {
net_delete_socketlist ();
list_destroy (UDPL_head, ev_udp_in_data_free_v);
}
int ev_udp_in_register (Context *cptr, struct sockaddr *sa_p, int sa_len,
uint16_t id) {
const char *fn = "ev_udp_in_register()";
Ev_UDP_In_Data *euid_new = NULL;
if (T.debug > 3)
syslog (LOG_DEBUG, "%s: id=%d", fn, id);
euid_new = malloc (sizeof (Ev_UDP_In_Data));
if (!euid_new)
return -1;
euid_new->sa_p = malloc (sa_len);
if (!euid_new->sa_p) {
free (euid_new);
return -1;
}
memcpy (euid_new->sa_p, sa_p, sa_len);
euid_new->cptr = cptr;
euid_new->id = id;
if (!list_add (UDPL_head, euid_new)) {
if (T.debug > 3)
syslog (LOG_DEBUG, "%s: %p", fn, euid_new);
/* SUCCESS */
return 0;
} else {
ev_udp_in_data_free (euid_new);
return -1;
}
}
int ev_udp_in_remove (struct sockaddr *sa_p, int id) {
Ev_UDP_In_Data euid_tmp;
Ev_UDP_In_Data *euid_p;
G_List *gl_tmp;
euid_tmp.sa_p = sa_p;
euid_tmp.id = id;
gl_tmp = list_search (UDPL_head, (void *) &euid_tmp, ev_udp_in_eq);
if (!gl_tmp)
return -1;
euid_p = (Ev_UDP_In_Data *) list_delete (gl_tmp);
ev_udp_in_data_free (euid_p);
return 0;
}
/*
* Receive a UDP message; either a request or response.
* ==> a request message starts a new UDP transaction with root context.
* ==> a response message overwrites a request message in the
* existing context of the matching transaction whose `process'
* routine is called.
*/
int ev_udp_in_read (int sock) {
const char *fn = "ev_udp_in_read()";
struct sockaddr_storage sa;
u_char *newbuf;
Mesg_Hdr *mesg;
int mesg_len;
unsigned int sa_len;
G_List *gl_tmp;
Ev_UDP_In_Data euid;
Nia *ni_l;
/* allocate buffer */
newbuf = malloc (MAX_PACKET);
if (!newbuf)
return (-1);
mesg = (Mesg_Hdr *) newbuf;
/* read packet */
sa_len = sizeof(sa);
memset ((void *) &sa, 0, sa_len);
mesg_len = recvfrom (sock, newbuf, MAX_PACKET, 0,
(struct sockaddr *) &sa, &sa_len);
if (mesg_len < 0) {
syslog (LOG_ERR, "recvfrom: %m");
if (newbuf)
free (newbuf);
return (-1);
}
if (T.debug > 3)
syslog (LOG_DEBUG, "%s: read from sockid %d, len %d.", fn,
sock, mesg_len);
if (mesg_len < sizeof (Mesg_Hdr)) {
syslog(LOG_NOTICE, "ignoring too short message");
if (newbuf)
free (newbuf);
return (-1);
}
/*
* Check for duplicate message id. If we already have a transaction
* going with the same id, we have to ignore it to avoid confusion.
* Note that this may be just a retransmission of a client, i.e.
* nothing to worry about.
*/
if (ev_dup ((struct sockaddr *) &sa, sa_len, mesg->id) < 0) {
/* duplicate */
if (T.debug > 3)
syslog (LOG_DEBUG, "%s: duplicate request ignored", fn);
if (newbuf)
free (newbuf);
return (0);
}
/* identify and match */
euid.id = mesg->id;
euid.sa_p = (struct sockaddr *) &sa;
gl_tmp = list_search (UDPL_head, (void *) &euid, ev_udp_in_eq);
if (!gl_tmp) {
if (mesg->qr == 1) {
if (T.debug > 3)
syslog (LOG_DEBUG, "%s: unknown UDP response \
ignored", fn);
if (newbuf)
free (newbuf);
return (0);
}
/* new request, start new transaction */
if (T.debug > 3)
syslog (LOG_DEBUG, "%s: Create new transaction", fn);
ni_l = nia_find_by_sock (sock);
if (!ni_l) {
syslog (LOG_ERR, "no socket for interface");
if (newbuf)
free (newbuf);
return (-1);
}
return udp_response_start (newbuf, mesg_len,
(struct sockaddr *) &sa, ni_l);
} else {
Context *cont;
if (T.debug > 3)
syslog (LOG_DEBUG, "%s: resume transaction", fn);
cont = ((Ev_UDP_In_Data *) gl_tmp->list_data)->cptr;
/* delete old message buffer (with request message) */
if (cont->mesg.p)
free (cont->mesg.p);
/* ... and replace it with the new response message */
cont->mesg.p = newbuf;
cont->mesg_len = mesg_len;
/*
* `wp'' has no meaning for UDP transactions,
* clear it in case we switch to TCP later
*/
cont->wp = NULL;
/*
* process context; context must release the timeout event
*/
return (cont->process) (cont);
}
/* NOTREACHED */
return -1;
}
syntax highlighted by Code2HTML, v. 0.9.1