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 */
externalfinish(fd)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 */
externalabort(fd)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 */
externaloption(fd,opts,optlen)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