Recreate doc/pwmd.html after 'make distclean'.
[pwmd.git] / src / status.c
blobe5a7853aea105f59746ec7a004b15ea0ac60abc2
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <pthread.h>
25 #include <stdarg.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.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 va_list ap;
53 char *p;
54 #ifdef WITH_GNUTLS
55 struct client_s *client = ctx ? assuan_get_pointer (ctx) : NULL;
56 #endif
57 gpg_error_t rc = 0;
59 if (fmt)
61 va_start (ap, fmt);
62 vsnprintf (buf, sizeof (buf), fmt, ap);
63 va_end (ap);
64 line = buf;
67 switch (which)
69 case STATUS_GENKEY:
70 status = "GENKEY";
71 break;
72 case STATUS_XFER:
73 status = "XFER";
74 break;
75 case STATUS_CACHE:
76 snprintf (buf, sizeof (buf), "%u", cache_file_count ());
77 line = buf;
78 status = "CACHE";
79 break;
80 case STATUS_CLIENTS:
81 MUTEX_LOCK (&cn_mutex);
82 snprintf (buf, sizeof (buf), "%i", slist_length (cn_thread_list));
83 line = buf;
84 MUTEX_UNLOCK (&cn_mutex);
85 status = "CLIENTS";
86 break;
87 case STATUS_LOCKED:
88 status = "LOCKED";
89 line = _("Waiting for lock");
90 break;
91 case STATUS_ENCRYPT:
92 status = "ENCRYPT";
93 break;
94 case STATUS_DECRYPT:
95 status = "DECRYPT";
96 break;
97 case STATUS_NEWFILE:
98 status = "NEWFILE";
99 break;
100 case STATUS_KEEPALIVE:
101 status = "KEEPALIVE";
102 break;
103 case STATUS_AGENT:
104 p = strchr (line, ' ');
105 if (!p)
107 status = line;
108 line = NULL;
110 else
112 *p = 0;
113 status = line;
114 line = line + strlen (status) + 1;
116 break;
119 if (!ctx)
121 log_write ("%s %s", status, line ? line : "");
122 return 0;
125 #ifdef WITH_GNUTLS
126 if (client->thd->remote && which == STATUS_KEEPALIVE)
128 int buffered = 0;
130 #ifdef HAVE_DECL_SIOCOUTQ
131 if (ioctl (client->thd->fd, SIOCOUTQ, &buffered) == -1)
132 log_write ("%s(%i): ioctl: %s", __FUNCTION__, __LINE__,
133 pwmd_strerror (gpg_error_from_syserror ()));
134 #elif defined (HAVE_DECL_FIONWRITE)
135 if (ioctl (client->thd->fd, FIONWRITE, &buffered) == -1)
136 log_write ("%s(%i): ioctl: %s", __FUNCTION__, __LINE__,
137 pwmd_strerror (gpg_error_from_syserror ()));
138 #else
139 if (1)
141 int sndbuf;
142 socklen_t len = sizeof(int);
144 if (getsockopt (client->thd->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
145 &len) == -1)
146 log_write ("%s(%i): getsockopt: %s", __FUNCTION__, __LINE__,
147 pwmd_strerror (gpg_error_from_syserror ()));
148 else
150 int lowat;
152 len = sizeof(int);
153 if (getsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
154 &lowat, &len) == -1)
155 log_write ("%s(%i): getsockopt: %s", __FUNCTION__,
156 __LINE__, pwmd_strerror (gpg_error_from_syserror ()));
157 else
159 len = sizeof(int);
160 if (setsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
161 &sndbuf, len) == -1)
162 log_write ("%s(%i): setsockopt: %s", __FUNCTION__,
163 __LINE__,
164 pwmd_strerror (gpg_error_from_syserror ()));
165 else
167 struct timeval tv = { 0, 0 };
168 fd_set wfds;
169 int n;
171 buffered = client->thd->last_buffer_size + 1;
172 FD_ZERO (&wfds);
173 FD_SET (client->thd->fd, &wfds);
174 n = select (client->thd->fd + 1, NULL, &wfds, NULL, &tv);
175 len = sizeof(int);
176 if (setsockopt (client->thd->fd, SOL_SOCKET, SO_SNDLOWAT,
177 &lowat, len) == -1)
178 log_write ("%s(%i): setsockopt: %s", __FUNCTION__,
179 __LINE__,
180 pwmd_strerror (gpg_error_from_syserror ()));
181 if (n > 0 && FD_ISSET (client->thd->fd, &wfds))
182 buffered = 0;
187 #endif
188 if (buffered)
190 int interval = config_get_integer ("global", "keepalive_interval");
191 int timeout = config_get_integer ("global", "tls_timeout");
193 if (buffered < client->thd->last_buffer_size)
194 client->thd->buffer_timeout = 0;
196 client->thd->last_buffer_size = buffered;
198 if (++client->thd->buffer_timeout * interval >= timeout)
199 rc = gpg_error (GPG_ERR_ETIMEDOUT);
201 else
202 client->thd->buffer_timeout = client->thd->last_buffer_size = 0;
204 #endif
206 if (!rc)
207 rc = assuan_write_status (ctx, status, line);
209 #ifdef WITH_GNUTLS
210 if (client->thd->remote && which != STATUS_KEEPALIVE)
211 client->thd->buffer_timeout = client->thd->last_buffer_size = 0;
212 #endif
214 return rc;
217 void
218 send_status_all (status_msg_t s, const char *fmt, ...)
220 MUTEX_LOCK (&cn_mutex);
221 int i = 0;
222 int t = slist_length (cn_thread_list);
224 for (; i < t; i++)
226 struct client_thread_s *thd = slist_nth_data (cn_thread_list, i);
227 struct status_msg_s *msg, *p;
228 char c = 0xff;
229 int match = 0;
231 MUTEX_LOCK (&thd->status_mutex);
233 for (p = thd->msg_queue; p; p = p->next)
235 if (p->s == s)
237 match = 1;
238 break;
242 if (match)
244 MUTEX_UNLOCK (&thd->status_mutex);
245 continue;
248 msg = xcalloc (1, sizeof (struct status_msg_s));
249 msg->s = s;
250 if (fmt)
252 va_list ap;
254 va_start (ap, fmt);
255 str_vasprintf (&msg->line, fmt, ap);
256 va_end (ap);
259 for (p = thd->msg_queue; p && p->next; p = p->next);
260 if (!p)
261 thd->msg_queue = msg;
262 else
263 p->next = msg;
265 write (thd->status_msg_pipe[1], &c, 1);
266 MUTEX_UNLOCK (&thd->status_mutex);
269 MUTEX_UNLOCK (&cn_mutex);