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_client.c,v 1.2 2003/11/24 21:32:33 dillon Exp $
32 static lwkt_msg_t caps_client_kev(struct kevent *kev);
34 static int caps_client_putport(lwkt_port_t port, lwkt_msg_t msg);
35 static void *caps_client_waitport(lwkt_port_t port, lwkt_msg_t msg);
36 static void caps_client_replyport(lwkt_port_t port, lwkt_msg_t msg);
39 * Connect to a remote service message port.
41 * Use the standard lwkt_*() messaging functions to send messages and wait
44 * This code will eventually be replaced by a kernel API
47 caps_client(const char *name, uid_t uid, int flags)
49 struct sockaddr_un sunix;
56 * If uid is -1 first try our current uid, then try uid 0
58 if (uid == (uid_t)-1) {
60 if ((port = caps_client(name, uid, flags)) != NULL)
66 * Allocate a port to handle incoming messages
68 port = caps_mkport(CAPT_CLIENT,
71 caps_client_replyport);
74 * Construct the unix domain socket. If uid is -1 attempt to connect
75 * to the services UID for this process (use VARSYM variable?). XXX
78 if ((port->cfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
80 bzero(&sunix, sizeof(sunix));
81 sunix.sun_family = AF_UNIX;
83 snprintf(sunix.sun_path, sizeof(sunix.sun_path),
86 snprintf(sunix.sun_path, sizeof(sunix.sun_path),
87 CAPS_PATH2, (int)uid, name);
89 len = strlen(sunix.sun_path);
91 error = connect(port->cfd, (void *)&sunix,
92 offsetof(struct sockaddr_un, sun_path[len+1]));
96 if ((port->kqfd = kqueue()) < 0)
100 * The server expects a cred immediately.
103 struct msghdr msghdr;
104 struct caps_creds_cmsg cmsg;
106 bzero(&msghdr, sizeof(msghdr));
107 bzero(&cmsg, sizeof(cmsg));
108 msghdr.msg_control = &cmsg;
109 msghdr.msg_controllen = sizeof(cmsg);
110 cmsg.cmsg.cmsg_len = sizeof(cmsg);
111 cmsg.cmsg.cmsg_level = SOL_SOCKET;
112 cmsg.cmsg.cmsg_type = SCM_CREDS;
113 if (sendmsg(port->cfd, &msghdr, 0) < 0) {
118 fcntl(port->cfd, F_SETFL, O_NONBLOCK);
119 fcntl(port->cfd, F_SETFD, FD_CLOEXEC);
120 EV_SET(&kev, port->cfd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, port);
121 if (kevent(port->kqfd, &kev, 1, NULL, 0, NULL) < 0)
123 DBPRINTF(("Successfully created port %s\n", sunix.sun_path));
131 * Service kqueue events on a client port.
134 caps_client_kev(struct kevent *kev)
136 caps_port_t port = kev->udata;
139 if (port->type == CAPT_CLIENT) {
140 if (kev->filter == EVFILT_WRITE)
141 caps_kev_write(port, NULL);
142 if (kev->filter == EVFILT_READ) {
143 msg = caps_kev_read(port);
155 * You can only reply to messages received on a services port. You cannot
156 * send a message to a services port (where would we send it?)
160 caps_client_putport(lwkt_port_t port, lwkt_msg_t msg)
162 msg->ms_flags &= ~(MSGF_DONE | MSGF_REPLY);
163 caps_kev_write((caps_port_t)port, msg);
168 * Temporary hack until LWKT threading is integrated, because until then
169 * we can't wait on a normal LWKT port (the client's reply port)
172 caps_client_waitreply(caps_port_t port, lwkt_msg_t msg)
174 return(caps_client_waitport(&port->lport, msg));
178 * Wait for a new message to arrive. At the moment we expect only replies
179 * to previously sent messagse to be received.
183 caps_client_waitport(lwkt_port_t lport, lwkt_msg_t wmsg)
189 * Wait for any message or a particular message. If the message
190 * is available dequeue and return it.
193 wmsg = TAILQ_FIRST(&lport->mp_msgq);
194 if (wmsg && (wmsg->ms_flags & MSGF_DONE)) {
195 if (wmsg->ms_flags & MSGF_QUEUED) {
196 TAILQ_REMOVE(&lport->mp_msgq, wmsg, ms_node);
197 wmsg->ms_flags &= ~MSGF_QUEUED;
203 * Wait for any message or a particular message which is not yet
206 port = (caps_port_t)lport;
210 if (kevent(port->kqfd, NULL, 0, &kev, 1, NULL) <= 0) {
216 msg = caps_client_kev(&kev);
218 assert(msg->ms_flags & MSGF_DONE);
220 * Return the message we are looking for
222 if (msg == wmsg || wmsg == NULL) {
226 * Or save it for later retrieval
228 TAILQ_INSERT_TAIL(&lport->mp_msgq, msg, ms_node);
229 msg->ms_flags |= MSGF_QUEUED;
236 * A message's reply port is set to the port representing the connection
237 * the message came in on, not set to the services port. There should be
238 * no replies made to the services port.
242 caps_client_replyport(lwkt_port_t port, lwkt_msg_t msg)