2 * Copyright (C) 2010 Martin Willi
4 * Copyright (C) secunet Security Networks AG
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>.
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
18 * Copyright (C) 2015 Thom Troy
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:
27 * The above copyright notice and this permission notice shall be included in
28 * all copies or substantial portions of the Software.
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
39 #include "radius_config.h"
41 #include <threading/mutex.h>
42 #include <threading/condvar.h>
43 #include <collections/linked_list.h>
45 typedef struct private_radius_config_t private_radius_config_t
;
48 * Private data of an radius_config_t object.
50 struct private_radius_config_t
{
53 * Public radius_config_t interface.
55 radius_config_t
public;
58 * list of radius sockets, as radius_socket_t
60 linked_list_t
*sockets
;
63 * Total number of sockets, in list + currently in use
68 * mutex to lock sockets list
73 * condvar to wait for sockets
85 chunk_t nas_identifier
;
88 * Preference boost for this server
93 * Is the server currently reachable
98 * Retry counter for unreachable servers
108 METHOD(radius_config_t
, get_socket
, radius_socket_t
*,
109 private_radius_config_t
*this)
111 radius_socket_t
*skt
;
113 this->mutex
->lock(this->mutex
);
114 while (this->sockets
->remove_first(this->sockets
, (void**)&skt
) != SUCCESS
)
116 this->condvar
->wait(this->condvar
, this->mutex
);
118 this->mutex
->unlock(this->mutex
);
122 METHOD(radius_config_t
, put_socket
, void,
123 private_radius_config_t
*this, radius_socket_t
*skt
, bool result
)
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
;
132 METHOD(radius_config_t
, get_nas_identifier
, chunk_t
,
133 private_radius_config_t
*this)
135 return this->nas_identifier
;
138 METHOD(radius_config_t
, get_preference
, int,
139 private_radius_config_t
*this)
143 if (this->socket_count
== 0)
144 { /* don't have sockets, huh? */
147 /* calculate preference between 0-100 + boost */
148 pref
= this->preference
;
149 pref
+= this->sockets
->get_count(this->sockets
) * 100 / this->socket_count
;
151 { /* reachable server get a boost: pref = 110-210 + boost */
154 /* Not reachable. Increase preference randomly to let it retry from
155 * time to time, especially if other servers have high load. */
157 if (this->retry
% 128 == 0)
158 { /* every 64th request gets 210, same as unloaded reachable */
161 if (this->retry
% 32 == 0)
162 { /* every 32th request gets 190, wins against average loaded */
165 if (this->retry
% 8 == 0)
166 { /* every 8th request gets 110, same as server under load */
169 /* other get ~100, less than fully loaded */
173 METHOD(radius_config_t
, get_name
, char*,
174 private_radius_config_t
*this)
179 METHOD(radius_config_t
, get_ref
, radius_config_t
*,
180 private_radius_config_t
*this)
183 return &this->public;
187 METHOD(radius_config_t
, destroy
, void,
188 private_radius_config_t
*this)
190 if (ref_put(&this->ref
))
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
));
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
)
209 private_radius_config_t
*this;
210 radius_socket_t
*socket
;
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
,
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
),
229 .preference
= preference
,
235 socket
= radius_socket_create(address
, auth_port
, acct_port
,
236 chunk_create(secret
, strlen(secret
)),
237 tries
, timeout
, base
);
243 this->sockets
->insert_last(this->sockets
, socket
);
245 return &this->public;