Annotation of embedaddon/strongswan/src/libcharon/plugins/lookip/lookip_socket.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012 Martin Willi
3: * Copyright (C) 2012 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 "lookip_socket.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/thread.h>
27: #include <threading/mutex.h>
28: #include <collections/linked_list.h>
29: #include <processing/jobs/callback_job.h>
30:
31: #include "lookip_msg.h"
32:
33: typedef struct private_lookip_socket_t private_lookip_socket_t;
34:
35: /**
36: * Private data of an lookip_socket_t object.
37: */
38: struct private_lookip_socket_t {
39:
40: /**
41: * Public lookip_socket_t interface.
42: */
43: lookip_socket_t public;
44:
45: /**
46: * lookip
47: */
48: lookip_listener_t *listener;
49:
50: /**
51: * stream service accepting connections
52: */
53: stream_service_t *service;
54:
55: /**
56: * List of connected clients, as entry_t
57: */
58: linked_list_t *connected;
59:
60: /**
61: * Mutex to lock clients list
62: */
63: mutex_t *mutex;
64: };
65:
66: /**
67: * List entry for a connected stream
68: */
69: typedef struct {
70: /* stream to write to */
71: stream_t *stream;
72: /* registered for up events? */
73: bool up;
74: /* registered for down events? */
75: bool down;
76: /** backref to this for unregistration */
77: private_lookip_socket_t *this;
78: } entry_t;
79:
80: /**
81: * Clean up a connection entry
82: */
83: static void entry_destroy(entry_t *entry)
84: {
85: entry->stream->destroy(entry->stream);
86: free(entry);
87: }
88:
89: /**
90: * Data for async disconnect job
91: */
92: typedef struct {
93: /** socket ref */
94: private_lookip_socket_t *this;
95: /** stream to disconnect */
96: stream_t *stream;
97: } disconnect_data_t;
98:
99: /**
100: * Disconnect a stream asynchronously, remove connection entry
101: */
102: static job_requeue_t disconnect_async(disconnect_data_t *data)
103: {
104: private_lookip_socket_t *this = data->this;
105: enumerator_t *enumerator;
106: entry_t *entry;
107:
108: this->mutex->lock(this->mutex);
109: enumerator = this->connected->create_enumerator(this->connected);
110: while (enumerator->enumerate(enumerator, &entry))
111: {
112: if (entry->stream == data->stream)
113: {
114: this->connected->remove_at(this->connected, enumerator);
115: if (entry->up || entry->down)
116: {
117: this->listener->remove_listener(this->listener, entry);
118: }
119: entry_destroy(entry);
120: break;
121: }
122: }
123: enumerator->destroy(enumerator);
124: this->mutex->unlock(this->mutex);
125: return JOB_REQUEUE_NONE;
126: }
127:
128: /**
129: * Queue async disconnect job
130: */
131: static void disconnect(private_lookip_socket_t *this, stream_t *stream)
132: {
133: disconnect_data_t *data;
134:
135: INIT(data,
136: .this = this,
137: .stream = stream,
138: );
139:
140: lib->processor->queue_job(lib->processor,
141: (job_t*)callback_job_create((void*)disconnect_async, data,
142: free, NULL));
143: }
144:
145: /**
146: * Callback function for listener up/down events
147: */
148: static bool event_cb(entry_t *entry, bool up, host_t *vip, host_t *other,
149: identification_t *id, char *name, u_int unique_id)
150: {
151: lookip_response_t resp = {
152: .unique_id = htonl(unique_id),
153: };
154:
155: if (up)
156: {
157: if (!entry->up)
158: {
159: return TRUE;
160: }
161: resp.type = htonl(LOOKIP_NOTIFY_UP);
162: }
163: else
164: {
165: if (!entry->down)
166: {
167: return TRUE;
168: }
169: resp.type = htonl(LOOKIP_NOTIFY_DOWN);
170: }
171:
172: snprintf(resp.vip, sizeof(resp.vip), "%H", vip);
173: snprintf(resp.ip, sizeof(resp.ip), "%H", other);
174: snprintf(resp.id, sizeof(resp.id), "%Y", id);
175: snprintf(resp.name, sizeof(resp.name), "%s", name);
176:
177: if (entry->stream->write_all(entry->stream, &resp, sizeof(resp)))
178: {
179: return TRUE;
180: }
181: switch (errno)
182: {
183: case ECONNRESET:
184: case EPIPE:
185: /* client disconnected, adios */
186: break;
187: default:
188: DBG1(DBG_CFG, "sending lookip event failed: %s", strerror(errno));
189: break;
190: }
191: /* don't unregister, as we return FALSE */
192: entry->up = entry->down = FALSE;
193: disconnect(entry->this, entry->stream);
194: return FALSE;
195: }
196:
197: /**
198: * Callback function for queries
199: */
200: static bool query_cb(stream_t *stream, bool up, host_t *vip, host_t *other,
201: identification_t *id, char *name, u_int unique_id)
202: {
203: lookip_response_t resp = {
204: .type = htonl(LOOKIP_ENTRY),
205: .unique_id = htonl(unique_id),
206: };
207:
208: snprintf(resp.vip, sizeof(resp.vip), "%H", vip);
209: snprintf(resp.ip, sizeof(resp.ip), "%H", other);
210: snprintf(resp.id, sizeof(resp.id), "%Y", id);
211: snprintf(resp.name, sizeof(resp.name), "%s", name);
212:
213: if (stream->write_all(stream, &resp, sizeof(resp)))
214: {
215: return TRUE;
216: }
217: switch (errno)
218: {
219: case ECONNRESET:
220: case EPIPE:
221: /* client disconnected, adios */
222: break;
223: default:
224: DBG1(DBG_CFG, "sending lookip response failed: %s", strerror(errno));
225: break;
226: }
227: return FALSE;
228: }
229:
230: /**
231: * Perform a lookup
232: */
233: static void query(private_lookip_socket_t *this, stream_t *stream,
234: lookip_request_t *req)
235: {
236:
237: host_t *vip = NULL;
238: int matches = 0;
239:
240: if (req)
241: { /* lookup */
242: req->vip[sizeof(req->vip) - 1] = 0;
243: vip = host_create_from_string(req->vip, 0);
244: if (vip)
245: {
246: matches = this->listener->lookup(this->listener, vip,
247: (void*)query_cb, stream);
248: vip->destroy(vip);
249: }
250: if (matches == 0)
251: {
252: lookip_response_t resp = {
253: .type = htonl(LOOKIP_NOT_FOUND),
254: };
255:
256: snprintf(resp.vip, sizeof(resp.vip), "%s", req->vip);
257: if (!stream->write_all(stream, &resp, sizeof(resp)))
258: {
259: DBG1(DBG_CFG, "sending lookip not-found failed: %s",
260: strerror(errno));
261: }
262: }
263: }
264: else
265: { /* dump */
266: this->listener->lookup(this->listener, NULL,
267: (void*)query_cb, stream);
268: }
269: }
270:
271: /**
272: * Subscribe to virtual IP events
273: */
274: static void subscribe(private_lookip_socket_t *this, stream_t *stream, bool up)
275: {
276: enumerator_t *enumerator;
277: entry_t *entry;
278:
279: this->mutex->lock(this->mutex);
280: enumerator = this->connected->create_enumerator(this->connected);
281: while (enumerator->enumerate(enumerator, &entry))
282: {
283: if (entry->stream == stream)
284: {
285: if (!entry->up && !entry->down)
286: { /* newly registered */
287: this->listener->add_listener(this->listener,
288: (void*)event_cb, entry);
289: }
290: if (up)
291: {
292: entry->up = TRUE;
293: }
294: else
295: {
296: entry->down = TRUE;
297: }
298: }
299: }
300: enumerator->destroy(enumerator);
301: this->mutex->unlock(this->mutex);
302: }
303:
304: /**
305: * Check if a client is subscribed for notifications
306: */
307: static bool subscribed(private_lookip_socket_t *this, stream_t *stream)
308: {
309: enumerator_t *enumerator;
310: bool subscribed = FALSE;
311: entry_t *entry;
312:
313: this->mutex->lock(this->mutex);
314: enumerator = this->connected->create_enumerator(this->connected);
315: while (enumerator->enumerate(enumerator, &entry))
316: {
317: if (entry->stream == stream)
318: {
319: subscribed = entry->up || entry->down;
320: break;
321: }
322: }
323: enumerator->destroy(enumerator);
324: this->mutex->unlock(this->mutex);
325:
326: return subscribed;
327: }
328:
329: /**
330: * Dispatch from a socket, on-read callback
331: */
332: static bool on_read(private_lookip_socket_t *this, stream_t *stream)
333: {
334: lookip_request_t req;
335:
336: if (stream->read_all(stream, &req, sizeof(req)))
337: {
338: switch (ntohl(req.type))
339: {
340: case LOOKIP_LOOKUP:
341: query(this, stream, &req);
342: return TRUE;
343: case LOOKIP_DUMP:
344: query(this, stream, NULL);
345: return TRUE;
346: case LOOKIP_REGISTER_UP:
347: subscribe(this, stream, TRUE);
348: return TRUE;
349: case LOOKIP_REGISTER_DOWN:
350: subscribe(this, stream, FALSE);
351: return TRUE;
352: case LOOKIP_END:
353: break;
354: default:
355: DBG1(DBG_CFG, "received unknown lookip command");
356: break;
357: }
358: }
359: else
360: {
361: if (errno != ECONNRESET)
362: {
363: DBG1(DBG_CFG, "receiving lookip request failed: %s",
364: strerror(errno));
365: }
366: disconnect(this, stream);
367: return FALSE;
368: }
369: if (subscribed(this, stream))
370: {
371: return TRUE;
372: }
373: disconnect(this, stream);
374: return FALSE;
375: }
376:
377: /**
378: * Accept client connections, dispatch
379: */
380: static bool on_accept(private_lookip_socket_t *this, stream_t *stream)
381: {
382: entry_t *entry;
383:
384: INIT(entry,
385: .stream = stream,
386: .this = this,
387: );
388:
389: this->mutex->lock(this->mutex);
390: this->connected->insert_last(this->connected, entry);
391: this->mutex->unlock(this->mutex);
392:
393: stream->on_read(stream, (void*)on_read, this);
394:
395: return TRUE;
396: }
397:
398: METHOD(lookip_socket_t, destroy, void,
399: private_lookip_socket_t *this)
400: {
401: DESTROY_IF(this->service);
402: this->connected->destroy_function(this->connected, (void*)entry_destroy);
403: this->mutex->destroy(this->mutex);
404: free(this);
405: }
406:
407: /**
408: * See header
409: */
410: lookip_socket_t *lookip_socket_create(lookip_listener_t *listener)
411: {
412: private_lookip_socket_t *this;
413: char *uri;
414:
415: INIT(this,
416: .public = {
417: .destroy = _destroy,
418: },
419: .listener = listener,
420: .connected = linked_list_create(),
421: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
422: );
423:
424: uri = lib->settings->get_str(lib->settings,
425: "%s.plugins.lookip.socket", "unix://" LOOKIP_SOCKET,
426: lib->ns);
427: this->service = lib->streams->create_service(lib->streams, uri, 10);
428: if (!this->service)
429: {
430: DBG1(DBG_CFG, "creating lookip socket failed");
431: destroy(this);
432: return NULL;
433: }
434:
435: this->service->on_accept(this->service, (stream_service_cb_t)on_accept,
436: this, JOB_PRIO_CRITICAL, 1);
437:
438: return &this->public;
439: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>