1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program 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 this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
24 #include "pwmd_error.h"
26 struct status_thread_s
{
35 static void cleanup(void *arg
)
37 struct status_thread_s
*s
= arg
;
44 pth_event_free(s
->ev
, PTH_FREE_ALL
);
48 static void *write_status_thread(void *arg
)
50 struct status_thread_s
*s
= arg
;
52 pth_attr_t attr
= pth_attr_of(pth_self());
54 pth_attr_set(attr
, PTH_ATTR_NAME
, __FUNCTION__
);
55 pth_attr_destroy(attr
);
56 pth_cancel_state(PTH_CANCEL_ASYNCHRONOUS
, NULL
);
57 rc
= assuan_write_status(s
->ctx
, s
->status
, s
->line
);
58 pth_write(s
->fd
[1], &rc
, sizeof(gpg_error_t
));
62 gpg_error_t
send_status(assuan_context_t ctx
, status_msg_t which
,
63 const gchar
*fmt
, ...)
65 const gchar
*line
= NULL
;
66 gchar buf
[ASSUAN_LINELENGTH
];
71 struct status_thread_s
*s
;
72 gint to
= get_key_file_integer("global", "keepalive");
79 g_vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
86 CACHE_LOCK(client
->ctx
);
87 line
= print_fmt(buf
, sizeof(buf
), "%i", cache_file_count());
92 MUTEX_LOCK(&cn_mutex
);
93 line
= print_fmt(buf
, sizeof(buf
), "%i", g_slist_length(cn_thread_list
));
94 MUTEX_UNLOCK(&cn_mutex
);
100 case STATUS_KEEPALIVE
:
101 status
= "KEEPALIVE";
105 line
= N_("Waiting for lock");
113 case STATUS_DECOMPRESS
:
114 status
= "DECOMPRESS";
116 case STATUS_COMPRESS
:
122 log_write("%s %s", status
, line
);
126 s
= g_malloc0(sizeof(struct status_thread_s
));
129 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
130 return gpg_error_from_errno(ENOMEM
);
137 if (pipe(s
->fd
) == -1) {
140 return gpg_error_from_errno(n
);
143 pth_cleanup_push(cleanup
, s
);
144 /* Since we use the keepalive from the configuration, it may be 0. If so,
145 * status messages would fail and abort the connection. So use a default
146 * that doesn't affect the configured keepalive value. */
147 to
= to
<= 0 ? DEFAULT_KEEPALIVE_TO
: to
;
148 s
->ev
= pth_event(PTH_EVENT_FD
|PTH_UNTIL_FD_READABLE
, s
->fd
[0]);
149 tev
= pth_event(PTH_EVENT_TIME
, pth_timeout(to
, 0));
150 s
->ev
= pth_event_concat(s
->ev
, tev
, NULL
);
151 attr
= pth_attr_new();
153 pth_attr_set(attr
, PTH_ATTR_JOINABLE
, FALSE
);
154 s
->tid
= pth_spawn(attr
, write_status_thread
, s
);
156 pth_attr_destroy(attr
);
158 st
= pth_event_status(s
->ev
);
160 if (st
== PTH_STATUS_FAILED
) {
163 rc
= GPG_ERR_ASS_WRITE_ERROR
;
165 else if (st
== PTH_STATUS_OCCURRED
) {
166 size_t len
= pth_read(s
->fd
[0], &rc
, sizeof(gpg_error_t
));
168 if (len
!= sizeof(gpg_error_t
)) {
169 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(errno
));
170 rc
= GPG_ERR_ASS_WRITE_ERROR
;
176 st
= pth_event_status(tev
);
178 if (st
== PTH_STATUS_OCCURRED
) {
181 rc
= GPG_ERR_ASS_WRITE_ERROR
;
189 static void *do_send_status(void *arg
)
191 struct client_s
*cl
= arg
;
194 rc
= send_status(cl
->ctx
, cl
->msg
, NULL
);
195 pth_exit((void *)rc
);
199 void *client_msg_thread(void *arg
)
201 struct client_thread_s
*thd
= arg
;
203 pth_attr_t attr
= pth_attr_of(pth_self());
205 pth_attr_set(attr
, PTH_ATTR_NAME
, __FUNCTION__
);
206 pth_attr_destroy(attr
);
208 pth_cond_init(&thd
->msg_cond
);
209 pth_mutex_acquire(&m
, FALSE
, NULL
);
212 pth_cond_await(&thd
->msg_cond
, &m
, NULL
);
220 MUTEX_LOCK(&thd
->msg_list_mutex
);
221 msg
= g_slist_nth_data(thd
->msg_list
, 0);
224 thd
->msg_list
= g_slist_remove(thd
->msg_list
, msg
);
226 MUTEX_UNLOCK(&thd
->msg_list_mutex
);
233 tid
= pth_spawn(NULL
, do_send_status
, thd
->cl
);
235 pth_join(tid
, (void **)&rc
);
239 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(rc
));
240 pth_cancel(thd
->tid
);
249 static gboolean
msg_list_dup(GSList
*list
, status_msg_t which
)
253 for (t
= g_slist_length(list
), i
= 0; i
< t
; i
++) {
254 status_msg_t
*m
= g_slist_nth_data(list
, i
);
263 void send_status_all(status_msg_t which
)
267 MUTEX_LOCK(&cn_mutex
);
269 for (t
= g_slist_length(cn_thread_list
), i
= 0; i
< t
; i
++) {
270 struct client_thread_s
*cn
= g_slist_nth_data(cn_thread_list
, i
);
273 if (msg_list_dup(cn
->msg_list
, which
))
276 m
= g_malloc(sizeof(status_msg_t
));
279 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
284 MUTEX_LOCK(&cn
->msg_list_mutex
);
285 cn
->msg_list
= g_slist_append(cn
->msg_list
, m
);
286 MUTEX_UNLOCK(&cn
->msg_list_mutex
);
287 pth_cond_notify(&cn
->msg_cond
, FALSE
);
290 MUTEX_UNLOCK(&cn_mutex
);