4 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * $DragonFly: src/lib/libcaps/Attic/caps_service.c,v 1.1 2003/11/24 21:15:58 dillon Exp $
33 static lwkt_msg_t caps_service_kev(struct kevent *kev);
35 static int caps_service_putport(lwkt_port_t port, lwkt_msg_t msg);
36 static void *caps_service_waitport(lwkt_port_t port, lwkt_msg_t msg);
37 static void caps_service_replyport(lwkt_port_t port, lwkt_msg_t msg);
39 static int caps_remote_putport(lwkt_port_t port, lwkt_msg_t msg);
40 static void *caps_remote_waitport(lwkt_port_t port, lwkt_msg_t msg);
41 static void caps_remote_replyport(lwkt_port_t port, lwkt_msg_t msg);
44 * Create a message port rendezvous at the specified service name.
46 * Use the standard lwkt_*() messaging functions to retrieve and reply to
47 * messages sent to your port.
49 * This code will eventually be replaced by a kernel API
52 caps_service(const char *name, gid_t gid, mode_t modes, int flags)
54 struct sockaddr_un sunix;
63 * Allocate a port to handle incoming messages
65 port = caps_mkport(CAPT_SERVICE,
67 caps_service_waitport,
68 caps_service_replyport);
72 * Construct the unix domain socket.
74 if ((port->lfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
76 bzero(&sunix, sizeof(sunix));
77 sunix.sun_family = AF_UNIX;
79 snprintf(sunix.sun_path, sizeof(sunix.sun_path),
82 snprintf(sunix.sun_path, sizeof(sunix.sun_path),
83 CAPS_PATH2, (int)uid, name);
85 len = strlen(sunix.sun_path);
88 * If CAPS_EXCL is set do not allow duplicate registrations.
90 if (flags & CAPS_EXCL) {
91 error = connect(port->lfd, (void *)&sunix,
92 offsetof(struct sockaddr_un, sun_path[len+1]));
100 * Bind and listen on the port. Note: if the unix domain file
101 * is on a read-only filesystem the remove may fail.
103 remove(sunix.sun_path); /* XXX use create/rename for atomicy */
104 omask = umask(~modes & 0x0777);
105 error = bind(port->lfd, (void *)&sunix,
106 offsetof(struct sockaddr_un, sun_path[len+1]));
110 fcntl(port->lfd, F_SETFL, O_NONBLOCK);
111 if ((error = listen(port->lfd, 128)) < 0)
113 if ((port->kqfd = kqueue()) < 0)
117 * Use kqueue to get accept events on the listen descriptor
119 EV_SET(&kev, port->lfd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, port);
120 if (kevent(port->kqfd, &kev, 1, NULL, 0, NULL) < 0)
122 DBPRINTF(("Successfully created port %s\n", sunix.sun_path));
130 * Service kqueue events on a services port. Note that ports representing
131 * individual client connections aggregate their events onto the main services
135 caps_service_kev(struct kevent *kev)
137 caps_port_t port = kev->udata;
140 if (port->type == CAPT_SERVICE && kev->filter == EVFILT_READ) {
142 * Accept a new connection on the master service port
144 int fd = accept(port->lfd, NULL, 0);
148 rport = caps_mkport(CAPT_REMOTE,
150 caps_remote_waitport,
151 caps_remote_replyport);
152 rport->flags |= CAPPF_WAITCRED | CAPPF_ONLIST;
154 rport->server = port;
155 fcntl(port->cfd, F_SETFL, O_NONBLOCK);
156 /* note: use rport's mp_refs (1) to indicate ONLIST */
157 TAILQ_INSERT_TAIL(&port->clist, rport, centry);
158 EV_SET(kev, fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, rport);
159 if (kevent(port->kqfd, kev, 1, NULL, 0, NULL) < 0)
160 caps_shutdown(rport);
162 DBPRINTF(("accepted %d\n", fd));
165 } else if (port->type == CAPT_REMOTE && kev->filter == EVFILT_READ) {
166 msg = caps_kev_read(port);
167 } else if (port->type == CAPT_REMOTE && kev->filter == EVFILT_WRITE) {
168 caps_kev_write(port, NULL);
171 fprintf(stderr, "bad port: type %d flags %d\n", port->type, kev->filter);
180 * You can only reply to messages received on a services port. You cannot
181 * send a message to a services port (where would we send it?)
185 caps_service_putport(lwkt_port_t port, lwkt_msg_t msg)
191 * Wait for a new message to arrive. Since messages are not replied to
192 * services port msg must be NULL.
196 caps_service_waitport(lwkt_port_t lport, lwkt_msg_t msg)
202 if ((msg = TAILQ_FIRST(&lport->mp_msgq)) != NULL) {
203 TAILQ_REMOVE(&lport->mp_msgq, msg, ms_node);
206 port = (caps_port_t)lport;
209 while (kevent(port->kqfd, NULL, 0, &kev, 1, NULL) > 0) {
210 if ((msg = (lwkt_msg_t)caps_service_kev(&kev)) != NULL)
213 } while (errno == EINTR);
218 * A message's reply port is set to the port representing the connection
219 * the message came in on, not set to the services port. There should be
220 * no replies made to the services port.
224 caps_service_replyport(lwkt_port_t port, lwkt_msg_t msg)
230 * You can only reply to messages received on a services remote port.
231 * You cannot send a message to a services remote port. XXX future
232 * feature should allow the sending of unsolicited messagse to the remote
237 caps_remote_putport(lwkt_port_t port, lwkt_msg_t msg)
243 * Wait for a new message to arrive. Message waiting is done on the main
244 * services port, not on the per-client remote port. XXX as a future feature
245 * we could allow waiting for a message from a particular client.
249 caps_remote_waitport(lwkt_port_t lport, lwkt_msg_t msg)
256 * Messages received on the main services port are replied back to a
257 * port representing the particular connection the message actually
258 * came in on. If the port has been shutdown due to an error we have
259 * to destroy it when the last message reference goes away.
263 caps_remote_replyport(lwkt_port_t lport, lwkt_msg_t msg)
265 assert(lport->mp_refs > 0);
267 if (lport->mp_flags & CAPPF_SHUTDOWN) {
268 if (lport->mp_refs == 0) {
270 caps_close((caps_port_t)lport);
274 msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
275 caps_kev_write((caps_port_t)lport, msg);