1 /*-
2  * Copyright (c) 1993 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Bill Jolitz.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)externalconnect.c	5.2 (Berkeley) 05/29/93";
13 #endif /* LIBC_SCCS and not lint */
14 
15 /*
16  * externalconnect:
17  *	send a message to connection daemon via UNIX domain socket
18  *	containing a resource request and preparation instructions;
19  *	expect a response message containing either the file descriptor
20  *	of the resource and method of preparation, or an connection
21  *	error status explaining why it could not be done.
22  */
23 
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/uio.h>
28 #include <connect.h>
29 
30 static struct fdsocket {
31 	int fd;
32 	int sock;
33 	int state ;
34 }	fdsockets[MAXCONNECTS];
35 static nfds = 0, inprocess = -1 ;
36 
37 externalconnect (cdp, opts, optlen, efd)
38 	struct connectdomain *cdp ;
39 	char *opts ; int optlen ; int efd ;
40 {
41 	int sock, n, i, fd, rv ;
42 	struct sockaddr_un rqsts;
43 	struct iovec iov[4];
44 	struct msghdr msg ;
45 	int constatus, rqstfmt;
46 
47 
48 	sock = socket (AF_UNIX, SOCK_STREAM, 0) ;
49 	if (sock < 0) {
50 		perror("externalconnect: stream socket") ;
51 		exit(1) ;
52 	}
53 	rqsts.sun_family = AF_UNIX ;
54 	strcpy (rqsts.sun_path,"/dev/connect") ;
55 	if (connect (sock, &rqsts, sizeof (rqsts)) < 0) {
56 		perror ("externalconnect: connect /dev/connect") ;
57 		exit (1) ;
58 	}
59 
60 	/* record evidence of communication, so that multiple
61 	   outstandings/aborts are possible */
62 	if (!nfds)
63 		for (i = 0; i < MAXCONNECTS ; i++) {
64 			fdsockets[i].fd = -1;
65 			fdsockets[i].sock = -1;
66 			fdsockets[i].state = -1; } ;
67 	fdsockets[nfds].sock = sock ;
68 	fdsockets[nfds].state = CDNEWREQUEST ;
69 	inprocess = nfds++ ;
70 
71 
72 	/* send connnection request message */
73 	rqstfmt = CDNEWREQUEST;
74 	msg.msg_name = "";
75 	msg.msg_namelen = 0 ;
76 	iov[0].iov_base = (caddr_t) &rqstfmt ;
77 	iov[0].iov_len = sizeof (rqstfmt) ;
78 	iov[1].iov_base = (caddr_t) cdp ;
79 	iov[1].iov_len = CDSIZE(cdp) ;
80 	iov[2].iov_base = (caddr_t) opts;
81 	iov[2].iov_len = optlen ;
82 	msg.msg_iov = iov;
83 	msg.msg_iovlen = 3;
84 	if (efd) {
85 		msg.msg_accrights = (caddr_t) &efd ;
86 		msg.msg_accrightslen = sizeof (efd) ;
87 	} else	msg.msg_accrightslen = 0;
88 
89 	if (sendmsg (sock, &msg, 0) < 0) {
90 		perror("externalconnection: sendmsg") ;
91 		exit(1) ;
92 	}
93 
94 	/* recieve message from connection daemon */
95 	msg.msg_name = "" ;
96 	msg.msg_namelen = 0 ;
97 	iov[0].iov_base = (caddr_t) &rqstfmt ;
98 	iov[0].iov_len = sizeof(rqstfmt) ;
99 	iov[1].iov_base = (caddr_t) &constatus ;
100 	iov[1].iov_len = sizeof(constatus) ;
101 	iov[2].iov_base = (caddr_t) opts;
102 	iov[2].iov_len = optlen ;
103 	msg.msg_iov = iov;
104 	msg.msg_iovlen = 3;
105 	msg.msg_accrights = (caddr_t) &fd ;
106 	msg.msg_accrightslen = sizeof (fd) ;
107 
108 	if (recvmsg (sock, &msg, 0) < 0) {
109 		perror("externalconnection: recvmsg") ;
110 		exit(1) ;
111 	}
112 
113 	/* did we succeed? */
114 	inprocess = -1 ;
115 	if (msg.msg_accrightslen >= sizeof (fd)) {
116 /* XXX needs more work */
117 		fdsockets[nfds-1].fd = fd ;
118 		fdsockets[nfds-1].state = CDNEWRESPONSE ;
119 		return (fd) ;
120 	} else {
121 		nfds--;
122 		close (sock) ;
123 		return (constatus) ;
124 	}
125 }
126 
127 /*
128  * externalfinish: send back file descriptor we got from
129  *	external connect for a well-behaved close. We
130  *	will wait for close just to be able to report
131  *	back any trouble.
132  */
133 externalfinish (fd)
134 	int fd ;
135 {
136 	int sock, n, i, rv ;
137 	struct iovec iov[2];
138 	struct msghdr msg ;
139 	int constatus, rqstfmt;
140 	struct fdsocket *fdp;
141 
142 
143 	fdp = fdsockets ;
144 	/* find socket associated with file descriptor */
145 	for (i = 0; i < nfds ; i++,fdp++)
146 		if (fdp->fd == fd) break;
147 
148 	/* not found at all */
149 	if (i > nfds || !nfds) {
150 		if (inprocess >= 0) externalabort(-1);
151 		return (-1) ;
152 	}
153 
154 	sock = fdp->sock ;
155 
156 	/* never was open */
157 	if (sock < 0) return (-2) ;
158 
159 	/* is there an outstanding request on this guy? */
160 	if (ISCDREQUEST(fdp->state)) externalabort(fdp->fd);
161 
162 	/* mark as closed */
163 	fdp->fd = -1 ;
164 
165 
166 	/* send finish request message */
167 	inprocess = rqstfmt = CDFINISHREQUEST;
168 	msg.msg_name = "";
169 	msg.msg_namelen = 0 ;
170 	iov[0].iov_base = (caddr_t) &rqstfmt ;
171 	iov[0].iov_len = sizeof (rqstfmt) ;
172 	msg.msg_iov = iov;
173 	msg.msg_iovlen = 1;
174 	msg.msg_accrights = (caddr_t) &fd ;
175 	msg.msg_accrightslen = sizeof (fd) ;
176 
177 	if (sendmsg (sock, &msg, 0) < 0) {
178 		perror("externalfinish: sendmsg") ;
179 		return (-3) ;
180 	}
181 
182 	/* recieve message from connection daemon */
183 	msg.msg_name = "" ;
184 	msg.msg_namelen = 0 ;
185 	iov[0].iov_base = (caddr_t) &rqstfmt ;
186 	iov[0].iov_len = sizeof(rqstfmt) ;
187 	iov[1].iov_base = (caddr_t) &constatus ;
188 	iov[1].iov_len = sizeof(constatus) ;
189 	msg.msg_iov = iov;
190 	msg.msg_iovlen = 2;
191 	msg.msg_accrights = 0 ;
192 	msg.msg_accrightslen = 0;
193 
194 	if (recvmsg (sock, &msg, 0) < 0) {
195 		perror("externalfinish: recvmsg") ;
196 		return (-4) ;
197 	}
198 	inprocess = -1 ;
199 	close (fd) ;
200 	close (sock) ;
201 
202 	if (rqstfmt != CDFINISHRESPONSE) return (-5) ;
203 	return (constatus) ;
204 }
205 
206 /*
207  * externalabort: if we have an outstanding request,
208  *	cancel it and return immediately. If the request
209  *	was the initial open, the connection will never
210  *	return a file descriptor, otherwise connection
211  *	status is unaffected. This  routine is mean to be
212  *	called from interrupt routines.
213  */
214 externalabort (fd)
215 	int fd ;
216 {
217 	int sock, n, i, rv ;
218 	struct iovec iov[2];
219 	struct msghdr msg ;
220 	int constatus, rqstfmt;
221 	struct fdsocket *fdp;
222 
223 
224 	fdp = fdsockets ;
225 	/* if we don't know who we are, abort current connection */
226 	if (fd < 0) {
227 		/* but nothing's going on... */
228 		if (inprocess < 0) return (-1) ;
229 		fdp += inprocess ;
230 	} else	{
231 		/* find socket associated with file descriptor */
232 		for (i = 0; i < nfds ; i++,fdp++)
233 			if (fdp->fd == fd) break;
234 
235 		/* not found at all */
236 		if (i > nfds || !nfds)
237 			return (-1) ;
238 	}
239 
240 	sock = fdp->sock ;
241 
242 	/* never was open */
243 	if (sock < 0) return (-2) ;
244 
245 	/* is there not an outstanding request on this guy? */
246 	if (!ISCDREQUEST(fdp->state)) return (-3) ;
247 
248 	/* send abort request message */
249 	rqstfmt = CDCANCELREQUEST;
250 	msg.msg_name = "";
251 	msg.msg_namelen = 0 ;
252 	iov[0].iov_base = (caddr_t) &rqstfmt ;
253 	iov[0].iov_len = sizeof (rqstfmt) ;
254 	msg.msg_iov = iov;
255 	msg.msg_iovlen = 1;
256 	msg.msg_accrights = (caddr_t) &fd ;
257 	msg.msg_accrightslen = sizeof (fd) ;
258 
259 	if (sendmsg (sock, &msg, MSG_OOB) < 0) {
260 		perror("externalabort: sendmsg") ;
261 		return (-4) ;
262 	}
263 	return (0) ;
264 }
265 
266 /*
267  * externaloption: send a bag of options to be done to the file descriptor
268  *	we got from externalconnect. Options are passed as value-result.
269  */
270 externaloption (fd, opts, optlen)
271 	int fd ;
272 	char *opts ;
273 	int *optlen ;
274 {
275 	int sock, n, i, rv ;
276 	struct iovec iov[3];
277 	struct msghdr msg ;
278 	int constatus, rqstfmt;
279 	struct fdsocket *fdp;
280 
281 
282 	fdp = fdsockets ;
283 	/* find socket associated with file descriptor */
284 	for (i = 0; i < nfds ; i++,fdp++)
285 		if (fdp->fd == fd) break;
286 
287 	/* not found at all */
288 	if (i > nfds || !nfds)
289 		return (-1) ;
290 
291 	sock = fdp->sock ;
292 
293 	/* never was open */
294 	if (sock < 0) return (-2) ;
295 
296 	/* is there an outstanding request on this guy? */
297 	if (ISCDREQUEST(fdp->state)) return (-3) ;
298 
299 	/* mark as closed */
300 	fdp->fd = -1 ;
301 
302 	/* send finish request message */
303 	inprocess = rqstfmt = CDOPTIONREQUEST;
304 	msg.msg_name = "";
305 	msg.msg_namelen = 0 ;
306 	iov[0].iov_base = (caddr_t) &rqstfmt ;
307 	iov[0].iov_len = sizeof (rqstfmt) ;
308 	iov[1].iov_base = (caddr_t) opts ;
309 	iov[1].iov_len = *optlen ;
310 	msg.msg_iov = iov;
311 	msg.msg_iovlen = 2;
312 	msg.msg_accrights = (caddr_t) &fd ;
313 	msg.msg_accrightslen = sizeof (fd) ;
314 
315 	if (sendmsg (sock, &msg, 0) < 0) {
316 		perror("externaloption: sendmsg") ;
317 		return (-3) ;
318 	}
319 
320 	/* recieve message from connection daemon */
321 	msg.msg_name = "" ;
322 	msg.msg_namelen = 0 ;
323 	iov[0].iov_base = (caddr_t) &rqstfmt ;
324 	iov[0].iov_len = sizeof(rqstfmt) ;
325 	iov[1].iov_base = (caddr_t) &constatus ;
326 	iov[1].iov_len = sizeof(constatus) ;
327 	iov[2].iov_base = (caddr_t) opts ;
328 	iov[2].iov_len = *optlen ;
329 	msg.msg_iov = iov;
330 	msg.msg_iovlen = 3;
331 	msg.msg_accrights = 0 ;
332 	msg.msg_accrightslen = 0;
333 
334 	if (recvmsg (sock, &msg, 0) < 0) {
335 		perror("externaloption: recvmsg") ;
336 		return (-4) ;
337 	}
338 	inprocess = -1 ;
339 
340 	if (rqstfmt != CDOPTIONRESPONSE) return (-5) ;
341 	return (constatus) ;
342 }
343