#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <string.h>
#include <syslog.h>
#include <sys/param.h>
#include <rpc/rpc.h>
#include <sys/stat.h>
#include <netconfig.h>
#include <netdir.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <rpcsvc/mount.h>
#include <signal.h>
#include <locale.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <thread.h>
#include <assert.h>
#include <limits.h>
#define TESTPROG 987654
uint32_t test_vers_max = 2;
uint32_t test_vers_min = 1;
int debug;
int verbose;
int testd_port;
static void mysvc(struct svc_req *, SVCXPRT *);
static void bind2(void);
static void
test_svc_tp_create(struct netconfig *nconf)
{
char port_str[8];
struct nd_hostserv hs;
struct nd_addrlist *al = NULL;
SVCXPRT *xprt = NULL;
rpcvers_t vers;
vers = test_vers_max;
if (testd_port != 0 &&
(strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
int err;
snprintf(port_str, sizeof (port_str), "%u",
(unsigned short)testd_port);
hs.h_host = HOST_SELF_BIND;
hs.h_serv = port_str;
err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
if (err == 0 && al != NULL) {
xprt = svc_tp_create_addr(mysvc, TESTPROG, vers,
nconf, al->n_addrs);
netdir_free(al, ND_ADDRLIST);
}
if (xprt == NULL) {
printf("testd: unable to create "
"(TESTD,%d) on transport %s (port %d)\n",
(int)vers, nconf->nc_netid, testd_port);
}
}
if (xprt == NULL) {
xprt = svc_tp_create(mysvc, TESTPROG, vers, nconf);
}
if (xprt == NULL) {
printf("testd: unable to create "
"(TESTD,%d) on transport %s\n",
(int)vers, nconf->nc_netid);
return;
}
while (--vers >= test_vers_min) {
if (!svc_reg(xprt, TESTPROG, vers, mysvc, nconf)) {
printf("testd: "
"failed to register vers %d on %s\n",
(int)vers, nconf->nc_netid);
}
}
}
static void
test_svc_unreg(void)
{
rpcvers_t vers;
for (vers = test_vers_min; vers <= test_vers_max; vers++)
svc_unreg(TESTPROG, vers);
}
int
main(int argc, char *argv[])
{
int c;
bool_t exclbind = TRUE;
int tmp;
struct netconfig *nconf;
NCONF_HANDLE *nc;
while ((c = getopt(argc, argv, "dvp:")) != EOF) {
switch (c) {
case 'd':
debug++;
break;
case 'v':
verbose++;
break;
case 'p':
(void) sscanf(optarg, "%d", &tmp);
if (tmp < 1 || tmp > UINT16_MAX) {
(void) fprintf(stderr,
"testd: -P port invalid.\n");
return (1);
}
testd_port = tmp;
break;
default:
fprintf(stderr, "usage: testd [-v] [-r]\n");
exit(1);
}
}
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
}
if (testd_port < 0 || testd_port > UINT16_MAX) {
fprintf(stderr, "unable to use specified port\n");
exit(1);
}
test_svc_unreg();
if ((nc = setnetconfig()) == NULL) {
perror("setnetconfig failed");
return (-1);
}
while ((nconf = getnetconfig(nc)) != NULL) {
if ((nconf->nc_flag & NC_VISIBLE) == 0)
continue;
if (nconf->nc_semantics != NC_TPI_CLTS &&
nconf->nc_semantics != NC_TPI_COTS &&
nconf->nc_semantics != NC_TPI_COTS_ORD)
continue;
test_svc_tp_create(nconf);
}
(void) endnetconfig(nc);
if (testd_port != 0)
bind2();
if (debug) {
char sysbuf[100];
snprintf(sysbuf, sizeof (sysbuf),
"rpcinfo -p |grep %u", TESTPROG);
printf("x %s\n", sysbuf);
fflush(stdout);
system(sysbuf);
if (testd_port) {
snprintf(sysbuf, sizeof (sysbuf),
"netstat -a -f inet -P udp |grep %u", testd_port);
printf("x %s\n", sysbuf);
fflush(stdout);
system(sysbuf);
snprintf(sysbuf, sizeof (sysbuf),
"netstat -a -f inet -P tcp |grep %u", testd_port);
printf("x %s\n", sysbuf);
fflush(stdout);
system(sysbuf);
}
}
test_svc_unreg();
printf("%s complete\n", argv[0]);
return (0);
}
static void
mysvc(struct svc_req *rq, SVCXPRT *xprt)
{
switch (rq->rq_proc) {
case NULLPROC:
errno = 0;
(void) svc_sendreply(xprt, xdr_void, (char *)0);
return;
default:
svcerr_noproc(xprt);
return;
}
}
struct sockaddr_in addr;
static void
bind2(void)
{
int ret;
int sock;
addr.sin_family = AF_INET;
addr.sin_port = htons(testd_port);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
fprintf(stderr, "bind2 socket fail %s\n",
strerror(errno));
exit(1);
}
ret = bind(sock, (struct sockaddr *)&addr, sizeof (addr));
if (ret == -1) {
fprintf(stderr, "bind2 bind fail %s (expected) PASS\n",
strerror(errno));
close(sock);
return;
}
printf("Oh no, bind2 worked! test FAILED\n");
close(sock);
}