Added class to relay IPsec events (like expiration) to listeners
[strongswan.git] / src / libipsec / ipsec_event_relay.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "ipsec_event_relay.h"
19
20 #include <library.h>
21 #include <debug.h>
22 #include <threading/rwlock.h>
23 #include <utils/linked_list.h>
24 #include <utils/blocking_queue.h>
25 #include <processing/jobs/callback_job.h>
26
27 typedef struct private_ipsec_event_relay_t private_ipsec_event_relay_t;
28
29 /**
30 * Private additions to ipsec_event_relay_t.
31 */
32 struct private_ipsec_event_relay_t {
33
34 /**
35 * Public members
36 */
37 ipsec_event_relay_t public;
38
39 /**
40 * Registered listeners
41 */
42 linked_list_t *listeners;
43
44 /**
45 * Lock to safely access the list of listeners
46 */
47 rwlock_t *lock;
48
49 /**
50 * Blocking queue for events
51 */
52 blocking_queue_t *queue;
53 };
54
55 /**
56 * Helper struct used to manage events in a queue
57 */
58 typedef struct {
59
60 /**
61 * Type of the event
62 */
63 enum {
64 IPSEC_EVENT_EXPIRE,
65 } type;
66
67 /**
68 * Reqid of the SA, if any
69 */
70 u_int32_t reqid;
71
72 /**
73 * SPI of the SA, if any
74 */
75 u_int32_t spi;
76
77 /**
78 * Additional data for specific event types
79 */
80 union {
81
82 struct {
83 /** Protocol of the SA */
84 u_int8_t protocol;
85 /** TRUE in case of a hard expire */
86 bool hard;
87 } expire;
88
89 } data;
90
91 } ipsec_event_t;
92
93 /**
94 * Dequeue events and relay them to listeners
95 */
96 static job_requeue_t handle_events(private_ipsec_event_relay_t *this)
97 {
98 enumerator_t *enumerator;
99 ipsec_event_listener_t *current;
100 ipsec_event_t *event;
101
102 event = this->queue->dequeue(this->queue);
103
104 this->lock->read_lock(this->lock);
105 enumerator = this->listeners->create_enumerator(this->listeners);
106 while (enumerator->enumerate(enumerator, (void**)&current))
107 {
108 switch (event->type)
109 {
110 case IPSEC_EVENT_EXPIRE:
111 if (current->expire)
112 {
113 current->expire(event->reqid, event->data.expire.protocol,
114 event->spi, event->data.expire.hard);
115 }
116 break;
117 }
118 }
119 enumerator->destroy(enumerator);
120 this->lock->unlock(this->lock);
121 return JOB_REQUEUE_DIRECT;
122 }
123
124 METHOD(ipsec_event_relay_t, expire, void,
125 private_ipsec_event_relay_t *this, u_int32_t reqid, u_int8_t protocol,
126 u_int32_t spi, bool hard)
127 {
128 ipsec_event_t *event;
129
130 INIT(event,
131 .type = IPSEC_EVENT_EXPIRE,
132 .reqid = reqid,
133 .spi = spi,
134 .data = {
135 .expire = {
136 .protocol = protocol,
137 .hard = hard,
138 },
139 },
140 );
141 this->queue->enqueue(this->queue, event);
142 }
143
144 METHOD(ipsec_event_relay_t, register_listener, void,
145 private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener)
146 {
147 this->lock->write_lock(this->lock);
148 this->listeners->insert_last(this->listeners, listener);
149 this->lock->unlock(this->lock);
150 }
151
152 METHOD(ipsec_event_relay_t, unregister_listener, void,
153 private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener)
154 {
155 this->lock->write_lock(this->lock);
156 this->listeners->remove(this->listeners, listener, NULL);
157 this->lock->unlock(this->lock);
158 }
159
160 METHOD(ipsec_event_relay_t, destroy, void,
161 private_ipsec_event_relay_t *this)
162 {
163 this->queue->destroy_function(this->queue, free);
164 this->listeners->destroy(this->listeners);
165 this->lock->destroy(this->lock);
166 free(this);
167 }
168
169 /**
170 * Described in header.
171 */
172 ipsec_event_relay_t *ipsec_event_relay_create()
173 {
174 private_ipsec_event_relay_t *this;
175
176 INIT(this,
177 .public = {
178 .expire = _expire,
179 .register_listener = _register_listener,
180 .unregister_listener = _unregister_listener,
181 .destroy = _destroy,
182 },
183 .listeners = linked_list_create(),
184 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
185 .queue = blocking_queue_create(),
186 );
187
188 lib->processor->queue_job(lib->processor,
189 (job_t*)callback_job_create((callback_job_cb_t)handle_events, this,
190 NULL, (callback_job_cancel_t)return_false));
191
192 return &this->public;
193 }