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 "lookip_socket.h"
18 #include <sys/types.h>
20 #include <sys/socket.h>
26 #include <threading/thread.h>
27 #include <threading/mutex.h>
28 #include <utils/linked_list.h>
29 #include <processing/jobs/callback_job.h>
31 #include "lookip_msg.h"
33 typedef struct private_lookip_socket_t private_lookip_socket_t
;
36 * Private data of an lookip_socket_t object.
38 struct private_lookip_socket_t
{
41 * Public lookip_socket_t interface.
43 lookip_socket_t
public;
48 lookip_listener_t
*listener
;
51 * lookip unix socket file descriptor
56 * List of registered listeners, as entry_t
58 linked_list_t
*clients
;
61 * Mutex to lock clients list
67 * Open lookip unix socket
69 static bool open_socket(private_lookip_socket_t
*this)
71 struct sockaddr_un addr
;
74 addr
.sun_family
= AF_UNIX
;
75 strcpy(addr
.sun_path
, LOOKIP_SOCKET
);
77 this->socket
= socket(AF_UNIX
, SOCK_SEQPACKET
, 0);
78 if (this->socket
== -1)
80 DBG1(DBG_CFG
, "creating lookip socket failed");
83 unlink(addr
.sun_path
);
84 old
= umask(~(S_IRWXU
| S_IRWXG
));
85 if (bind(this->socket
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
87 DBG1(DBG_CFG
, "binding lookip socket failed: %s", strerror(errno
));
92 if (chown(addr
.sun_path
, charon
->caps
->get_uid(charon
->caps
),
93 charon
->caps
->get_gid(charon
->caps
)) != 0)
95 DBG1(DBG_CFG
, "changing lookip socket permissions failed: %s",
98 if (listen(this->socket
, 10) < 0)
100 DBG1(DBG_CFG
, "listening on lookip socket failed: %s", strerror(errno
));
102 unlink(addr
.sun_path
);
109 * Listener callback entry
114 /* message type to send */
116 /* back pointer to socket, only for subscriptions */
117 private_lookip_socket_t
*this;
123 static void entry_destroy(entry_t
*this)
130 * Callback function for listener
132 static bool listener_cb(entry_t
*entry
, bool up
, host_t
*vip
,
133 host_t
*other
, identification_t
*id
, char *name
)
135 lookip_response_t resp
= {
140 if (up
&& entry
->type
== LOOKIP_NOTIFY_DOWN
)
144 if (!up
&& entry
->type
== LOOKIP_NOTIFY_UP
)
149 snprintf(resp
.vip
, sizeof(resp
.vip
), "%H", vip
);
150 snprintf(resp
.ip
, sizeof(resp
.ip
), "%H", other
);
151 snprintf(resp
.id
, sizeof(resp
.id
), "%Y", id
);
152 snprintf(resp
.name
, sizeof(resp
.name
), "%s", name
);
154 switch (send(entry
->fd
, &resp
, sizeof(resp
), 0))
159 /* client disconnected, adios */
162 DBG1(DBG_CFG
, "sending lookip response failed: %s", strerror(errno
));
166 { /* unregister listener */
167 entry
->this->mutex
->lock(entry
->this->mutex
);
168 entry
->this->clients
->remove(entry
->this->clients
, entry
, NULL
);
169 entry
->this->mutex
->unlock(entry
->this->mutex
);
171 entry_destroy(entry
);
177 * Perform a entry lookup
179 static void query(private_lookip_socket_t
*this, int fd
, lookip_request_t
*req
)
183 .type
= LOOKIP_ENTRY
,
189 req
->vip
[sizeof(req
->vip
) - 1] = 0;
190 vip
= host_create_from_string(req
->vip
, 0);
193 this->listener
->lookup(this->listener
, vip
,
194 (void*)listener_cb
, &entry
);
200 this->listener
->lookup(this->listener
, NULL
,
201 (void*)listener_cb
, &entry
);
206 * Subscribe to virtual IP events
208 static void subscribe(private_lookip_socket_t
*this, int fd
, int type
)
218 this->mutex
->lock(this->mutex
);
219 this->clients
->insert_last(this->clients
, entry
);
220 this->mutex
->unlock(this->mutex
);
222 this->listener
->add_listener(this->listener
, (void*)listener_cb
, entry
);
226 * Accept client connections, dispatch
228 static job_requeue_t
receive(private_lookip_socket_t
*this)
230 struct sockaddr_un addr
;
231 int fd
, len
= sizeof(addr
);
232 lookip_request_t req
;
233 bool oldstate
, subscribed
= FALSE
;
235 oldstate
= thread_cancelability(TRUE
);
236 fd
= accept(this->socket
, (struct sockaddr
*)&addr
, &len
);
237 thread_cancelability(oldstate
);
243 oldstate
= thread_cancelability(TRUE
);
244 len
= recv(fd
, &req
, sizeof(req
), 0);
245 thread_cancelability(oldstate
);
247 if (len
== sizeof(req
))
252 query(this, fd
, &req
);
255 query(this, fd
, NULL
);
257 case LOOKIP_REGISTER_UP
:
258 subscribe(this, fd
, LOOKIP_NOTIFY_UP
);
261 case LOOKIP_REGISTER_DOWN
:
262 subscribe(this, fd
, LOOKIP_NOTIFY_DOWN
);
268 DBG1(DBG_CFG
, "received unknown lookip command");
276 DBG1(DBG_CFG
, "receiving lookip request failed: %s",
284 { /* don't close if we queued the fd */
290 DBG1(DBG_CFG
, "accepting lookip connection failed: %s",
293 return JOB_REQUEUE_FAIR
;
296 METHOD(lookip_socket_t
, destroy
, void,
297 private_lookip_socket_t
*this)
299 this->clients
->destroy_function(this->clients
, (void*)entry_destroy
);
300 this->mutex
->destroy(this->mutex
);
308 lookip_socket_t
*lookip_socket_create(lookip_listener_t
*listener
)
310 private_lookip_socket_t
*this;
316 .listener
= listener
,
317 .clients
= linked_list_create(),
318 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
321 if (!open_socket(this))
327 lib
->processor
->queue_job(lib
->processor
,
328 (job_t
*)callback_job_create_with_prio((callback_job_cb_t
)receive
, this,
329 NULL
, (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
331 return &this->public;