1/*
2 * LTsock.c -- Lsof Test IPv4 sockets
3 *
4 * V. Abell
5 * Purdue University
6 */
7
8
9/*
10 * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
11 * 47907.  All rights reserved.
12 *
13 * Written by V. Abell.
14 *
15 * This software is not subject to any license of the American Telephone
16 * and Telegraph Company or the Regents of the University of California.
17 *
18 * Permission is granted to anyone to use this software for any purpose on
19 * any computer system, and to alter it and redistribute it freely, subject
20 * to the following restrictions:
21 *
22 * 1. Neither the authors nor Purdue University are responsible for any
23 *    consequences of the use of this software.
24 *
25 * 2. The origin of this software must not be misrepresented, either by
26 *    explicit claim or by omission.  Credit to the authors and Purdue
27 *    University must appear in documentation and sources.
28 *
29 * 3. Altered versions must be plainly marked as such, and must not be
30 *    misrepresented as being the original software.
31 *
32 * 4. This notice may not be removed or altered.
33 */
34
35#ifndef lint
36static char copyright[] =
37"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n";
38#endif
39
40#include "LsofTest.h"
41#include "lsof_fields.h"
42
43#include <netdb.h>
44#include <signal.h>
45#include <sys/socket.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48
49
50/*
51 * Pre-definitions that make be changed or revoked by dialects
52 */
53
54#define SIGHANDLER_T	void		/* signal handler function type */
55#define	LT_SOCKLEN_T	int		/* socket length type */
56
57
58#if	defined(LT_DIAL_aix)
59/*
60 * AIX-specific items
61 */
62
63#undef	LT_SOCKLEN_T
64#define	LT_SOCKLEN_T	size_t
65#endif	/* defined(LT_DIAL_aix) */
66
67
68#if	defined(LT_DIAL_darwin)
69/*
70 * Darwin-specific items
71 */
72
73# if	LT_VERS>=800
74#undef	LT_SOCKLEN_T
75#define	LT_SOCKLEN_T	socklen_t
76# endif	/* LT_VERS>=800 */
77#endif	/* defined(LT_DIAL_darwin) */
78
79
80#if	defined(LT_DIAL_hpux)
81/*
82 * HP-UX-specific items
83 */
84
85# if	LT_VERS>=1123 && defined(__GNUC__)
86#undef	LT_SOCKLEN_T
87#define	LT_SOCKLEN_T	size_t
88# endif	/* LT_VERS>=1123 && defined(__GNUC__) */
89#endif	/* defined(LT_DIAL_hpux) */
90
91
92#if	defined(LT_DIAL_ou)
93/*
94 * OpenUNIX-specific items
95 */
96
97#undef	LT_SOCKLEN_T
98#define	LT_SOCKLEN_T	size_t
99#endif	/* defined(LT_DIAL_ou) */
100
101
102#if	defined(LT_DIAL_uw)
103/*
104 * UnixWare-specific items
105 */
106
107#undef	LT_SOCKLEN_T
108#define	LT_SOCKLEN_T	size_t
109#endif	/* defined(LT_DIAL_uw) */
110
111
112/*
113 * Local definitions
114 */
115
116#define	ALARMTM		30		/* alarm timer */
117
118#define	LT_CLNT		0		/* child process index */
119#define	LT_SRVR		1		/* parent process index */
120
121#define	LT_FNF		0		/* file not found */
122#define LT_FBYIP	1		/* file found by IP address */
123#define	LT_FBYHN	2		/* file found by host name */
124#define	LT_FBYPORT	4		/* file found by port */
125
126#if	!defined(MAXHOSTNAMELEN)
127#define	MAXHOSTNAMELEN	256		/* maximum host name length */
128#endif	/* !defined(MAXHOSTNAMELEN) */
129
130#if	!defined(MAXPATHLEN)
131#define	MAXPATHLEN	1024		/* maximum path length */
132#endif	/* !defined(MAXPATHLEN) */
133
134
135/*
136 * Local structure definitions.
137 */
138
139
140typedef struct fdpara {		/* file descriptor parameters */
141    int fd;			/* FD */
142    char *fds;			/* FD in ASCII */
143    int ff;			/* file found flags (see LT_F*) */
144    char *host;			/* host name */
145    int hlen;			/* strlen(host) */
146    char *ipaddr;		/* dotted IP address */
147    int ilen;			/* strlen(ipaddr) */
148    pid_t pid;			/* PID of process */
149    char *port;			/* port in ASCII */
150    int plen;			/* strlen(port) */
151    struct sockaddr_in sa;	/* socket's address */
152} fdpara_t;
153
154
155/*
156 * Globals
157 */
158
159pid_t CPid = (pid_t)0;		/* client PID */
160fdpara_t FdPara[2];		/* file descriptor parameters */
161#define	NFDPARA	(sizeof(FdPara) /sizeof(fdpara_t))
162struct sockaddr_in Myad;	/* my (server) socket address */
163pid_t MyPid = (pid_t)0;		/* PID of this process */
164char *Pn = (char *)NULL;	/* program name */
165char *PtNm[] = { "client", "server" };
166				/* program type name */
167int Ssock = -1;			/* server socket */
168
169
170/*
171 * Local function prototypes
172 */
173
174_PROTOTYPE(static void CleanupClnt,(void));
175_PROTOTYPE(static void CleanupSrvr,(void));
176_PROTOTYPE(static SIGHANDLER_T HandleClntAlarm,(int sig));
177_PROTOTYPE(static SIGHANDLER_T HandleSrvrAlarm,(int sig));
178_PROTOTYPE(static char *FindSock,(int fn));
179_PROTOTYPE(static void StartClnt,(struct sockaddr_in *cad));
180
181
182/*
183 * Main program
184 */
185
186int
187main(argc, argv)
188    int argc;				/* argument count */
189    char *argv[];			/* arguments */
190{
191    struct sockaddr_in aa;		/* accept address */
192    struct sockaddr_in ba;		/* bind address */
193    char buf[2048];			/* temporary buffer */
194    int bufl = sizeof(buf);		/* size of buf[] */
195    struct sockaddr_in ca;		/* connect address */
196    char *cem;				/* current error message pointer */
197    char *ep;				/* error message parameter */
198    char hnm[MAXHOSTNAMELEN + 1];	/* this host's name */
199    char *host;				/* host name */
200    struct hostent *hp;			/* this host's hostent structure */
201    char *ipaddr;			/* IP address */
202    char *pem = (char *)NULL;		/* previous error message */
203    char *port;				/* port */
204    LT_SOCKLEN_T sal;			/* socket address length */
205    char *tcp;				/* temporary character size */
206    int ti, tj, tk;			/* temporary indexes */
207    int tsfd;				/* temporary socket FD */
208    int xv = 0;				/* exit value */
209/*
210 * Get program name and PID, issue start message, and build space prefix.
211 */
212    if ((Pn = strrchr(argv[0], '/')))
213	Pn++;
214    else
215	Pn = argv[0];
216    MyPid = getpid();
217    (void) printf("%s ... ", Pn);
218    (void) fflush(stdout);
219    PrtMsg((char *)NULL, Pn);
220/*
221 * Initalize the FdPara[] array before any CleanupClnt() call.
222 */
223    for (ti = 0; ti < NFDPARA; ti++) {
224	(void) memset((void *)&FdPara[ti], 0, sizeof(fdpara_t));
225	FdPara[ti].fd = -1;
226	FdPara[ti].ff = LT_FNF;
227    }
228/*
229 * Process arguments.
230 */
231    if (ScanArg(argc, argv, "h", Pn))
232	xv = 1;
233    if (xv || LTopt_h) {
234	(void) PrtMsg("usage: [-h]", Pn);
235	PrtMsgX("       -h       print help (this panel)", Pn, CleanupSrvr,
236		xv);
237    }
238/*
239 * See if lsof can be executed and can access kernel memory.
240 */
241    if ((cem = IsLsofExec()))
242	(void) PrtMsgX(cem, Pn, CleanupSrvr, 1);
243    if ((cem = CanRdKmem()))
244	(void) PrtMsgX(cem, Pn, CleanupSrvr, 1);
245/*
246 * Get the host name and its IP address.  Convert the IP address to dotted
247 * ASCII form.
248 */
249    if (gethostname(hnm, sizeof(hnm) - 1)) {
250	cem = "ERROR!!!  can't get this host's name";
251	goto print_errno;
252    }
253    hnm[sizeof(hnm) - 1] = '\0';
254    if (!(hp = gethostbyname(hnm))) {
255	(void) snprintf(buf, bufl - 1, "ERROR!!!  can't get IP address for %s",
256	    hnm);
257	buf[bufl - 1] = '\0';
258	cem = buf;
259	goto print_errno;
260    }
261    (void) memset((void *)&Myad, 0, sizeof(Myad));
262    if ((ti = hp->h_length) > sizeof(Myad.sin_addr))
263	ti = sizeof(Myad.sin_addr);
264    (void) memcpy((void *)&Myad.sin_addr, (void *)hp->h_addr, ti);
265    Myad.sin_family = hp->h_addrtype;
266/*
267 * Get INET domain socket FDs.
268 */
269    for (ti = 0; ti < NFDPARA; ti++) {
270	if ((tsfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
271	    ep = "socket";
272
273print_errno_by_ti:
274
275	/*
276	 * Report socket function error.
277	 *
278	 * Entry: ep   = function name
279	 *	  hnm  = this host's name
280	 *	  Myad = this host's IP address
281	 *	  ti   =  FdPara[] index
282	 */
283	    (void) snprintf(buf, bufl - 1, "ERROR!!!  %s %s() failure",
284		PtNm[ti], ep);
285	    buf[bufl - 1] = '\0';
286	    PrtMsg(buf, Pn);
287	    (void) snprintf(buf, bufl - 1, "    host: %s",
288		FdPara[ti].host ? FdPara[ti].host : hnm);
289	    buf[bufl - 1] = '\0';
290	    PrtMsg(buf, Pn);
291	    (void) snprintf(buf, bufl - 1, "    IP: %s",
292		FdPara[ti].ipaddr ? FdPara[ti].ipaddr
293				  : inet_ntoa(Myad.sin_addr));
294	    buf[bufl - 1] = '\0';
295	    cem = buf;
296
297print_errno:
298
299	/*
300	 * Report errno.
301	 *
302	 * Entry: errno = error number
303	 */
304	    PrtMsg(cem, Pn);
305	    (void) snprintf(buf, bufl - 1, "    Errno %d: %s", errno,
306		strerror(errno));
307	    buf[bufl - 1] = '\0';
308	    PrtMsgX(buf, Pn, CleanupSrvr, 1);
309	}
310    /*
311     * Put the FD just acquired in FdPara[ti].fd.
312     *
313     * Set the file-not-found to LT_FNF.
314     *
315     * Save the server socket if this FdPara[] is for it.
316     */
317	FdPara[ti].fd = tsfd;
318	(void) snprintf(buf, bufl - 1, "%d", tsfd);
319	buf[bufl - 1] = '\0';
320	FdPara[ti].fds = MkStrCpy(buf, &tj);
321	if (ti == LT_SRVR)
322	    Ssock = tsfd;
323    }
324/*
325 * Bind the host name to the server socket.
326 *
327 * Get and save the server's socket address.
328 *
329 * Initiate a listen with an address list of one.
330 */
331    (void) memcpy((void *)&ba, (void *)&Myad, sizeof(ba));
332    ti = LT_SRVR;
333    FdPara[ti].pid = MyPid;
334    if (bind(Ssock, (struct sockaddr *)&ba, sizeof(ba)) < 0) {
335	ep = "bind";
336	goto print_errno_by_ti;
337    }
338    sal = (LT_SOCKLEN_T)sizeof(ca);
339    if (getsockname(Ssock, (struct sockaddr *)&ca, &sal)) {
340	ep = "getsockname";
341	goto print_errno_by_ti;
342    }
343    (void) memcpy((void *)&FdPara[ti].sa, (void *)&ca, sizeof(FdPara[ti].sa));
344    if (listen(Ssock, 1) < 0) {
345	ep = "listen";
346	goto print_errno_by_ti;
347    }
348/*
349 * Fork a child process to run as the client.
350 */
351    switch ((CPid = (pid_t)fork())) {
352    case (pid_t)0:
353
354    /*
355     * This is the child.  Start the client.
356     */
357	StartClnt(&ca);
358	(void) PrtMsgX("ERROR!!!  unexpected client return", Pn, CleanupSrvr,
359		       1);
360    case (pid_t)-1:
361
362    /*
363     * This is a fork error.
364     */
365	cem = "ERROR!!! fork() error";
366	goto print_errno;
367    default:
368
369    /*
370     * This is the parent.
371     *
372     * Save the client's PID.
373     *
374     * Close the client's socket.
375     */
376	FdPara[LT_CLNT].pid = CPid;
377	if (FdPara[LT_CLNT].fd >= 0) {
378	    (void) close(FdPara[LT_CLNT].fd);
379	    FdPara[LT_CLNT].fd = -1;
380	}
381    }
382/*
383 * Set a SIGALRM, then accept() the connection from the client.
384 *
385 * Save the client's socket address.
386 *
387 * Replace the server's FD with the accepted one and close the original.
388 */
389    sal = (LT_SOCKLEN_T)sizeof(aa);
390    (void) alarm(0);
391    (void) signal(SIGALRM, HandleSrvrAlarm);
392    (void) alarm(ALARMTM);
393    tsfd = FdPara[LT_SRVR].fd = accept(Ssock, (struct sockaddr *)&aa, &sal);
394    (void) alarm(0);
395    (void) signal(SIGALRM, SIG_DFL);
396    if (tsfd < 0) {
397	ep = "accept";
398	goto print_errno_by_ti;
399    }
400    (void) snprintf(buf, bufl - 1, "%d", tsfd);
401    buf[bufl - 1] = '\0';
402    if (FdPara[LT_SRVR].fds)
403	(void) free((void *)FdPara[LT_SRVR].fds);
404    FdPara[LT_SRVR].fds = MkStrCpy(buf, &tj);
405    ti = LT_CLNT;
406    (void) memcpy((void *)&FdPara[ti].sa, (void *)&aa, sizeof(FdPara[ti].sa));
407    (void) close(Ssock);
408    Ssock = -1;
409/*
410 * Convert the client and server IP address to ASCII form.
411 *
412 * Look up the client and server host names for their IP addresses.
413 *
414 * Convert the port from the socket address to host form.
415 */
416    for (ti = 0; ti < NFDPARA; ti++) {
417	tcp = inet_ntoa(FdPara[ti].sa.sin_addr);
418	FdPara[ti].ipaddr = MkStrCpy(tcp, &FdPara[ti].ilen);
419	(void) snprintf(buf, bufl - 1, "%d",
420	    (int)ntohs(FdPara[ti].sa.sin_port));
421	buf[bufl - 1] = '\0';
422	FdPara[ti].port = MkStrCpy(buf, &FdPara[ti].plen);
423	if (!(hp = gethostbyaddr((char *)&FdPara[ti].sa.sin_addr,
424				 sizeof(FdPara[ti].sa.sin_addr),
425				 FdPara[ti].sa.sin_family))
426	) {
427	    ep = "gethostbyaddr";
428	    goto print_errno_by_ti;
429	}
430	if (hp->h_name)
431	    FdPara[ti].host = MkStrCpy(hp->h_name, &FdPara[ti].hlen);
432	else {
433
434	/*
435	 * The connected client's socket address can't be mapped to a host
436	 * name.
437	 */
438
439	    (void) snprintf(buf, bufl - 1,
440		"ERROR!!!  can't map %s (client) to a host name",
441		FdPara[ti].ipaddr);
442	    buf[bufl - 1] = '\0';
443	    PrtMsgX(buf, Pn, CleanupSrvr, 1);
444	}
445    }
446/*
447 * Call lsof three times to find the two sockets: 1) by host name and port;
448 * 2) by IP address and port; and 3) by port.
449 */
450    if ((cem = FindSock(LT_FBYHN)))
451	PrtMsgX(cem, Pn, CleanupSrvr, 1);
452    if ((cem = FindSock(LT_FBYIP)))
453	PrtMsgX(cem, Pn, CleanupSrvr, 1);
454    if ((cem = FindSock(LT_FBYPORT)))
455	PrtMsgX(cem, Pn, CleanupSrvr, 1);
456/*
457 * Check the FindSock() results.
458 */
459    for (pem = (char *)NULL, ti = 0; ti < NFDPARA; ti++) {
460	if ((tj = FdPara[ti].ff) != (LT_FBYHN | LT_FBYIP | LT_FBYPORT)) {
461	    host = FdPara[ti].host;
462	    ipaddr = FdPara[ti].ipaddr;
463	    port = FdPara[ti].port;
464
465	/*
466	 * This FD wasn't found by some search method.
467	 */
468	    if (!(tj & LT_FBYHN)) {
469
470	    /*
471	     * The search by host name and port failed.
472	     */
473		(void) snprintf(buf, bufl - 1,
474		    "ERROR!!!  no %s socket by host and port: %s@%s",
475		    PtNm[ti], host, port);
476		buf[bufl - 1] = '\0';
477		if (pem)
478		    (void) PrtMsg(pem, Pn);
479		pem = MkStrCpy(buf, &tk);
480	    }
481	    if (!(tj & LT_FBYIP)) {
482
483	    /*
484	     * The search by IP address and port failed.
485	     */
486		(void) snprintf(buf, bufl - 1,
487		    "ERROR!!!  no %s socket by IP and port: %s@%s",
488		    PtNm[ti], ipaddr, port);
489		buf[bufl - 1] = '\0';
490		if (pem)
491		    (void) PrtMsg(pem, Pn);
492		pem = MkStrCpy(buf, &tk);
493	    }
494	    if (!(tj & LT_FBYPORT)) {
495
496	    /*
497	     * The search by port number failed.
498	     */
499		(void) snprintf(buf, bufl - 1,
500		    "ERROR!!!  no %s socket by port: %s",
501		    PtNm[ti], port);
502		buf[bufl - 1] = '\0';
503		if (pem)
504		    (void) PrtMsg(pem, Pn);
505		pem = MkStrCpy(buf, &tk);
506	    }
507	}
508    }
509    if (pem)
510	(void) PrtMsgX(pem, Pn, CleanupSrvr, 1);
511/*
512 * Exit successfully.
513 */
514    (void) PrtMsgX("OK", Pn, CleanupSrvr, 0);
515    return(0);
516}
517
518
519/*
520 * ClntCleanup() -- release client resources
521 */
522
523static void
524CleanupClnt()
525{
526    int tfd;				/* temporary file descriptor */
527
528    if ((tfd = FdPara[LT_CLNT].fd) >= 0) {
529	(void) shutdown(tfd, 2);
530	(void) close(tfd);
531	FdPara[LT_CLNT].fd = -1;
532    }
533}
534
535
536/*
537 * CleanupSrvr() -- release server resources
538 */
539
540static void
541CleanupSrvr()
542{
543    int tfd;				/* temporary file descriptor */
544    int ti;				/* temporary index */
545    pid_t wpid;				/* wait() PID */
546
547    if ((Ssock >= 0) && (Ssock != FdPara[LT_SRVR].fd)) {
548	(void) shutdown(Ssock, 2);
549	(void) close(Ssock);
550	Ssock = -1;
551    }
552    for (ti = 0; ti < NFDPARA; ti++) {
553	if ((tfd = FdPara[ti].fd) >= 0) {
554	    (void) shutdown(tfd, 2);
555	    (void) close(tfd);
556	    FdPara[ti].fd = -1;
557	}
558    }
559    if (CPid > 0) {
560	wpid = wait3(NULL, WNOHANG, NULL);
561	if (wpid != CPid) {
562	    kill(CPid, SIGKILL);
563	    (void) wait3(NULL, WNOHANG, NULL);
564	}
565	CPid = (pid_t)0;
566    }
567}
568
569
570/*
571 * FindSock() -- find sockets with lsof
572 */
573
574static char *
575FindSock(fn)
576    int fn;				/* function -- an LT_FBY* value */
577{
578    char buf[2048];			/* temporary buffer */
579    int bufl = sizeof(buf);		/* size of buf[] */
580    char *cem;				/* current error message pointer */
581    LTfldo_t *cmdp;			/* command pointer */
582    LTfldo_t *fop;			/* field output pointer */
583    int nf;				/* number of fields */
584    int nl;				/* name length */
585    LTfldo_t *nmp;			/* name pointer */
586    char *opv[5];			/* option vector for ExecLsof() */
587    char *pem = (char *)NULL;		/* previous error message pointer */
588    pid_t pid;				/* PID */
589    int pids = 0;			/* PID found status */
590    int pl;				/* port length */
591    int px;				/* process index -- LT_CLNT or
592					 * LT_SRVR */
593    char *tcp, *tcp1;			/* temporary character pointers */
594    int ti, tj;				/* temporary integers */
595    LTfldo_t *typ;			/* file type pointer */
596/*
597 * Check the function and determine the first lsof option from it.
598 */
599    ti = 0;
600    switch (fn) {
601    case LT_FBYHN:
602	opv[ti++] = "-P";
603	for (tj = 0; tj < NFDPARA; tj++) {
604	    (void) snprintf(buf, bufl - 1, "-i@%s:%s", FdPara[tj].host,
605		FdPara[tj].port);
606	    buf[bufl - 1] = '\0';
607	    opv[ti++] = MkStrCpy(buf, &pl);
608	}
609	break;
610    case LT_FBYIP:
611	opv[ti++] = "-Pn";
612	for (tj = 0; tj < NFDPARA; tj++) {
613	    (void) snprintf(buf, bufl - 1, "-i@%s:%s", FdPara[tj].ipaddr,
614		FdPara[tj].port);
615	    buf[bufl - 1] = '\0';
616	    opv[ti++] = MkStrCpy(buf, &pl);
617	}
618	break;
619    case LT_FBYPORT:
620	opv[ti++] = "-P";
621	for (tj = 0; tj < NFDPARA; tj++) {
622	    (void) snprintf(buf, bufl - 1, "-i:%s", FdPara[tj].port);
623	    buf[bufl - 1] = '\0';
624	    opv[ti++] = MkStrCpy(buf, &pl);
625	}
626	break;
627    default:
628	(void) snprintf(buf, bufl - 1,
629	    "ERROR!!!  illegal FindSock() function: %d", fn);
630	buf[bufl - 1] = '\0';
631	return(MkStrCpy(buf, &ti));
632    }
633/*
634 * Complete the option vector and start lsof execution.
635 */
636
637#if	defined(USE_LSOF_C_OPT)
638    opv[ti++] = "-C";
639#endif	/* defined(USE_LSOF_C_OPT) */
640
641    opv[ti] = (char *)NULL;
642    if ((cem = ExecLsof(opv)))
643	return(cem);
644/*
645 * Read lsof output.
646 */
647    while ((((FdPara[LT_CLNT].ff & fn) == 0)
648    ||	    ((FdPara[LT_SRVR].ff & fn) == 0))
649    &&	   (fop = RdFrLsof(&nf, &cem))
650    ) {
651	if (cem) {
652	    if (pem)
653		(void) PrtMsg(pem, Pn);
654	    return(cem);
655	}
656	switch (fop->ft) {
657	case LSOF_FID_PID:
658
659	/*
660	 * This is a process information line.
661	 */
662	    pid = (pid_t)atoi(fop->v);
663	    pids = 1;
664	    cmdp = (LTfldo_t *)NULL;
665	    for (fop++, ti = 1; ti < nf; fop++, ti++) {
666		switch (fop->ft) {
667		case LSOF_FID_CMD:
668		    cmdp = fop;
669		    break;
670		}
671	    }
672	    if (!cmdp || ((pid != CPid) && (pid != MyPid)))
673		pids = 0;
674	    break;
675	case LSOF_FID_FD:
676
677	/*
678	 * This is a file descriptor line.
679	 *
680	 * Identify the process -- client or server.
681	 */
682	    if (!pids)
683		break;
684	    if (pid == CPid)
685		px = LT_CLNT;
686	    else if (pid == MyPid)
687		px = LT_SRVR;
688	    else
689		break;
690	/*
691	 * Make sure the FD matches the identified process.
692	 */
693	    if (strcmp(fop->v, FdPara[px].fds))
694		break;
695	/*
696	 * Scan for name and type.
697	 */
698	    nmp = typ  = (LTfldo_t *)NULL;
699	    for (fop++, ti = 1; ti < nf; fop++, ti++) {
700		switch (fop->ft) {
701		case LSOF_FID_NAME:
702		    nmp = fop;
703		    break;
704		case LSOF_FID_TYPE:
705		    typ = fop;
706		    break;
707		}
708	    }
709	/*
710	 * Check the type of the file.
711	 */
712	    if (!typ
713	    ||  (strcasecmp(typ->v, "inet") && strcasecmp(typ->v, "ipv4"))
714	    ) {
715		break;
716	    }
717	/*
718	 * Check the addess in the name, based on the calling function.
719	 */
720	    if (!nmp)
721		break;
722	    tcp = nmp->v;
723	    switch (fn) {
724	    case LT_FBYHN:
725		if (((nl = FdPara[px].hlen) <= 0)
726		||  !(tcp1 = FdPara[px].host)
727		||  strncasecmp(tcp, tcp1, nl)
728		) {
729		    break;
730		}
731		tcp += nl;
732		if ((*tcp++ != ':')
733		||  !(tcp1 = FdPara[px].port)
734		||  ((pl = FdPara[px].plen) <= 0)
735		||  strncmp(tcp, tcp1, pl)
736		) {
737		    break;
738		}
739		tcp += pl;
740		if ((*tcp == '-') || (*tcp == ' ') || !*tcp) {
741		    FdPara[px].ff |= LT_FBYHN;
742		}
743		break;
744	    case LT_FBYIP:
745		if (((nl = FdPara[px].ilen) <= 0)
746		||  !(tcp1 = FdPara[px].ipaddr)
747		||  strncasecmp(tcp, tcp1, nl)
748		) {
749		    break;
750		}
751		tcp += nl;
752		if ((*tcp++ != ':')
753		||  !(tcp1 = FdPara[px].port)
754		||  ((pl = FdPara[px].plen) <= 0)
755		||  strncmp(tcp, tcp1, pl)
756		) {
757		    break;
758		}
759		tcp += pl;
760		if ((*tcp == '-') || (*tcp == ' ') || !*tcp) {
761		    FdPara[px].ff |= LT_FBYIP;
762		}
763		break;
764	    case LT_FBYPORT:
765		if (!(tcp = strchr(tcp, ':')))
766		    break;
767		tcp++;
768		if (!(tcp1 = FdPara[px].port)
769		||  ((pl = FdPara[px].plen) <= 0)
770		||  strncmp(tcp, tcp1, pl)
771		) {
772		    break;
773		}
774		tcp += pl;
775		if ((*tcp == '-') || (*tcp == ' ') || !*tcp) {
776		    FdPara[px].ff |= LT_FBYPORT;
777		}
778		break;
779	    }
780	}
781    }
782/*
783 * Clean up and return.
784 */
785    (void) StopLsof();
786    return(pem);
787}
788
789
790/*
791 * HandleClntAlarm() -- handle client alarm
792 */
793
794static SIGHANDLER_T
795HandleClntAlarm(sig)
796    int sig;				/* the signal (SIGALRM) */
797{
798    (void) PrtMsgX("ERROR!!!  client caught an alarm signal", Pn,
799	CleanupClnt, 1);
800}
801
802
803/*
804 * Handle SrvrAlarm() -- handle server alarm
805 */
806
807static SIGHANDLER_T
808HandleSrvrAlarm(sig)
809    int sig;				/* the signal (SIGALRM) */
810{
811    (void) PrtMsgX("ERROR!!!  server caught an alarm signal.", Pn,
812	CleanupSrvr, 1);
813}
814
815
816/*
817 * StartClnt() -- start network client
818 */
819
820static void
821StartClnt(cad)
822    struct sockaddr_in *cad;		/* connection address */
823{
824    struct sockaddr_in ba;		/* bind address */
825    int br;				/* bytes read */
826    char buf[2048];			/* temporary buffer */
827    int bufl = sizeof(buf);		/* size of buf[] */
828    int cr;				/* connect() reply */
829    char *em;				/* error message pointer */
830    int fd = FdPara[LT_CLNT].fd;	/* client's socket FD */
831/*
832 * Close the server's sockets.
833 */
834    if ((Ssock >= 0) && (Ssock != FdPara[LT_SRVR].fd)) {
835	(void) close(Ssock);
836	Ssock = -1;
837    }
838    if (FdPara[LT_SRVR].fd >= 0) {
839	(void) close(FdPara[LT_SRVR].fd);
840	FdPara[LT_SRVR].fd = -1;
841    }
842/*
843 * Bind to the local address.
844 */
845    (void) memcpy((void *)&ba, (void *)&Myad, sizeof(ba));
846    if (bind(fd, (struct sockaddr *)&ba, sizeof(ba)) < 0) {
847	em = "bind";
848
849client_errno:
850
851	(void) snprintf(buf, bufl - 1,
852	    "ERROR!!!  client %s error: %s", em, strerror(errno));
853	buf[bufl - 1] = '\0';
854	(void) PrtMsgX(em, Pn, CleanupClnt, 1);
855    }
856/*
857 * Set an alarm timeout and connect to the server.
858 */
859    (void) signal(SIGALRM, HandleClntAlarm);
860    (void) alarm(ALARMTM);
861    cr = connect(fd, (struct sockaddr *)cad, sizeof(struct sockaddr_in));
862    (void) alarm(0);
863    (void) signal(SIGALRM, SIG_DFL);
864    if (cr) {
865	em = "connect";
866	goto client_errno;
867    }
868/*
869 * Sleep until the socket closes or the parent kills the process.
870 */
871    for (br = 0; br >= 0;) {
872	sleep(1);
873	br = read(fd, buf, bufl);
874    }
875    (void) CleanupClnt();
876    exit(0);
877}
878