1 /* this file is #include'd by service.c */
3 static int num_sox = 0;
4 static struct soxinfo soxinfo [1024];
5 static struct pollfd soxpoll [1024];
7 /* Register a socket. It is assumed that first all server sockets register */
8 static void register_socket (pool_handle_t sox, uint32_t soxinfo_flags) {
9 int flags = fcntl (sox, F_GETFD);
11 fcntl (sox, F_SETFD, flags);
12 //TODO// if (soxinfo == NULL) {
13 //TODO// soxinfo = calloc ()
15 if (num_sox == 1024) {
16 tlog (TLOG_UNIXSOCK, LOG_CRIT, "Cannot allocate more than 1024 server sockets");
19 soxpoll [num_sox].fd = sox;
20 soxpoll [num_sox].events = POLLIN;
21 soxpoll [num_sox].revents = 0;
22 soxinfo [num_sox].flags = soxinfo_flags;
23 soxinfo [num_sox].cbq = NULL;
27 /* TODO: This may copy information back and thereby avoid processing in the
28 * current loop passthrough. No problem, poll() will show it once more. */
29 static void unregister_client_socket_byindex (int soxidx) {
30 pool_handle_t sox = soxpoll [soxidx].fd;
31 free_callbacks_by_clientfd (sox);
32 free_commands_by_clientfd (sox);
33 pinentry_forget_clientfd (sox);
34 lidentry_forget_clientfd (sox);
35 ctlkey_close_ctlfd (sox);
37 if (soxidx < num_sox) {
38 memcpy (&soxinfo [soxidx], &soxinfo [num_sox], sizeof (*soxinfo));
39 memcpy (&soxpoll [soxidx], &soxpoll [num_sox], sizeof (*soxpoll));
43 static int os_send_command (struct command *cmd, int passfd)
45 char anc [CMSG_SPACE(sizeof (int))];
50 memset (anc, 0, sizeof (anc));
51 memset (&iov, 0, sizeof (iov));
52 memset (&mh, 0, sizeof (mh));
53 iov.iov_base = &cmd->cmd;
54 iov.iov_len = sizeof (cmd->cmd);
59 mh.msg_controllen = sizeof (anc);
60 cmsg = CMSG_FIRSTHDR (&mh);
61 cmsg->cmsg_level = SOL_SOCKET;
62 cmsg->cmsg_type = SCM_RIGHTS;
63 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
64 * (int *) CMSG_DATA (cmsg) = passfd;
66 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Sending command 0x%08x and fd %d to socket %d", cmd->cmd.pio_cmd, passfd, (int) cmd->clientfd);
67 if (sendmsg (cmd->clientfd, &mh, MSG_NOSIGNAL) == -1) {
68 //TODO// Differentiate behaviour based on errno?
69 perror ("Failed to send command");
72 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Sent command code 0x%08x", cmd->cmd.pio_cmd);
77 /* Receive a command. Return nonzero on success, zero on failure. */
78 static int receive_command (pool_handle_t sox, struct command *cmd) {
81 char anc [CMSG_SPACE (sizeof (int))];
83 struct msghdr mh = { 0 };
86 iov.iov_base = &cmd->cmd;
87 iov.iov_len = sizeof (cmd->cmd);
91 mh.msg_controllen = sizeof (anc);
93 if (recvmsg (sox, &mh, MSG_NOSIGNAL) == -1) {
94 //TODO// Differentiate behaviour based on errno?
95 perror ("Failed to receive command");
98 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Received command request code 0x%08x with cbid=%d over fd=%d", cmd->cmd.pio_cmd, cmd->cmd.pio_cbid, sox);
100 cmsg = CMSG_FIRSTHDR (&mh);
101 //TODO// It is more general to look at all FDs passed, close all 2+
102 if (cmsg && (cmsg->cmsg_len == CMSG_LEN (sizeof (int)))) {
103 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_RIGHTS)) {
104 if (cmd->passfd == -1) {
105 cmd->passfd = * (int *) CMSG_DATA (cmsg);
106 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Received file descriptor as %d", cmd->passfd);
108 int superfd = * (int *) CMSG_DATA (cmsg);
109 tlog (TLOG_UNIXSOCK, LOG_ERR, "Received superfluous file descriptor as %d", superfd);
113 cmsg = CMSG_NXTHDR (&mh, cmsg);
119 void register_server_socket (pool_handle_t srvsox) {
120 register_socket (srvsox, SOF_SERVER);
124 void register_client_socket (pool_handle_t clisox) {
125 register_socket (clisox, SOF_CLIENT);
128 /* Pickup on activity and process it. Processing may mean a number of things:
129 * - to try an accept() on a server socket (ignoring it upon EAGAIN)
130 * - to trigger a thread that is hoping writing after EAGAIN
131 * - to read a message and further process it
133 void process_activity (pool_handle_t sox, int soxidx, struct soxinfo *soxi, short int revents) {
134 if (revents & POLLOUT) {
135 //TODO// signal waiting thread that it may continue
136 tlog (TLOG_UNIXSOCK, LOG_CRIT, "Eekk!! Could send a packet?!? Unregistering client");
137 unregister_client_socket_byindex (soxidx);
138 tlspool_close_poolhandle (sox);
140 if (revents & POLLIN) {
141 if (soxi->flags & SOF_SERVER) {
143 socklen_t salen = sizeof (sa);
144 pool_handle_t newsox = accept (sox, &sa, &salen);
145 if (newsox != INVALID_POOL_HANDLE) {
146 tlog (TLOG_UNIXSOCK, LOG_NOTICE, "Received incoming connection. Registering it");
147 register_client_socket (newsox);
150 if (soxi->flags & SOF_CLIENT) {
151 struct command *cmd = allocate_command_for_clientfd (sox);
152 if (receive_command (sox, cmd)) {
153 process_command (cmd);
155 tlog (TLOG_UNIXSOCK, LOG_ERR, "Failed to receive command request");
161 static void os_run_service ()
165 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Polling %d sockets numbered %d, %d, %d, ...", num_sox, soxpoll [0].fd, soxpoll [1].fd, soxpoll [2].fd);
166 while (polled = poll (soxpoll, num_sox, -1), polled > 0) {
167 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Polled %d sockets, returned %d", num_sox, polled);
168 for (i=0; i<num_sox; i++) {
169 if (soxpoll [i].revents & (POLLHUP|POLLERR|POLLNVAL)) {
170 pool_handle_t sox = soxpoll [i].fd;
171 tlog (TLOG_UNIXSOCK, LOG_NOTICE, "Unregistering socket %d", sox);
172 unregister_client_socket_byindex (i);
175 } else if (soxpoll [i].revents) {
176 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Socket %d has revents=%d", soxpoll [i].fd, soxpoll [i].revents);
177 process_activity (soxpoll [i].fd, i, &soxinfo [i], soxpoll [i].revents);
180 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Polling %d sockets numbered %d, %d, %d, ...", num_sox, soxpoll [0].fd, soxpoll [1].fd, soxpoll [2].fd);
183 tlog (TLOG_UNIXSOCK, LOG_NOTICE, "Service hangup in response to request");
185 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Polled %d sockets, returned %d", num_sox, polled);
186 perror ("Failed to poll for activity");