Use CRITICAL job priority class for long running dispatcher jobs
[strongswan.git] / src / libcharon / plugins / duplicheck / duplicheck_notify.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "duplicheck_notify.h"
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <unistd.h>
23 #include <errno.h>
24
25 #include <daemon.h>
26 #include <threading/mutex.h>
27 #include <threading/thread.h>
28 #include <utils/linked_list.h>
29 #include <processing/jobs/callback_job.h>
30
31 #define DUPLICHECK_SOCKET IPSEC_PIDDIR "/charon.dck"
32
33 typedef struct private_duplicheck_notify_t private_duplicheck_notify_t;
34
35 /**
36 * Private data of an duplicheck_notify_t object.
37 */
38 struct private_duplicheck_notify_t {
39
40 /**
41 * Public duplicheck_notify_t interface.
42 */
43 duplicheck_notify_t public;
44
45 /**
46 * Callback job dispatching connections
47 */
48 callback_job_t *job;
49
50 /**
51 * Mutex to lock list
52 */
53 mutex_t *mutex;
54
55 /**
56 * List of connected sockets
57 */
58 linked_list_t *connected;
59
60 /**
61 * Socket dispatching connections
62 */
63 int socket;
64 };
65
66 /**
67 * Open duplicheck unix socket
68 */
69 static bool open_socket(private_duplicheck_notify_t *this)
70 {
71 struct sockaddr_un addr;
72 mode_t old;
73
74 addr.sun_family = AF_UNIX;
75 strcpy(addr.sun_path, DUPLICHECK_SOCKET);
76
77 this->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
78 if (this->socket == -1)
79 {
80 DBG1(DBG_CFG, "creating duplicheck socket failed");
81 return FALSE;
82 }
83 unlink(addr.sun_path);
84 old = umask(~(S_IRWXU | S_IRWXG));
85 if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) < 0)
86 {
87 DBG1(DBG_CFG, "binding duplicheck socket failed: %s", strerror(errno));
88 close(this->socket);
89 return FALSE;
90 }
91 umask(old);
92 if (chown(addr.sun_path, charon->uid, charon->gid) != 0)
93 {
94 DBG1(DBG_CFG, "changing duplicheck socket permissions failed: %s",
95 strerror(errno));
96 }
97 if (listen(this->socket, 3) < 0)
98 {
99 DBG1(DBG_CFG, "listening on duplicheck socket failed: %s",
100 strerror(errno));
101 close(this->socket);
102 unlink(addr.sun_path);
103 return FALSE;
104 }
105 return TRUE;
106 }
107
108 /**
109 * Accept duplicheck notification connections
110 */
111 static job_requeue_t receive(private_duplicheck_notify_t *this)
112 {
113 struct sockaddr_un addr;
114 int len = sizeof(addr);
115 uintptr_t fd;
116 bool oldstate;
117
118 oldstate = thread_cancelability(TRUE);
119 fd = accept(this->socket, (struct sockaddr*)&addr, &len);
120 thread_cancelability(oldstate);
121
122 if (fd != -1)
123 {
124 this->mutex->lock(this->mutex);
125 this->connected->insert_last(this->connected, (void*)fd);
126 this->mutex->unlock(this->mutex);
127 }
128 else
129 {
130 DBG1(DBG_CFG, "accepting duplicheck connection failed: %s",
131 strerror(errno));
132 }
133 return JOB_REQUEUE_FAIR;
134 }
135
136 METHOD(duplicheck_notify_t, send_, void,
137 private_duplicheck_notify_t *this, identification_t *id)
138 {
139 char buf[128];
140 enumerator_t *enumerator;
141 uintptr_t fd;
142 int len;
143
144 len = snprintf(buf, sizeof(buf), "%Y", id);
145 if (len > 0 && len < sizeof(buf))
146 {
147 this->mutex->lock(this->mutex);
148 enumerator = this->connected->create_enumerator(this->connected);
149 while (enumerator->enumerate(enumerator, &fd))
150 {
151 if (send(fd, &buf, len + 1, 0) != len + 1)
152 {
153 DBG1(DBG_CFG, "sending duplicheck notify failed: %s",
154 strerror(errno));
155 this->connected->remove_at(this->connected, enumerator);
156 close(fd);
157 }
158 }
159 enumerator->destroy(enumerator);
160 this->mutex->unlock(this->mutex);
161 }
162 }
163
164 METHOD(duplicheck_notify_t, destroy, void,
165 private_duplicheck_notify_t *this)
166 {
167 enumerator_t *enumerator;
168 uintptr_t fd;
169
170 if (this->job)
171 {
172 this->job->cancel(this->job);
173 }
174 enumerator = this->connected->create_enumerator(this->connected);
175 while (enumerator->enumerate(enumerator, &fd))
176 {
177 close(fd);
178 }
179 enumerator->destroy(enumerator);
180 this->connected->destroy(this->connected);
181 this->mutex->destroy(this->mutex);
182 free(this);
183 }
184
185 /**
186 * See header
187 */
188 duplicheck_notify_t *duplicheck_notify_create()
189 {
190 private_duplicheck_notify_t *this;
191
192 INIT(this,
193 .public = {
194 .send = _send_,
195 .destroy = _destroy,
196 },
197 .connected = linked_list_create(),
198 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
199 );
200
201 if (!open_socket(this))
202 {
203 destroy(this);
204 return NULL;
205 }
206 this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
207 this, NULL, NULL, JOB_PRIO_CRITICAL);
208 lib->processor->queue_job(lib->processor, (job_t*)this->job);
209
210 return &this->public;
211 }