1*60594Sbostic /*-
2*60594Sbostic  * Copyright (c) 1993 The Regents of the University of California.
338026Sbostic  * All rights reserved.
438026Sbostic  *
538026Sbostic  * This code is derived from software contributed to Berkeley by
638026Sbostic  * Bill Jolitz.
738026Sbostic  *
8*60594Sbostic  * %sccs.include.redist.c%
938026Sbostic  */
1038026Sbostic 
1138026Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*60594Sbostic static char sccsid[] = "@(#)externalconnect.c	5.2 (Berkeley) 05/29/93";
1338026Sbostic #endif /* LIBC_SCCS and not lint */
1438026Sbostic 
1538026Sbostic /*
1638026Sbostic  * externalconnect:
1738026Sbostic  *	send a message to connection daemon via UNIX domain socket
1838026Sbostic  *	containing a resource request and preparation instructions;
1938026Sbostic  *	expect a response message containing either the file descriptor
2038026Sbostic  *	of the resource and method of preparation, or an connection
2138026Sbostic  *	error status explaining why it could not be done.
2238026Sbostic  */
2338026Sbostic 
2438026Sbostic #include <sys/types.h>
2538026Sbostic #include <sys/socket.h>
2638026Sbostic #include <sys/un.h>
2738026Sbostic #include <sys/uio.h>
2838026Sbostic #include <connect.h>
2938026Sbostic 
3038026Sbostic static struct fdsocket {
3138026Sbostic 	int fd;
3238026Sbostic 	int sock;
3338026Sbostic 	int state ;
3438026Sbostic }	fdsockets[MAXCONNECTS];
3538026Sbostic static nfds = 0, inprocess = -1 ;
3638026Sbostic 
3738026Sbostic externalconnect (cdp, opts, optlen, efd)
3838026Sbostic 	struct connectdomain *cdp ;
3938026Sbostic 	char *opts ; int optlen ; int efd ;
4038026Sbostic {
4138026Sbostic 	int sock, n, i, fd, rv ;
4238026Sbostic 	struct sockaddr_un rqsts;
4338026Sbostic 	struct iovec iov[4];
4438026Sbostic 	struct msghdr msg ;
4538026Sbostic 	int constatus, rqstfmt;
4638026Sbostic 
4738026Sbostic 
4838026Sbostic 	sock = socket (AF_UNIX, SOCK_STREAM, 0) ;
4938026Sbostic 	if (sock < 0) {
5038026Sbostic 		perror("externalconnect: stream socket") ;
5138026Sbostic 		exit(1) ;
5238026Sbostic 	}
5338026Sbostic 	rqsts.sun_family = AF_UNIX ;
5438026Sbostic 	strcpy (rqsts.sun_path,"/dev/connect") ;
5538026Sbostic 	if (connect (sock, &rqsts, sizeof (rqsts)) < 0) {
5638026Sbostic 		perror ("externalconnect: connect /dev/connect") ;
5738026Sbostic 		exit (1) ;
5838026Sbostic 	}
5938026Sbostic 
6038026Sbostic 	/* record evidence of communication, so that multiple
6138026Sbostic 	   outstandings/aborts are possible */
6238026Sbostic 	if (!nfds)
6338026Sbostic 		for (i = 0; i < MAXCONNECTS ; i++) {
6438026Sbostic 			fdsockets[i].fd = -1;
6538026Sbostic 			fdsockets[i].sock = -1;
6638026Sbostic 			fdsockets[i].state = -1; } ;
6738026Sbostic 	fdsockets[nfds].sock = sock ;
6838026Sbostic 	fdsockets[nfds].state = CDNEWREQUEST ;
6938026Sbostic 	inprocess = nfds++ ;
7038026Sbostic 
7138026Sbostic 
7238026Sbostic 	/* send connnection request message */
7338026Sbostic 	rqstfmt = CDNEWREQUEST;
7438026Sbostic 	msg.msg_name = "";
7538026Sbostic 	msg.msg_namelen = 0 ;
7638026Sbostic 	iov[0].iov_base = (caddr_t) &rqstfmt ;
7738026Sbostic 	iov[0].iov_len = sizeof (rqstfmt) ;
7838026Sbostic 	iov[1].iov_base = (caddr_t) cdp ;
7938026Sbostic 	iov[1].iov_len = CDSIZE(cdp) ;
8038026Sbostic 	iov[2].iov_base = (caddr_t) opts;
8138026Sbostic 	iov[2].iov_len = optlen ;
8238026Sbostic 	msg.msg_iov = iov;
8338026Sbostic 	msg.msg_iovlen = 3;
8438026Sbostic 	if (efd) {
8538026Sbostic 		msg.msg_accrights = (caddr_t) &efd ;
8638026Sbostic 		msg.msg_accrightslen = sizeof (efd) ;
8738026Sbostic 	} else	msg.msg_accrightslen = 0;
8838026Sbostic 
8938026Sbostic 	if (sendmsg (sock, &msg, 0) < 0) {
9038026Sbostic 		perror("externalconnection: sendmsg") ;
9138026Sbostic 		exit(1) ;
9238026Sbostic 	}
9338026Sbostic 
9438026Sbostic 	/* recieve message from connection daemon */
9538026Sbostic 	msg.msg_name = "" ;
9638026Sbostic 	msg.msg_namelen = 0 ;
9738026Sbostic 	iov[0].iov_base = (caddr_t) &rqstfmt ;
9838026Sbostic 	iov[0].iov_len = sizeof(rqstfmt) ;
9938026Sbostic 	iov[1].iov_base = (caddr_t) &constatus ;
10038026Sbostic 	iov[1].iov_len = sizeof(constatus) ;
10138026Sbostic 	iov[2].iov_base = (caddr_t) opts;
10238026Sbostic 	iov[2].iov_len = optlen ;
10338026Sbostic 	msg.msg_iov = iov;
10438026Sbostic 	msg.msg_iovlen = 3;
10538026Sbostic 	msg.msg_accrights = (caddr_t) &fd ;
10638026Sbostic 	msg.msg_accrightslen = sizeof (fd) ;
10738026Sbostic 
10838026Sbostic 	if (recvmsg (sock, &msg, 0) < 0) {
10938026Sbostic 		perror("externalconnection: recvmsg") ;
11038026Sbostic 		exit(1) ;
11138026Sbostic 	}
11238026Sbostic 
11338026Sbostic 	/* did we succeed? */
11438026Sbostic 	inprocess = -1 ;
11538026Sbostic 	if (msg.msg_accrightslen >= sizeof (fd)) {
11638026Sbostic /* XXX needs more work */
11738026Sbostic 		fdsockets[nfds-1].fd = fd ;
11838026Sbostic 		fdsockets[nfds-1].state = CDNEWRESPONSE ;
11938026Sbostic 		return (fd) ;
12038026Sbostic 	} else {
12138026Sbostic 		nfds--;
12238026Sbostic 		close (sock) ;
12338026Sbostic 		return (constatus) ;
12438026Sbostic 	}
12538026Sbostic }
12638026Sbostic 
12738026Sbostic /*
12838026Sbostic  * externalfinish: send back file descriptor we got from
12938026Sbostic  *	external connect for a well-behaved close. We
13038026Sbostic  *	will wait for close just to be able to report
13138026Sbostic  *	back any trouble.
13238026Sbostic  */
externalfinish(fd)13338026Sbostic externalfinish (fd)
13438026Sbostic 	int fd ;
13538026Sbostic {
13638026Sbostic 	int sock, n, i, rv ;
13738026Sbostic 	struct iovec iov[2];
13838026Sbostic 	struct msghdr msg ;
13938026Sbostic 	int constatus, rqstfmt;
14038026Sbostic 	struct fdsocket *fdp;
14138026Sbostic 
14238026Sbostic 
14338026Sbostic 	fdp = fdsockets ;
14438026Sbostic 	/* find socket associated with file descriptor */
14538026Sbostic 	for (i = 0; i < nfds ; i++,fdp++)
14638026Sbostic 		if (fdp->fd == fd) break;
14738026Sbostic 
14838026Sbostic 	/* not found at all */
14938026Sbostic 	if (i > nfds || !nfds) {
15038026Sbostic 		if (inprocess >= 0) externalabort(-1);
15138026Sbostic 		return (-1) ;
15238026Sbostic 	}
15338026Sbostic 
15438026Sbostic 	sock = fdp->sock ;
15538026Sbostic 
15638026Sbostic 	/* never was open */
15738026Sbostic 	if (sock < 0) return (-2) ;
15838026Sbostic 
15938026Sbostic 	/* is there an outstanding request on this guy? */
16038026Sbostic 	if (ISCDREQUEST(fdp->state)) externalabort(fdp->fd);
16138026Sbostic 
16238026Sbostic 	/* mark as closed */
16338026Sbostic 	fdp->fd = -1 ;
16438026Sbostic 
16538026Sbostic 
16638026Sbostic 	/* send finish request message */
16738026Sbostic 	inprocess = rqstfmt = CDFINISHREQUEST;
16838026Sbostic 	msg.msg_name = "";
16938026Sbostic 	msg.msg_namelen = 0 ;
17038026Sbostic 	iov[0].iov_base = (caddr_t) &rqstfmt ;
17138026Sbostic 	iov[0].iov_len = sizeof (rqstfmt) ;
17238026Sbostic 	msg.msg_iov = iov;
17338026Sbostic 	msg.msg_iovlen = 1;
17438026Sbostic 	msg.msg_accrights = (caddr_t) &fd ;
17538026Sbostic 	msg.msg_accrightslen = sizeof (fd) ;
17638026Sbostic 
17738026Sbostic 	if (sendmsg (sock, &msg, 0) < 0) {
17838026Sbostic 		perror("externalfinish: sendmsg") ;
17938026Sbostic 		return (-3) ;
18038026Sbostic 	}
18138026Sbostic 
18238026Sbostic 	/* recieve message from connection daemon */
18338026Sbostic 	msg.msg_name = "" ;
18438026Sbostic 	msg.msg_namelen = 0 ;
18538026Sbostic 	iov[0].iov_base = (caddr_t) &rqstfmt ;
18638026Sbostic 	iov[0].iov_len = sizeof(rqstfmt) ;
18738026Sbostic 	iov[1].iov_base = (caddr_t) &constatus ;
18838026Sbostic 	iov[1].iov_len = sizeof(constatus) ;
18938026Sbostic 	msg.msg_iov = iov;
19038026Sbostic 	msg.msg_iovlen = 2;
19138026Sbostic 	msg.msg_accrights = 0 ;
19238026Sbostic 	msg.msg_accrightslen = 0;
19338026Sbostic 
19438026Sbostic 	if (recvmsg (sock, &msg, 0) < 0) {
19538026Sbostic 		perror("externalfinish: recvmsg") ;
19638026Sbostic 		return (-4) ;
19738026Sbostic 	}
19838026Sbostic 	inprocess = -1 ;
19938026Sbostic 	close (fd) ;
20038026Sbostic 	close (sock) ;
20138026Sbostic 
20238026Sbostic 	if (rqstfmt != CDFINISHRESPONSE) return (-5) ;
20338026Sbostic 	return (constatus) ;
20438026Sbostic }
20538026Sbostic 
20638026Sbostic /*
20738026Sbostic  * externalabort: if we have an outstanding request,
20838026Sbostic  *	cancel it and return immediately. If the request
20938026Sbostic  *	was the initial open, the connection will never
21038026Sbostic  *	return a file descriptor, otherwise connection
21138026Sbostic  *	status is unaffected. This  routine is mean to be
21238026Sbostic  *	called from interrupt routines.
21338026Sbostic  */
externalabort(fd)21438026Sbostic externalabort (fd)
21538026Sbostic 	int fd ;
21638026Sbostic {
21738026Sbostic 	int sock, n, i, rv ;
21838026Sbostic 	struct iovec iov[2];
21938026Sbostic 	struct msghdr msg ;
22038026Sbostic 	int constatus, rqstfmt;
22138026Sbostic 	struct fdsocket *fdp;
22238026Sbostic 
22338026Sbostic 
22438026Sbostic 	fdp = fdsockets ;
22538026Sbostic 	/* if we don't know who we are, abort current connection */
22638026Sbostic 	if (fd < 0) {
22738026Sbostic 		/* but nothing's going on... */
22838026Sbostic 		if (inprocess < 0) return (-1) ;
22938026Sbostic 		fdp += inprocess ;
23038026Sbostic 	} else	{
23138026Sbostic 		/* find socket associated with file descriptor */
23238026Sbostic 		for (i = 0; i < nfds ; i++,fdp++)
23338026Sbostic 			if (fdp->fd == fd) break;
23438026Sbostic 
23538026Sbostic 		/* not found at all */
23638026Sbostic 		if (i > nfds || !nfds)
23738026Sbostic 			return (-1) ;
23838026Sbostic 	}
23938026Sbostic 
24038026Sbostic 	sock = fdp->sock ;
24138026Sbostic 
24238026Sbostic 	/* never was open */
24338026Sbostic 	if (sock < 0) return (-2) ;
24438026Sbostic 
24538026Sbostic 	/* is there not an outstanding request on this guy? */
24638026Sbostic 	if (!ISCDREQUEST(fdp->state)) return (-3) ;
24738026Sbostic 
24838026Sbostic 	/* send abort request message */
24938026Sbostic 	rqstfmt = CDCANCELREQUEST;
25038026Sbostic 	msg.msg_name = "";
25138026Sbostic 	msg.msg_namelen = 0 ;
25238026Sbostic 	iov[0].iov_base = (caddr_t) &rqstfmt ;
25338026Sbostic 	iov[0].iov_len = sizeof (rqstfmt) ;
25438026Sbostic 	msg.msg_iov = iov;
25538026Sbostic 	msg.msg_iovlen = 1;
25638026Sbostic 	msg.msg_accrights = (caddr_t) &fd ;
25738026Sbostic 	msg.msg_accrightslen = sizeof (fd) ;
25838026Sbostic 
25938026Sbostic 	if (sendmsg (sock, &msg, MSG_OOB) < 0) {
26038026Sbostic 		perror("externalabort: sendmsg") ;
26138026Sbostic 		return (-4) ;
26238026Sbostic 	}
26338026Sbostic 	return (0) ;
26438026Sbostic }
26538026Sbostic 
26638026Sbostic /*
26738026Sbostic  * externaloption: send a bag of options to be done to the file descriptor
26838026Sbostic  *	we got from externalconnect. Options are passed as value-result.
26938026Sbostic  */
externaloption(fd,opts,optlen)27038026Sbostic externaloption (fd, opts, optlen)
27138026Sbostic 	int fd ;
27238026Sbostic 	char *opts ;
27338026Sbostic 	int *optlen ;
27438026Sbostic {
27538026Sbostic 	int sock, n, i, rv ;
27638026Sbostic 	struct iovec iov[3];
27738026Sbostic 	struct msghdr msg ;
27838026Sbostic 	int constatus, rqstfmt;
27938026Sbostic 	struct fdsocket *fdp;
28038026Sbostic 
28138026Sbostic 
28238026Sbostic 	fdp = fdsockets ;
28338026Sbostic 	/* find socket associated with file descriptor */
28438026Sbostic 	for (i = 0; i < nfds ; i++,fdp++)
28538026Sbostic 		if (fdp->fd == fd) break;
28638026Sbostic 
28738026Sbostic 	/* not found at all */
28838026Sbostic 	if (i > nfds || !nfds)
28938026Sbostic 		return (-1) ;
29038026Sbostic 
29138026Sbostic 	sock = fdp->sock ;
29238026Sbostic 
29338026Sbostic 	/* never was open */
29438026Sbostic 	if (sock < 0) return (-2) ;
29538026Sbostic 
29638026Sbostic 	/* is there an outstanding request on this guy? */
29738026Sbostic 	if (ISCDREQUEST(fdp->state)) return (-3) ;
29838026Sbostic 
29938026Sbostic 	/* mark as closed */
30038026Sbostic 	fdp->fd = -1 ;
30138026Sbostic 
30238026Sbostic 	/* send finish request message */
30338026Sbostic 	inprocess = rqstfmt = CDOPTIONREQUEST;
30438026Sbostic 	msg.msg_name = "";
30538026Sbostic 	msg.msg_namelen = 0 ;
30638026Sbostic 	iov[0].iov_base = (caddr_t) &rqstfmt ;
30738026Sbostic 	iov[0].iov_len = sizeof (rqstfmt) ;
30838026Sbostic 	iov[1].iov_base = (caddr_t) opts ;
30938026Sbostic 	iov[1].iov_len = *optlen ;
31038026Sbostic 	msg.msg_iov = iov;
31138026Sbostic 	msg.msg_iovlen = 2;
31238026Sbostic 	msg.msg_accrights = (caddr_t) &fd ;
31338026Sbostic 	msg.msg_accrightslen = sizeof (fd) ;
31438026Sbostic 
31538026Sbostic 	if (sendmsg (sock, &msg, 0) < 0) {
31638026Sbostic 		perror("externaloption: sendmsg") ;
31738026Sbostic 		return (-3) ;
31838026Sbostic 	}
31938026Sbostic 
32038026Sbostic 	/* recieve message from connection daemon */
32138026Sbostic 	msg.msg_name = "" ;
32238026Sbostic 	msg.msg_namelen = 0 ;
32338026Sbostic 	iov[0].iov_base = (caddr_t) &rqstfmt ;
32438026Sbostic 	iov[0].iov_len = sizeof(rqstfmt) ;
32538026Sbostic 	iov[1].iov_base = (caddr_t) &constatus ;
32638026Sbostic 	iov[1].iov_len = sizeof(constatus) ;
32738026Sbostic 	iov[2].iov_base = (caddr_t) opts ;
32838026Sbostic 	iov[2].iov_len = *optlen ;
32938026Sbostic 	msg.msg_iov = iov;
33038026Sbostic 	msg.msg_iovlen = 3;
33138026Sbostic 	msg.msg_accrights = 0 ;
33238026Sbostic 	msg.msg_accrightslen = 0;
33338026Sbostic 
33438026Sbostic 	if (recvmsg (sock, &msg, 0) < 0) {
33538026Sbostic 		perror("externaloption: recvmsg") ;
33638026Sbostic 		return (-4) ;
33738026Sbostic 	}
33838026Sbostic 	inprocess = -1 ;
33938026Sbostic 
34038026Sbostic 	if (rqstfmt != CDOPTIONRESPONSE) return (-5) ;
34138026Sbostic 	return (constatus) ;
34238026Sbostic }
343