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