2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/socket.h>
28 #include <sys/ioctl.h>
32 #ifdef HAVE_LINUX_SOCKIOS_H
33 #include <linux/sockios.h>
36 #ifdef HAVE_SYS_FILIO_H
37 #include <sys/filio.h>
40 #include "pwmd-error.h"
42 #include "util-misc.h"
44 #include "util-string.h"
50 send_status (assuan_context_t ctx
, status_msg_t which
, const char *fmt
, ...)
52 const char *line
= NULL
;
53 char buf
[ASSUAN_LINELENGTH
+ 1];
54 const char *status
= NULL
;
56 struct client_s
*client
= ctx
? assuan_get_pointer (ctx
) : NULL
;
65 vsnprintf (buf
, sizeof (buf
), fmt
, ap
);
73 case STATUS_REHANDSHAKE
:
74 status
= "REHANDSHAKE";
87 snprintf (buf
, sizeof (buf
), "%u", cache_file_count ());
92 MUTEX_LOCK (&cn_mutex
);
93 snprintf (buf
, sizeof (buf
), "%u", slist_length (cn_thread_list
));
95 MUTEX_UNLOCK (&cn_mutex
);
100 line
= _("Waiting for lock");
111 case STATUS_KEEPALIVE
:
112 status
= "KEEPALIVE";
124 log_write ("%s %s", status
, line
? line
: "");
129 if (client
&& client
->thd
->remote
&& which
== STATUS_KEEPALIVE
)
133 #ifdef HAVE_DECL_SIOCOUTQ
134 if (ioctl (client
->thd
->fd
, SIOCOUTQ
, &buffered
) == -1)
135 log_write ("%s(%i): ioctl: %s", __FUNCTION__
, __LINE__
,
136 pwmd_strerror (gpg_error_from_errno (errno
)));
137 #elif defined (HAVE_DECL_FIONWRITE)
138 if (ioctl (client
->thd
->fd
, FIONWRITE
, &buffered
) == -1)
139 log_write ("%s(%i): ioctl: %s", __FUNCTION__
, __LINE__
,
140 pwmd_strerror (gpg_error_from_errno (errno
)));
145 socklen_t len
= sizeof(int);
147 if (getsockopt (client
->thd
->fd
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
,
149 log_write ("%s(%i): getsockopt: %s", __FUNCTION__
, __LINE__
,
150 pwmd_strerror (gpg_error_from_errno (errno
)));
156 if (getsockopt (client
->thd
->fd
, SOL_SOCKET
, SO_SNDLOWAT
,
158 log_write ("%s(%i): getsockopt: %s", __FUNCTION__
,
159 __LINE__
, pwmd_strerror (gpg_error_from_errno (errno
)));
163 if (setsockopt (client
->thd
->fd
, SOL_SOCKET
, SO_SNDLOWAT
,
165 log_write ("%s(%i): setsockopt: %s", __FUNCTION__
,
167 pwmd_strerror (gpg_error_from_errno (errno
)));
170 struct pollfd fds
[1];
173 fds
[0].fd
= client
->thd
->fd
;
174 fds
[0].events
= POLLOUT
;
176 buffered
= client
->thd
->last_buffer_size
+ 1;
177 n
= poll (fds
, 1, 0);
179 if (setsockopt (client
->thd
->fd
, SOL_SOCKET
, SO_SNDLOWAT
,
181 log_write ("%s(%i): setsockopt: %s", __FUNCTION__
,
183 pwmd_strerror (gpg_error_from_errno (errno
)));
184 if (n
> 0 && (fds
[0].revents
& POLLOUT
))
193 int interval
= config_get_integer ("global", "keepalive_interval");
194 int timeout
= config_get_integer ("global", "tls_timeout");
196 if (buffered
< client
->thd
->last_buffer_size
)
197 client
->thd
->buffer_timeout
= 0;
199 client
->thd
->last_buffer_size
= buffered
;
201 if (++client
->thd
->buffer_timeout
* interval
>= timeout
)
202 rc
= gpg_error (GPG_ERR_ETIMEDOUT
);
205 client
->thd
->buffer_timeout
= client
->thd
->last_buffer_size
= 0;
210 rc
= assuan_write_status (ctx
, status
, line
);
213 if (client
&& client
->thd
->remote
&& which
!= STATUS_KEEPALIVE
)
214 client
->thd
->buffer_timeout
= client
->thd
->last_buffer_size
= 0;
221 do_send_status_all (status_msg_t s
, const char *line
, pthread_t
*not_tid
)
223 MUTEX_LOCK (&cn_mutex
);
225 int t
= slist_length (cn_thread_list
);
227 pthread_cleanup_push (release_mutex_cb
, &cn_mutex
);
231 struct client_thread_s
*thd
= slist_nth_data (cn_thread_list
, i
);
232 struct status_msg_s
*msg
, *p
;
237 if (not_tid
&& pthread_equal (*not_tid
, thd
->tid
))
240 if (thd
->state
== CLIENT_STATE_UNKNOWN
241 || thd
->state
== CLIENT_STATE_DISCON
)
243 else if (s
== STATUS_STATE
&& !thd
->cl
->client_state
)
246 MUTEX_LOCK (&thd
->status_mutex
);
247 pthread_cleanup_push (release_mutex_cb
, &thd
->status_mutex
);
249 for (p
= thd
->msg_queue
; p
; p
= p
->next
)
258 if (match
&& s
!= STATUS_STATE
)
261 p
->line
= line
? str_dup (line
) : NULL
;
263 if (!thd
->wrote_status
)
265 ssize_t ret
= write (thd
->status_msg_pipe
[1], &c
, 1);
267 rc
= gpg_error_from_syserror ();
269 log_write ("%s (%i): %s", __FUNCTION__
, __LINE__
,
273 thd
->wrote_status
= 1;
277 msg
= xcalloc (1, sizeof (struct status_msg_s
));
279 msg
->line
= line
? str_dup (line
) : NULL
;
281 for (p
= thd
->msg_queue
; p
&& p
->next
; p
= p
->next
);
283 thd
->msg_queue
= msg
;
287 if (!thd
->wrote_status
)
289 ssize_t ret
= write (thd
->status_msg_pipe
[1], &c
, 1);
291 rc
= gpg_error_from_syserror ();
293 log_write ("%s (%i): %s", __FUNCTION__
, __LINE__
,
297 thd
->wrote_status
= 1;
300 pthread_cleanup_pop (1);
303 pthread_cleanup_pop (1);
307 send_status_all_not_self (status_msg_t s
, const char *fmt
, ...)
310 pthread_t tid
= pthread_self ();
317 str_vasprintf (&line
, fmt
, ap
);
321 pthread_cleanup_push (xfree
, line
);
322 do_send_status_all (s
, line
, &tid
);
323 pthread_cleanup_pop (1);
327 send_status_all (status_msg_t s
, const char *fmt
, ...)
336 str_vasprintf (&line
, fmt
, ap
);
340 pthread_cleanup_push (xfree
, line
);
341 do_send_status_all (s
, line
, NULL
);
342 pthread_cleanup_pop (1);