2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "error_notify_socket.h"
18 #include <sys/types.h>
20 #include <sys/socket.h>
26 #include <threading/thread.h>
27 #include <threading/mutex.h>
28 #include <collections/linked_list.h>
29 #include <processing/jobs/callback_job.h>
31 #include "error_notify_msg.h"
33 typedef struct private_error_notify_socket_t private_error_notify_socket_t
;
36 * Private data of an error_notify_socket_t object.
38 struct private_error_notify_socket_t
{
41 * Public error_notify_socket_t interface.
43 error_notify_socket_t
public;
46 * Unix socket file descriptor
51 * List of connected clients, as uintptr_t FD
53 linked_list_t
*connected
;
56 * Mutex to lock clients list
62 * Open error notify unix socket
64 static bool open_socket(private_error_notify_socket_t
*this)
66 struct sockaddr_un addr
;
69 addr
.sun_family
= AF_UNIX
;
70 strcpy(addr
.sun_path
, ERROR_NOTIFY_SOCKET
);
72 this->socket
= socket(AF_UNIX
, SOCK_SEQPACKET
, 0);
73 if (this->socket
== -1)
75 DBG1(DBG_CFG
, "creating notify socket failed");
78 unlink(addr
.sun_path
);
79 old
= umask(~(S_IRWXU
| S_IRWXG
));
80 if (bind(this->socket
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
82 DBG1(DBG_CFG
, "binding notify socket failed: %s", strerror(errno
));
87 if (chown(addr
.sun_path
, charon
->caps
->get_uid(charon
->caps
),
88 charon
->caps
->get_gid(charon
->caps
)) != 0)
90 DBG1(DBG_CFG
, "changing notify socket permissions failed: %s",
93 if (listen(this->socket
, 10) < 0)
95 DBG1(DBG_CFG
, "listening on notify socket failed: %s", strerror(errno
));
97 unlink(addr
.sun_path
);
103 METHOD(error_notify_socket_t
, has_listeners
, bool,
104 private_error_notify_socket_t
*this)
108 this->mutex
->lock(this->mutex
);
109 count
= this->connected
->get_count(this->connected
);
110 this->mutex
->unlock(this->mutex
);
115 METHOD(error_notify_socket_t
, notify
, void,
116 private_error_notify_socket_t
*this, error_notify_msg_t
*msg
)
118 enumerator_t
*enumerator
;
121 this->mutex
->lock(this->mutex
);
122 enumerator
= this->connected
->create_enumerator(this->connected
);
123 while (enumerator
->enumerate(enumerator
, (void*)&fd
))
125 while (send(fd
, msg
, sizeof(*msg
), 0) <= 0)
133 /* disconnect, remove this listener */
134 this->connected
->remove_at(this->connected
, enumerator
);
138 DBG1(DBG_CFG
, "sending notify failed: %s", strerror(errno
));
144 enumerator
->destroy(enumerator
);
145 this->mutex
->unlock(this->mutex
);
149 * Accept client connections, dispatch
151 static job_requeue_t
accept_(private_error_notify_socket_t
*this)
153 struct sockaddr_un addr
;
158 oldstate
= thread_cancelability(TRUE
);
159 fd
= accept(this->socket
, (struct sockaddr
*)&addr
, &len
);
160 thread_cancelability(oldstate
);
164 this->mutex
->lock(this->mutex
);
165 this->connected
->insert_last(this->connected
, (void*)(uintptr_t)fd
);
166 this->mutex
->unlock(this->mutex
);
170 DBG1(DBG_CFG
, "accepting notify connection failed: %s",
173 return JOB_REQUEUE_DIRECT
;
176 METHOD(error_notify_socket_t
, destroy
, void,
177 private_error_notify_socket_t
*this)
179 this->connected
->destroy(this->connected
);
180 this->mutex
->destroy(this->mutex
);
188 error_notify_socket_t
*error_notify_socket_create()
190 private_error_notify_socket_t
*this;
195 .has_listeners
= _has_listeners
,
198 .connected
= linked_list_create(),
199 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
202 if (!open_socket(this))
208 lib
->processor
->queue_job(lib
->processor
,
209 (job_t
*)callback_job_create_with_prio((callback_job_cb_t
)accept_
, this,
210 NULL
, (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
212 return &this->public;