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