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