2 Copyright (C) 2006-2022 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/>.
24 #include <sys/socket.h>
25 #ifdef HAVE_SYS_IOCTL_H
26 #include <sys/ioctl.h>
31 #ifdef HAVE_LINUX_SOCKIOS_H
32 #include <linux/sockios.h>
35 #ifdef HAVE_SYS_FILIO_H
36 #include <sys/filio.h>
39 #include "pwmd-error.h"
41 #include "util-misc.h"
43 #include "util-string.h"
49 send_status (assuan_context_t ctx
, status_msg_t which
, const char *fmt
, ...)
51 const char *line
= NULL
;
52 char buf
[ASSUAN_LINELENGTH
+ 1];
53 const char *status
= NULL
;
55 struct client_s
*client
= ctx
? assuan_get_pointer (ctx
) : NULL
;
64 vsnprintf (buf
, sizeof (buf
), fmt
, ap
);
72 case STATUS_REHANDSHAKE
:
73 status
= "REHANDSHAKE";
89 snprintf (buf
, sizeof (buf
), "%u", cache_file_count ());
94 MUTEX_LOCK (&cn_mutex
);
95 snprintf (buf
, sizeof (buf
), "%u", slist_length (cn_thread_list
));
97 MUTEX_UNLOCK (&cn_mutex
);
102 line
= _("Waiting for lock");
113 case STATUS_KEEPALIVE
:
114 status
= "KEEPALIVE";
128 log_write ("%s %s", status
, line
? line
: "");
133 if (client
&& client
->thd
->remote
&& which
== STATUS_KEEPALIVE
)
137 #ifdef HAVE_DECL_SIOCOUTQ
138 if (ioctl (client
->thd
->fd
, SIOCOUTQ
, &buffered
) == -1)
139 log_write ("%s(%i): ioctl: %s", __FUNCTION__
, __LINE__
,
140 pwmd_strerror (gpg_error_from_errno (errno
)));
141 #elif defined (HAVE_DECL_FIONWRITE)
142 if (ioctl (client
->thd
->fd
, FIONWRITE
, &buffered
) == -1)
143 log_write ("%s(%i): ioctl: %s", __FUNCTION__
, __LINE__
,
144 pwmd_strerror (gpg_error_from_errno (errno
)));
145 #elif !defined (HAVE_WINLIKE_SYSTEM)
149 socklen_t len
= sizeof(int);
151 if (getsockopt (client
->thd
->fd
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
,
153 log_write ("%s(%i): getsockopt: %s", __FUNCTION__
, __LINE__
,
154 pwmd_strerror (gpg_error_from_errno (errno
)));
160 if (getsockopt (client
->thd
->fd
, SOL_SOCKET
, SO_SNDLOWAT
,
162 log_write ("%s(%i): getsockopt: %s", __FUNCTION__
,
163 __LINE__
, pwmd_strerror (gpg_error_from_errno (errno
)));
167 if (setsockopt (client
->thd
->fd
, SOL_SOCKET
, SO_SNDLOWAT
,
169 log_write ("%s(%i): setsockopt: %s", __FUNCTION__
,
171 pwmd_strerror (gpg_error_from_errno (errno
)));
174 struct pollfd fds
[1];
177 fds
[0].fd
= client
->thd
->fd
;
178 fds
[0].events
= POLLOUT
;
180 buffered
= client
->thd
->last_buffer_size
+ 1;
181 n
= poll (fds
, 1, 0);
183 if (setsockopt (client
->thd
->fd
, SOL_SOCKET
, SO_SNDLOWAT
,
185 log_write ("%s(%i): setsockopt: %s", __FUNCTION__
,
187 pwmd_strerror (gpg_error_from_errno (errno
)));
188 if (n
> 0 && (fds
[0].revents
& POLLOUT
))
197 int interval
= config_get_integer ("global", "keepalive_interval");
198 int timeout
= config_get_integer ("global", "tls_timeout");
200 if (buffered
< client
->thd
->last_buffer_size
)
201 client
->thd
->buffer_timeout
= 0;
203 client
->thd
->last_buffer_size
= buffered
;
205 if (++client
->thd
->buffer_timeout
* interval
>= timeout
)
206 rc
= gpg_error (GPG_ERR_ETIMEDOUT
);
209 client
->thd
->buffer_timeout
= client
->thd
->last_buffer_size
= 0;
214 rc
= assuan_write_status (ctx
, status
, line
);
217 if (client
&& client
->thd
->remote
&& which
!= STATUS_KEEPALIVE
)
218 client
->thd
->buffer_timeout
= client
->thd
->last_buffer_size
= 0;
225 do_send_status_all (struct slist_s
*list
, status_msg_t s
,
226 const char *line
, pthread_t
*not_tid
)
229 int t
= slist_length (list
);
233 struct client_thread_s
*thd
= slist_nth_data (list
, i
);
234 struct status_msg_s
*msg
, *p
;
239 if (not_tid
&& pthread_equal (*not_tid
, thd
->tid
))
242 if (thd
->state
== CLIENT_STATE_UNKNOWN
243 || thd
->state
== CLIENT_STATE_DISCON
)
246 MUTEX_LOCK (&thd
->status_mutex
);
247 if (s
== STATUS_STATE
&& !thd
->send_state
)
249 MUTEX_UNLOCK (&thd
->status_mutex
);
253 pthread_cleanup_push (release_mutex_cb
, &thd
->status_mutex
);
255 for (p
= thd
->msg_queue
; p
; p
= p
->next
)
264 if (match
&& s
!= STATUS_STATE
)
267 p
->line
= line
? str_dup (line
) : NULL
;
269 if (!thd
->wrote_status
)
271 ssize_t ret
= write (thd
->status_msg_pipe
[1], &c
, 1);
273 rc
= gpg_error_from_syserror ();
275 log_write ("%s (%i): %s", __FUNCTION__
, __LINE__
,
279 thd
->wrote_status
= 1;
283 msg
= xcalloc (1, sizeof (struct status_msg_s
));
285 msg
->line
= line
? str_dup (line
) : NULL
;
287 for (p
= thd
->msg_queue
; p
&& p
->next
; p
= p
->next
);
289 thd
->msg_queue
= msg
;
293 if (!thd
->wrote_status
)
295 ssize_t ret
= write (thd
->status_msg_pipe
[1], &c
, 1);
297 rc
= gpg_error_from_syserror ();
299 log_write ("%s (%i): %s", __FUNCTION__
, __LINE__
,
303 thd
->wrote_status
= 1;
306 pthread_cleanup_pop (1);
311 send_status_all_not_self (status_msg_t s
, const char *fmt
, ...)
313 MUTEX_LOCK (&cn_mutex
);
315 pthread_t tid
= pthread_self ();
322 str_vasprintf (&line
, fmt
, ap
);
326 pthread_cleanup_push (release_mutex_cb
, &cn_mutex
);
327 pthread_cleanup_push (xfree
, line
);
328 do_send_status_all (cn_thread_list
, s
, line
, &tid
);
329 pthread_cleanup_pop (1);
330 pthread_cleanup_pop (1);
334 send_status_all (status_msg_t s
, const char *fmt
, ...)
336 MUTEX_LOCK (&cn_mutex
);
344 str_vasprintf (&line
, fmt
, ap
);
348 pthread_cleanup_push (release_mutex_cb
, &cn_mutex
);
349 pthread_cleanup_push (xfree
, line
);
350 do_send_status_all (cn_thread_list
, s
, line
, NULL
);
351 pthread_cleanup_pop (1);
352 pthread_cleanup_pop (1);
356 free_status_list (void *arg
)
358 struct slist_s
*list
= arg
;
364 send_status_modified (assuan_context_t ctx
)
366 MUTEX_LOCK (&cn_mutex
);
368 int t
= slist_length (cn_thread_list
);
369 struct slist_s
*list
= NULL
;
371 struct client_s
*client
= assuan_get_pointer (ctx
);
373 pthread_cleanup_push (release_mutex_cb
, &cn_mutex
);
378 struct client_thread_s
*thd
= slist_nth_data (cn_thread_list
, i
);
380 if (pthread_equal (client
->thd
->tid
, thd
->tid
))
383 if (thd
->cl
->filename
&& strcmp (thd
->cl
->filename
, client
->filename
))
385 else if (!thd
->cl
->filename
)
388 p
= slist_append (list
, thd
);
403 snprintf (line
, sizeof (line
), "%p", &client
->thd
->tid
);
404 pthread_cleanup_push (free_status_list
, list
);
405 do_send_status_all (list
, STATUS_MODIFIED
, line
, NULL
);
406 pthread_cleanup_pop (1);
409 pthread_cleanup_pop (1);