113240Sgraichen/*
213240Sgraichen * Copyright (c) 1994 Christos Zoulas
313240Sgraichen * All rights reserved.
413240Sgraichen *
513240Sgraichen * Redistribution and use in source and binary forms, with or without
613240Sgraichen * modification, are permitted provided that the following conditions
713240Sgraichen * are met:
813240Sgraichen * 1. Redistributions of source code must retain the above copyright
913240Sgraichen *    notice, this list of conditions and the following disclaimer.
1013240Sgraichen * 2. Redistributions in binary form must reproduce the above copyright
1113240Sgraichen *    notice, this list of conditions and the following disclaimer in the
1213240Sgraichen *    documentation and/or other materials provided with the distribution.
1313240Sgraichen * 3. All advertising materials mentioning features or use of this software
1413240Sgraichen *    must display the following acknowledgement:
1513240Sgraichen *	This product includes software developed by Christos Zoulas.
1613240Sgraichen * 4. The name of the author may not be used to endorse or promote products
1713240Sgraichen *    derived from this software without specific prior written permission.
1813240Sgraichen *
1913240Sgraichen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2013240Sgraichen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2113240Sgraichen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2213240Sgraichen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2313240Sgraichen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2413240Sgraichen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2513240Sgraichen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2613240Sgraichen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2713240Sgraichen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2813240Sgraichen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2913240Sgraichen */
3013240Sgraichen
3113240Sgraichen#ifndef lint
3231489Scharnierstatic const char rcsid[] =
3350476Speter  "$FreeBSD$";
3413240Sgraichen#endif /* not lint */
3513240Sgraichen
3631489Scharnier#include <rpc/rpc.h>
3731489Scharnier#include <rpcsvc/spray.h>
3831489Scharnier#include <signal.h>
3913240Sgraichen#include <stdio.h>
4013240Sgraichen#include <stdlib.h>
4113240Sgraichen#include <sys/time.h>
4213240Sgraichen#include <sys/socket.h>
4313240Sgraichen#include <syslog.h>
4431489Scharnier#include <unistd.h>
4513240Sgraichen
4690336Simpstatic void spray_service(struct svc_req *, SVCXPRT *);
4713240Sgraichen
4813240Sgraichenstatic int from_inetd = 1;
4913240Sgraichen
5013240Sgraichen#define	timersub(tvp, uvp, vvp)						\
5113240Sgraichen	do {								\
5213240Sgraichen		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
5313240Sgraichen		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
5413240Sgraichen		if ((vvp)->tv_usec < 0) {				\
5513240Sgraichen			(vvp)->tv_sec--;				\
5613240Sgraichen			(vvp)->tv_usec += 1000000;			\
5713240Sgraichen		}							\
5813240Sgraichen	} while (0)
5913240Sgraichen
6013240Sgraichen#define TIMEOUT 120
6113240Sgraichen
6213240Sgraichenvoid
6390336Simpcleanup(int sig __unused)
6413240Sgraichen{
65100120Salfred	(void) rpcb_unset(SPRAYPROG, SPRAYVERS, NULL);
6613240Sgraichen	exit(0);
6713240Sgraichen}
6813240Sgraichen
6913240Sgraichenvoid
7090336Simpdie(int sig __unused)
7113240Sgraichen{
7213240Sgraichen	exit(0);
7313240Sgraichen}
7413240Sgraichen
7513240Sgraichenint
7690336Simpmain(int argc, char *argv[])
7713240Sgraichen{
7813240Sgraichen	SVCXPRT *transp;
79100120Salfred	int ok;
80100120Salfred	struct sockaddr_storage from;
81141918Sstefanf	socklen_t fromlen;
8213240Sgraichen
8313240Sgraichen	/*
8413240Sgraichen	 * See if inetd started us
8513240Sgraichen	 */
8613240Sgraichen	fromlen = sizeof(from);
8713240Sgraichen	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
8813240Sgraichen		from_inetd = 0;
8913240Sgraichen	}
9013240Sgraichen
9113240Sgraichen	if (!from_inetd) {
9213240Sgraichen		daemon(0, 0);
9313240Sgraichen
94100120Salfred		(void) rpcb_unset(SPRAYPROG, SPRAYVERS, NULL);
9513240Sgraichen
9613240Sgraichen		(void) signal(SIGINT, cleanup);
9713240Sgraichen		(void) signal(SIGTERM, cleanup);
9813240Sgraichen		(void) signal(SIGHUP, cleanup);
9913240Sgraichen	} else {
10013240Sgraichen		(void) signal(SIGALRM, die);
10113240Sgraichen		alarm(TIMEOUT);
10213240Sgraichen	}
10313240Sgraichen
10413240Sgraichen	openlog("rpc.sprayd", LOG_CONS|LOG_PID, LOG_DAEMON);
10513240Sgraichen
106100120Salfred	if (from_inetd) {
107100120Salfred		transp = svc_tli_create(0, NULL, NULL, 0, 0);
108100120Salfred		if (transp == NULL) {
109100120Salfred			syslog(LOG_ERR, "cannot create udp service.");
110100120Salfred			exit(1);
111100120Salfred		}
112100120Salfred		ok = svc_reg(transp, SPRAYPROG, SPRAYVERS,
113100120Salfred			     spray_service, NULL);
114100120Salfred	} else
115100120Salfred		ok = svc_create(spray_service,
116100120Salfred				SPRAYPROG, SPRAYVERS, "udp");
117100120Salfred	if (!ok) {
11813240Sgraichen		syslog(LOG_ERR,
11931489Scharnier		    "unable to register (SPRAYPROG, SPRAYVERS, %s)",
120100120Salfred		    (!from_inetd)?"udp":"(inetd)");
12113240Sgraichen		return 1;
12213240Sgraichen	}
12313240Sgraichen
12413240Sgraichen	svc_run();
12513240Sgraichen	syslog(LOG_ERR, "svc_run returned");
12613240Sgraichen	return 1;
12713240Sgraichen}
12813240Sgraichen
12913240Sgraichen
13013240Sgraichenstatic void
13190336Simpspray_service(struct svc_req *rqstp, SVCXPRT *transp)
13213240Sgraichen{
13313240Sgraichen	static spraycumul scum;
13413240Sgraichen	static struct timeval clear, get;
13513240Sgraichen
13613240Sgraichen	switch (rqstp->rq_proc) {
13713240Sgraichen	case SPRAYPROC_CLEAR:
13813240Sgraichen		scum.counter = 0;
13913240Sgraichen		(void) gettimeofday(&clear, 0);
14013240Sgraichen		/*FALLTHROUGH*/
14113240Sgraichen
14213240Sgraichen	case NULLPROC:
14395658Sdes		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
14413240Sgraichen		return;
14513240Sgraichen
14613240Sgraichen	case SPRAYPROC_SPRAY:
14713240Sgraichen		scum.counter++;
14813240Sgraichen		return;
14913240Sgraichen
15013240Sgraichen	case SPRAYPROC_GET:
15113240Sgraichen		(void) gettimeofday(&get, 0);
15213240Sgraichen		timersub(&get, &clear, &get);
15313240Sgraichen		scum.clock.sec = get.tv_sec;
15413240Sgraichen		scum.clock.usec = get.tv_usec;
15513240Sgraichen		break;
15613240Sgraichen
15713240Sgraichen	default:
15813240Sgraichen		svcerr_noproc(transp);
15913240Sgraichen		return;
16013240Sgraichen	}
16113240Sgraichen
16295658Sdes	if (!svc_sendreply(transp, (xdrproc_t)xdr_spraycumul, &scum)) {
16313240Sgraichen		svcerr_systemerr(transp);
16413240Sgraichen		syslog(LOG_ERR, "bad svc_sendreply");
16513240Sgraichen	}
16613240Sgraichen}
167