]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libradius/radius_config.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libradius / radius_config.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 *
4 * Copyright (C) secunet Security Networks AG
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 /*
18 * Copyright (C) 2015 Thom Troy
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining a copy
21 * of this software and associated documentation files (the "Software"), to deal
22 * in the Software without restriction, including without limitation the rights
23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24 * copies of the Software, and to permit persons to whom the Software is
25 * furnished to do so, subject to the following conditions:
26 *
27 * The above copyright notice and this permission notice shall be included in
28 * all copies or substantial portions of the Software.
29 *
30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36 * THE SOFTWARE.
37 */
38
39 #include "radius_config.h"
40
41 #include <threading/mutex.h>
42 #include <threading/condvar.h>
43 #include <collections/linked_list.h>
44
45 typedef struct private_radius_config_t private_radius_config_t;
46
47 /**
48 * Private data of an radius_config_t object.
49 */
50 struct private_radius_config_t {
51
52 /**
53 * Public radius_config_t interface.
54 */
55 radius_config_t public;
56
57 /**
58 * list of radius sockets, as radius_socket_t
59 */
60 linked_list_t *sockets;
61
62 /**
63 * Total number of sockets, in list + currently in use
64 */
65 int socket_count;
66
67 /**
68 * mutex to lock sockets list
69 */
70 mutex_t *mutex;
71
72 /**
73 * condvar to wait for sockets
74 */
75 condvar_t *condvar;
76
77 /**
78 * Server name
79 */
80 char *name;
81
82 /**
83 * NAS-Identifier
84 */
85 chunk_t nas_identifier;
86
87 /**
88 * Preference boost for this server
89 */
90 int preference;
91
92 /**
93 * Is the server currently reachable
94 */
95 bool reachable;
96
97 /**
98 * Retry counter for unreachable servers
99 */
100 int retry;
101
102 /**
103 * reference count
104 */
105 refcount_t ref;
106 };
107
108 METHOD(radius_config_t, get_socket, radius_socket_t*,
109 private_radius_config_t *this)
110 {
111 radius_socket_t *skt;
112
113 this->mutex->lock(this->mutex);
114 while (this->sockets->remove_first(this->sockets, (void**)&skt) != SUCCESS)
115 {
116 this->condvar->wait(this->condvar, this->mutex);
117 }
118 this->mutex->unlock(this->mutex);
119 return skt;
120 }
121
122 METHOD(radius_config_t, put_socket, void,
123 private_radius_config_t *this, radius_socket_t *skt, bool result)
124 {
125 this->mutex->lock(this->mutex);
126 this->sockets->insert_last(this->sockets, skt);
127 this->mutex->unlock(this->mutex);
128 this->condvar->signal(this->condvar);
129 this->reachable = result;
130 }
131
132 METHOD(radius_config_t, get_nas_identifier, chunk_t,
133 private_radius_config_t *this)
134 {
135 return this->nas_identifier;
136 }
137
138 METHOD(radius_config_t, get_preference, int,
139 private_radius_config_t *this)
140 {
141 int pref;
142
143 if (this->socket_count == 0)
144 { /* don't have sockets, huh? */
145 return -1;
146 }
147 /* calculate preference between 0-100 + boost */
148 pref = this->preference;
149 pref += this->sockets->get_count(this->sockets) * 100 / this->socket_count;
150 if (this->reachable)
151 { /* reachable server get a boost: pref = 110-210 + boost */
152 return pref + 110;
153 }
154 /* Not reachable. Increase preference randomly to let it retry from
155 * time to time, especially if other servers have high load. */
156 this->retry++;
157 if (this->retry % 128 == 0)
158 { /* every 64th request gets 210, same as unloaded reachable */
159 return pref + 110;
160 }
161 if (this->retry % 32 == 0)
162 { /* every 32th request gets 190, wins against average loaded */
163 return pref + 90;
164 }
165 if (this->retry % 8 == 0)
166 { /* every 8th request gets 110, same as server under load */
167 return pref + 10;
168 }
169 /* other get ~100, less than fully loaded */
170 return pref;
171 }
172
173 METHOD(radius_config_t, get_name, char*,
174 private_radius_config_t *this)
175 {
176 return this->name;
177 }
178
179 METHOD(radius_config_t, get_ref, radius_config_t*,
180 private_radius_config_t *this)
181 {
182 ref_get(&this->ref);
183 return &this->public;
184 }
185
186
187 METHOD(radius_config_t, destroy, void,
188 private_radius_config_t *this)
189 {
190 if (ref_put(&this->ref))
191 {
192 this->mutex->destroy(this->mutex);
193 this->condvar->destroy(this->condvar);
194 this->sockets->destroy_offset(this->sockets,
195 offsetof(radius_socket_t, destroy));
196 free(this);
197 }
198 }
199
200 /**
201 * See header
202 */
203 radius_config_t *radius_config_create(char *name, char *address,
204 uint16_t auth_port, uint16_t acct_port,
205 char *nas_identifier, char *secret,
206 int sockets, int preference,
207 u_int tries, double timeout, double base)
208 {
209 private_radius_config_t *this;
210 radius_socket_t *socket;
211
212 INIT(this,
213 .public = {
214 .get_socket = _get_socket,
215 .put_socket = _put_socket,
216 .get_nas_identifier = _get_nas_identifier,
217 .get_preference = _get_preference,
218 .get_name = _get_name,
219 .get_ref = _get_ref,
220 .destroy = _destroy,
221 },
222 .reachable = TRUE,
223 .nas_identifier = chunk_create(nas_identifier, strlen(nas_identifier)),
224 .socket_count = sockets,
225 .sockets = linked_list_create(),
226 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
227 .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
228 .name = name,
229 .preference = preference,
230 .ref = 1,
231 );
232
233 while (sockets--)
234 {
235 socket = radius_socket_create(address, auth_port, acct_port,
236 chunk_create(secret, strlen(secret)),
237 tries, timeout, base);
238 if (!socket)
239 {
240 destroy(this);
241 return NULL;
242 }
243 this->sockets->insert_last(this->sockets, socket);
244 }
245 return &this->public;
246 }