#ifndef LINT
static char *rcsid="$Id: clnt_udp.c,v 1.13 1999/10/03 21:18:03 crosser Exp $";
#endif

/*
	$Log: clnt_udp.c,v $
	Revision 1.13  1999/10/03 21:18:03  crosser
	First (probably) working version with new run time config parser.
	Also added listenq parameter (backlog size for listen()) and
	renamed wtest to whoson (and with man page).  Release 2.00beta1.
	
	Revision 1.12  1999/08/19 17:22:14  crosser
	Move to new config scheme (does not work yet)
	
	Revision 1.11  1999/07/27 17:30:05  crosser
	fix names
	
	Revision 1.10  1999/01/30 14:45:43  crosser
	def for buffers

	Revision 1.9  1999/01/30 14:41:05  crosser
	fix reporting addresses (used to overwrite static buffer)

	Revision 1.8  1998/07/28 17:51:53  crosser
	make 64bit architecure happy

	Revision 1.7  1998/07/26 14:06:40  crosser
	Add source address checking in UDP client

	Revision 1.6  1998/07/12 16:43:57  crosser
	Change protocol: responce now is terminated with empty line

	Revision 1.5  1998/07/05 00:26:18  crosser
	Change copyright

	Revision 1.4  1998/07/03 11:10:39  crosser
	fix include sys/time.h

	Revision 1.3  1998/07/02 18:01:15  crosser
	change error reporting to syslog

	Revision 1.2  1998/07/02 15:37:07  crosser
	check perms
	fix bug with excessive retries

	Revision 1.1  1998/07/01 21:55:16  crosser
	Initial revision

	Revision 1.2  1998/07/01 05:18:09  crosser
	minor warnings fix

	Revision 1.1  1998/07/01 05:01:22  crosser
	Initial revision

	Revision 1.1  1998/05/05 19:08:16  crosser
	Initial revision

*/

/*
	WHAT IS IT:
		Implementation of experimental "whoson" protocol
	AUTHOR:
		Eugene G. Crosser <crosser@average.org>
	COPYRIGHT:
		Public domain
*/

#include "config.h"

#include <sys/types.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "whoson.h"
#include "rtconfig.h"
#include "checkperm.h"
#include "clnt_common.h"
#include "report.h"

#include "rtc_begin.h"
#include "clnt_udp_cfg.h"
#include "rtc_middle.h"
#include "clnt_udp_cfg.h"
#include "rtc_end.h"

#define MAXREQL 1024

#define INITTIMEOUT 100000
#define MAXTRIES 5
#define MAXREREADS 20

int wso_udp_clnt_connect(void *priv,char *buf)
{
	wso_clnt_udp_cfg *rec=(wso_clnt_udp_cfg *)(priv);
	struct sockaddr_in server,frominet;
	struct protoent *pe;
	int protonum;
	int fd;
	int len,slen;
	fd_set rfds,wfds,efds;
	struct timeval seltimer;
	unsigned long timeout;
	int tries,rereads,rc=0;
	char wbuf[MAXREQL];
	char addr1a[16],addr2a[16];

	memset((char *)&server,0,sizeof(server));
	server.sin_family = AF_INET;
	if ((pe=getprotobyname("udp"))) protonum=pe->p_proto;
	else protonum=17;
	server.sin_port=htons(rec->port);
	server.sin_addr=rec->address;
	if ((fd=socket(AF_INET,SOCK_DGRAM,protonum)) < 0) {
		ERRLOG((LOG_ERR,"[WHOSON] server socket: %m"))
		return -1;
	}

	strncpy(wbuf,buf,sizeof(wbuf)-1);
	wbuf[sizeof(wbuf)-1]='\0';
	timeout=rec->inittimeout;
	for (tries=0;tries<(rec->maxtries);tries++) {
		len=strlen(wbuf);
		if (sendto(fd,wbuf,len,0,(struct sockaddr *)&server,
				sizeof(server)) != len) {
			ERRLOG((LOG_ERR,"[WHOSON] sendto: %m"))
			close(fd);
			return -1;
		}

		rereads=0;
reread:

DPRINT(("udp waiting try=%d(%d max) timeout=%lu (init %u)\n",
			tries,rec->maxtries,timeout,rec->inittimeout))

		seltimer.tv_sec=timeout/1000000L;
		seltimer.tv_usec=timeout%1000000L;
DPRINT(("seltimer.tv_sec=%lu, seltimer.tv_usec=%lu\n",
			(long)seltimer.tv_sec,
			(long)seltimer.tv_usec))
		FD_ZERO(&rfds);
		FD_ZERO(&wfds);
		FD_ZERO(&efds);
		FD_SET(fd,&rfds);

		rc=select(fd+1,&rfds,&wfds,&efds,&seltimer);
		if (rc < 0) {
			ERRLOG((LOG_ERR,"[WHOSON] select: %m"))
			close(fd);
			return -1;
		} else if (rc > 0) {
			slen=sizeof(frominet);
			if ((len=recvfrom(fd,buf,MAXREQL-1,0,
					(struct sockaddr *) &frominet, &slen)) < 0) {
				ERRLOG((LOG_ERR,"[WHOSON] recvfrom: %m"))
				close(fd);
				return -1;
			}
			buf[len]='\0';
			if (rec->perms) {
				if (wso_perm_check(rec->perms,
					ntohl(frominet.sin_addr.s_addr)))
					break;
			} else {
				if (memcmp(&frominet.sin_addr.s_addr,
					&server.sin_addr.s_addr,
					sizeof(frominet.sin_addr.s_addr)) == 0)
					break;
			}
			strcpy(addr1a,inet_ntoa(frominet.sin_addr));
			strcpy(addr2a,inet_ntoa(server.sin_addr));
			ERRLOG((LOG_ERR,"[WHOSON] ignore from %s (dest was %s)",
					addr1a,addr2a))
			if (++rereads < MAXREREADS)
				goto reread;
			else
				sprintf(buf,"*Ignoring from %s, sent to %s\r\n\r\n",
					addr1a,addr2a);
		}

		timeout *= 2;
	}

	if (rc == 0) {
		ERRLOG((LOG_ERR,"[WHOSON] udp excessive retries\n"))
		close(fd);
		return -1;
	}

	close(fd);
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1