Remove string*_large() and add string_large().
[pwmd.git] / src / status.c
blob25e009fea720ed43d8ab60a7951df3cf5df5dd7a
1 /*
2 Copyright (C) 2006-2021 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 Pwmd is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <pthread.h>
23 #include <stdarg.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #include <errno.h>
27 #include <poll.h>
29 #ifdef HAVE_LINUX_SOCKIOS_H
30 #include <linux/sockios.h>
31 #endif
33 #ifdef HAVE_SYS_FILIO_H
34 #include <sys/filio.h>
35 #endif
37 #include "pwmd-error.h"
38 #include "mutex.h"
39 #include "util-misc.h"
40 #include "common.h"
41 #include "util-string.h"
42 #include "status.h"
43 #include "cache.h"
44 #include "mem.h"
46 gpg_error_t
47 send_status (assuan_context_t ctx, status_msg_t which, const char *fmt, ...)
49 const char *line = NULL;
50 char buf[ASSUAN_LINELENGTH + 1];
51 const char *status = NULL;
52 #ifdef WITH_GNUTLS
53 struct client_s *client = ctx ? assuan_get_pointer (ctx) : NULL;
54 #endif
55 gpg_error_t rc = 0;
57 if (fmt)
59 va_list ap;
61 va_start (ap, fmt);
62 vsnprintf (buf, sizeof (buf), fmt, ap);
63 va_end (ap);
64 line = buf;
67 switch (which)
69 #ifdef WITH_GNUTLS
70 case STATUS_REHANDSHAKE:
71 status = "REHANDSHAKE";
72 break;
73 #endif
74 case STATUS_EXPIRE:
75 status = "EXPIRE";
76 break;
77 case STATUS_GENKEY:
78 status = "GENKEY";
79 break;
80 case STATUS_XFER:
81 status = "XFER";
82 break;
83 case STATUS_CACHE:
84 snprintf (buf, sizeof (buf), "%u", cache_file_count ());
85 line = buf;
86 status = "CACHE";
87 break;
88 case STATUS_CLIENTS:
89 MUTEX_LOCK (&cn_mutex);
90 snprintf (buf, sizeof (buf), "%u", slist_length (cn_thread_list));
91 line = buf;
92 MUTEX_UNLOCK (&cn_mutex);
93 status = "CLIENTS";
94 break;
95 case STATUS_LOCKED:
96 status = "LOCKED";
97 line = _("Waiting for lock");
98 break;
99 case STATUS_ENCRYPT:
100 status = "ENCRYPT";
101 break;
102 case STATUS_DECRYPT:
103 status = "DECRYPT";
104 break;
105 case STATUS_NEWFILE:
106 status = "NEWFILE";
107 break;
108 case STATUS_KEEPALIVE:
109 status = "KEEPALIVE";
110 break;
111 case STATUS_GPGME:
112 status = "GPGME";
113 break;
114 case STATUS_STATE:
115 status = "STATE";
116 break;
117 case STATUS_BULK:
118 status = "BULK";
121 if (!ctx)
123 log_write ("%s %s", status, line ? line : "");
124 return 0;
127 #ifdef WITH_GNUTLS
128 if (client && client->thd->remote && which == STATUS_KEEPALIVE)
130 int buffered = 0;
132 #ifdef HAVE_DECL_SIOCOUTQ
133 if (ioctl (client->thd->fd, SIOCOUTQ, &buffered) == -1)
134 log_write ("%s(%i): ioctl: %s", __FUNCTION__, __LINE__,
135 pwmd_strerror (gpg_error_from_errno (errno)));
136 #elif defined (HAVE_DECL_FIONWRITE)
137 if (ioctl (client->thd->fd, FIONWRITE, &buffered) == -1)
138 log_write ("%s(%i): ioctl: %s", __FUNCTION__, __LINE__,
139 pwmd_strerror (gpg_error_from_errno (errno)));
140 #elif !defined (HAVE_WINLIKE_SYSTEM)
141 if (1)
143 int sndbuf;
144 socklen_t len = sizeof(int);
146 if (getsockopt (client->thd->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
147 &len) == -1)
148 log_write ("%s(%i): getsockopt: %s", __FUNCTION__, __LINE__,
149 pwmd_strerror (gpg_error_from_errno (errno)));
150 else
152 int lowat;
154 len = sizeof(int);
155 if (getsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
156 &lowat, &len) == -1)
157 log_write ("%s(%i): getsockopt: %s", __FUNCTION__,
158 __LINE__, pwmd_strerror (gpg_error_from_errno (errno)));
159 else
161 len = sizeof(int);
162 if (setsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
163 &sndbuf, len) == -1)
164 log_write ("%s(%i): setsockopt: %s", __FUNCTION__,
165 __LINE__,
166 pwmd_strerror (gpg_error_from_errno (errno)));
167 else
169 struct pollfd fds[1];
170 int n;
172 fds[0].fd = client->thd->fd;
173 fds[0].events = POLLOUT;
175 buffered = client->thd->last_buffer_size + 1;
176 n = poll (fds, 1, 0);
177 len = sizeof(int);
178 if (setsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
179 &lowat, len) == -1)
180 log_write ("%s(%i): setsockopt: %s", __FUNCTION__,
181 __LINE__,
182 pwmd_strerror (gpg_error_from_errno (errno)));
183 if (n > 0 && (fds[0].revents & POLLOUT))
184 buffered = 0;
189 #endif
190 if (buffered)
192 int interval = config_get_integer ("global", "keepalive_interval");
193 int timeout = config_get_integer ("global", "tls_timeout");
195 if (buffered < client->thd->last_buffer_size)
196 client->thd->buffer_timeout = 0;
198 client->thd->last_buffer_size = buffered;
200 if (++client->thd->buffer_timeout * interval >= timeout)
201 rc = gpg_error (GPG_ERR_ETIMEDOUT);
203 else
204 client->thd->buffer_timeout = client->thd->last_buffer_size = 0;
206 #endif
208 if (!rc)
209 rc = assuan_write_status (ctx, status, line);
211 #ifdef WITH_GNUTLS
212 if (client && client->thd->remote && which != STATUS_KEEPALIVE)
213 client->thd->buffer_timeout = client->thd->last_buffer_size = 0;
214 #endif
216 return rc;
219 static void
220 do_send_status_all (status_msg_t s, const char *line, pthread_t *not_tid)
222 MUTEX_LOCK (&cn_mutex);
223 int i = 0;
224 int t = slist_length (cn_thread_list);
226 pthread_cleanup_push (release_mutex_cb, &cn_mutex);
228 for (; i < t; i++)
230 struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
231 struct status_msg_s *msg, *p;
232 char c = 0xff;
233 int match = 0;
234 gpg_error_t rc;
236 if (not_tid && pthread_equal (*not_tid, thd->tid))
237 continue;
239 if (thd->state == CLIENT_STATE_UNKNOWN
240 || thd->state == CLIENT_STATE_DISCON)
241 continue;
243 MUTEX_LOCK (&thd->status_mutex);
244 if (s == STATUS_STATE && !thd->cl->client_state)
246 MUTEX_UNLOCK (&thd->status_mutex);
247 continue;
250 pthread_cleanup_push (release_mutex_cb, &thd->status_mutex);
252 for (p = thd->msg_queue; p; p = p->next)
254 if (p->s == s)
256 match = 1;
257 break;
261 if (match && s != STATUS_STATE)
263 xfree (p->line);
264 p->line = line ? str_dup (line) : NULL;
266 if (!thd->wrote_status)
268 ssize_t ret = write (thd->status_msg_pipe[1], &c, 1);
270 rc = gpg_error_from_syserror ();
271 if (ret == -1)
272 log_write ("%s (%i): %s", __FUNCTION__, __LINE__,
273 pwmd_strerror (rc));
276 thd->wrote_status = 1;
278 else
280 msg = xcalloc (1, sizeof (struct status_msg_s));
281 msg->s = s;
282 msg->line = line ? str_dup (line) : NULL;
284 for (p = thd->msg_queue; p && p->next; p = p->next);
285 if (!p)
286 thd->msg_queue = msg;
287 else
288 p->next = msg;
290 if (!thd->wrote_status)
292 ssize_t ret = write (thd->status_msg_pipe[1], &c, 1);
294 rc = gpg_error_from_syserror ();
295 if (ret == -1)
296 log_write ("%s (%i): %s", __FUNCTION__, __LINE__,
297 pwmd_strerror (rc));
300 thd->wrote_status = 1;
303 pthread_cleanup_pop (1);
306 pthread_cleanup_pop (1);
309 void
310 send_status_all_not_self (status_msg_t s, const char *fmt, ...)
312 char *line = NULL;
313 pthread_t tid = pthread_self ();
315 if (fmt)
317 va_list ap;
319 va_start (ap, fmt);
320 str_vasprintf (&line, fmt, ap);
321 va_end (ap);
324 pthread_cleanup_push (xfree, line);
325 do_send_status_all (s, line, &tid);
326 pthread_cleanup_pop (1);
329 void
330 send_status_all (status_msg_t s, const char *fmt, ...)
332 char *line = NULL;
334 if (fmt)
336 va_list ap;
338 va_start (ap, fmt);
339 str_vasprintf (&line, fmt, ap);
340 va_end (ap);
343 pthread_cleanup_push (xfree, line);
344 do_send_status_all (s, line, NULL);
345 pthread_cleanup_pop (1);