Coverage Report

Created: 2026-05-30 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libradius/radius_config.c
Line
Count
Source
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
0
{
111
0
  radius_socket_t *skt;
112
113
0
  this->mutex->lock(this->mutex);
114
0
  while (this->sockets->remove_first(this->sockets, (void**)&skt) != SUCCESS)
115
0
  {
116
0
    this->condvar->wait(this->condvar, this->mutex);
117
0
  }
118
0
  this->mutex->unlock(this->mutex);
119
0
  return skt;
120
0
}
121
122
METHOD(radius_config_t, put_socket, void,
123
  private_radius_config_t *this, radius_socket_t *skt, bool result)
124
0
{
125
0
  this->mutex->lock(this->mutex);
126
0
  this->sockets->insert_last(this->sockets, skt);
127
0
  this->mutex->unlock(this->mutex);
128
0
  this->condvar->signal(this->condvar);
129
0
  this->reachable = result;
130
0
}
131
132
METHOD(radius_config_t, get_nas_identifier, chunk_t,
133
  private_radius_config_t *this)
134
0
{
135
0
  return this->nas_identifier;
136
0
}
137
138
METHOD(radius_config_t, get_preference, int,
139
  private_radius_config_t *this)
140
0
{
141
0
  int pref;
142
143
0
  if (this->socket_count == 0)
144
0
  { /* don't have sockets, huh? */
145
0
    return -1;
146
0
  }
147
  /* calculate preference between 0-100 + boost */
148
0
  pref = this->preference;
149
0
  pref += this->sockets->get_count(this->sockets) * 100 / this->socket_count;
150
0
  if (this->reachable)
151
0
  { /* reachable server get a boost: pref = 110-210 + boost */
152
0
    return pref + 110;
153
0
  }
154
  /* Not reachable. Increase preference randomly to let it retry from
155
   * time to time, especially if other servers have high load. */
156
0
  this->retry++;
157
0
  if (this->retry % 128 == 0)
158
0
  { /* every 64th request gets 210, same as unloaded reachable */
159
0
    return pref + 110;
160
0
  }
161
0
  if (this->retry % 32 == 0)
162
0
  { /* every 32th request gets 190, wins against average loaded */
163
0
    return pref + 90;
164
0
  }
165
0
  if (this->retry % 8 == 0)
166
0
  { /* every 8th request gets 110, same as server under load */
167
0
    return pref + 10;
168
0
  }
169
  /* other get ~100, less than fully loaded */
170
0
  return pref;
171
0
}
172
173
METHOD(radius_config_t, get_name, char*,
174
  private_radius_config_t *this)
175
0
{
176
0
  return this->name;
177
0
}
178
179
METHOD(radius_config_t, get_ref, radius_config_t*,
180
  private_radius_config_t *this)
181
0
{
182
0
  ref_get(&this->ref);
183
0
  return &this->public;
184
0
}
185
186
187
METHOD(radius_config_t, destroy, void,
188
  private_radius_config_t *this)
189
0
{
190
0
  if (ref_put(&this->ref))
191
0
  {
192
0
    this->mutex->destroy(this->mutex);
193
0
    this->condvar->destroy(this->condvar);
194
0
    this->sockets->destroy_offset(this->sockets,
195
0
                    offsetof(radius_socket_t, destroy));
196
0
    free(this);
197
0
  }
198
0
}
199
200
/**
201
 * See header
202
 */
203
radius_config_t *radius_config_create(char *name, char *address, char *source,
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
0
{
209
0
  private_radius_config_t *this;
210
0
  radius_socket_t *socket;
211
212
0
  INIT(this,
213
0
    .public = {
214
0
      .get_socket = _get_socket,
215
0
      .put_socket = _put_socket,
216
0
      .get_nas_identifier = _get_nas_identifier,
217
0
      .get_preference = _get_preference,
218
0
      .get_name = _get_name,
219
0
      .get_ref = _get_ref,
220
0
      .destroy = _destroy,
221
0
    },
222
0
    .reachable = TRUE,
223
0
    .nas_identifier = chunk_create(nas_identifier, strlen(nas_identifier)),
224
0
    .socket_count = sockets,
225
0
    .sockets = linked_list_create(),
226
0
    .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
227
0
    .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
228
0
    .name = name,
229
0
    .preference = preference,
230
0
    .ref = 1,
231
0
  );
232
233
0
  while (sockets--)
234
0
  {
235
0
    socket = radius_socket_create(address, source, auth_port, acct_port,
236
0
                    chunk_create(secret, strlen(secret)),
237
0
                    tries, timeout, base);
238
0
    if (!socket)
239
0
    {
240
0
      destroy(this);
241
0
      return NULL;
242
0
    }
243
0
    this->sockets->insert_last(this->sockets, socket);
244
0
  }
245
0
  return &this->public;
246
0
}