/src/kamailio/src/core/flags.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2001-2003 FhG Fokus |
3 | | * |
4 | | * This file is part of Kamailio, a free SIP server. |
5 | | * |
6 | | * Kamailio is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version |
10 | | * |
11 | | * Kamailio is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | /*! |
22 | | * \file |
23 | | * \brief Kamailio core :: Flags |
24 | | * \ingroup core |
25 | | * Module: \ref core |
26 | | */ |
27 | | |
28 | | |
29 | | #include <limits.h> |
30 | | #include <stdint.h> |
31 | | #include "sr_module.h" |
32 | | #include "dprint.h" |
33 | | #include "parser/msg_parser.h" |
34 | | #include "flags.h" |
35 | | #include "error.h" |
36 | | #include "stdlib.h" |
37 | | #include "hashes.h" |
38 | | #include "clist.h" |
39 | | #include "mem/mem.h" |
40 | | |
41 | | /* Script flags */ |
42 | | static flag_t sflags = 0; |
43 | | |
44 | | |
45 | | int setflag(struct sip_msg *msg, flag_t flag) |
46 | 0 | { |
47 | 0 | msg->flags |= 1u << flag; |
48 | 0 | return 1; |
49 | 0 | } |
50 | | |
51 | | int resetflag(struct sip_msg *msg, flag_t flag) |
52 | 0 | { |
53 | 0 | msg->flags &= ~(1u << flag); |
54 | 0 | return 1; |
55 | 0 | } |
56 | | |
57 | | int resetflags(struct sip_msg *msg, flag_t flags) |
58 | 0 | { |
59 | 0 | msg->flags &= ~flags; |
60 | 0 | return 1; |
61 | 0 | } |
62 | | |
63 | | int isflagset(struct sip_msg *msg, flag_t flag) |
64 | 0 | { |
65 | 0 | return (msg->flags & (1u << flag)) ? 1 : -1; |
66 | 0 | } |
67 | | |
68 | | int flag_in_range(flag_t flag) |
69 | 0 | { |
70 | 0 | if(flag > MAX_FLAG) { |
71 | 0 | LM_ERR("message flag %d too high; MAX=%d\n", flag, MAX_FLAG); |
72 | 0 | return 0; |
73 | 0 | } |
74 | 0 | return 1; |
75 | 0 | } |
76 | | |
77 | | |
78 | | int setsflagsval(flag_t val) |
79 | 0 | { |
80 | 0 | sflags = val; |
81 | 0 | return 1; |
82 | 0 | } |
83 | | |
84 | | |
85 | | int setsflag(flag_t flag) |
86 | 0 | { |
87 | 0 | sflags |= 1u << flag; |
88 | 0 | return 1; |
89 | 0 | } |
90 | | |
91 | | |
92 | | int resetsflag(flag_t flag) |
93 | 0 | { |
94 | 0 | sflags &= ~(1u << flag); |
95 | 0 | return 1; |
96 | 0 | } |
97 | | |
98 | | |
99 | | int issflagset(flag_t flag) |
100 | 0 | { |
101 | 0 | return (sflags & (1u << flag)) ? 1 : -1; |
102 | 0 | } |
103 | | |
104 | | |
105 | | flag_t getsflags(void) |
106 | 0 | { |
107 | 0 | return sflags; |
108 | 0 | } |
109 | | |
110 | | |
111 | | /* use 2^k */ |
112 | 0 | #define FLAGS_NAME_HASH_ENTRIES 32 |
113 | | |
114 | | struct flag_entry |
115 | | { |
116 | | struct flag_entry *next; |
117 | | struct flag_entry *prev; |
118 | | str name; |
119 | | int no; |
120 | | }; |
121 | | |
122 | | |
123 | | struct flag_hash_head |
124 | | { |
125 | | struct flag_entry *next; |
126 | | struct flag_entry *prev; |
127 | | }; |
128 | | |
129 | | static struct flag_hash_head name2flags[FLAGS_NAME_HASH_ENTRIES]; |
130 | | static unsigned char registered_flags[MAX_FLAG + 1]; |
131 | | |
132 | | |
133 | | void init_named_flags() |
134 | 0 | { |
135 | 0 | int r; |
136 | |
|
137 | 0 | for(r = 0; r < FLAGS_NAME_HASH_ENTRIES; r++) |
138 | 0 | clist_init(&name2flags[r], next, prev); |
139 | 0 | } |
140 | | |
141 | | |
142 | | /* returns 0 on success, -1 on error */ |
143 | | int check_flag(int n) |
144 | 0 | { |
145 | 0 | if(!flag_in_range(n)) |
146 | 0 | return -1; |
147 | 0 | if(registered_flags[n]) { |
148 | 0 | LM_WARN("flag %d is already used by a named flag\n", n); |
149 | 0 | } |
150 | 0 | return 0; |
151 | 0 | } |
152 | | |
153 | | |
154 | | inline static struct flag_entry *flag_search( |
155 | | struct flag_hash_head *lst, char *name, int len) |
156 | 0 | { |
157 | 0 | struct flag_entry *fe; |
158 | |
|
159 | 0 | clist_foreach(lst, fe, next) |
160 | 0 | { |
161 | 0 | if((fe->name.len == len) && (memcmp(fe->name.s, name, len) == 0)) { |
162 | | /* found */ |
163 | 0 | return fe; |
164 | 0 | } |
165 | 0 | } |
166 | 0 | return 0; |
167 | 0 | } |
168 | | |
169 | | |
170 | | /* returns flag entry or 0 on not found */ |
171 | | inline static struct flag_entry *get_flag_entry(char *name, int len) |
172 | 0 | { |
173 | 0 | int h; |
174 | | /* get hash */ |
175 | 0 | h = get_hash1_raw(name, len) & (FLAGS_NAME_HASH_ENTRIES - 1); |
176 | 0 | return flag_search(&name2flags[h], name, len); |
177 | 0 | } |
178 | | |
179 | | |
180 | | /* returns flag number, or -1 on error */ |
181 | | int get_flag_no(char *name, int len) |
182 | 0 | { |
183 | 0 | struct flag_entry *fe; |
184 | |
|
185 | 0 | fe = get_flag_entry(name, len); |
186 | 0 | return (fe) ? fe->no : -1; |
187 | 0 | } |
188 | | |
189 | | |
190 | | /* resgiter a new flag name and associates it with pos |
191 | | * pos== -1 => any position will do |
192 | | * returns flag pos on success (>=0) |
193 | | * -1 flag is an alias for an already existing flag |
194 | | * -2 flag already registered |
195 | | * -3 mem. alloc. failure |
196 | | * -4 invalid pos |
197 | | * -5 no free flags */ |
198 | | int register_flag(char *name, int pos) |
199 | 0 | { |
200 | 0 | struct flag_entry *e; |
201 | 0 | int len; |
202 | 0 | unsigned int r; |
203 | 0 | static unsigned int crt_flag = 0; |
204 | 0 | unsigned int last_flag; |
205 | 0 | unsigned int h; |
206 | |
|
207 | 0 | len = strlen(name); |
208 | 0 | h = get_hash1_raw(name, len) & (FLAGS_NAME_HASH_ENTRIES - 1); |
209 | | /* check if the name already exists */ |
210 | 0 | e = flag_search(&name2flags[h], name, len); |
211 | 0 | if(e) { |
212 | 0 | LM_ERR("flag %.*s already registered\n", len, name); |
213 | 0 | return -2; |
214 | 0 | } |
215 | | /* check if there is already another flag registered at pos */ |
216 | 0 | if(pos != -1) { |
217 | 0 | if((pos < 0) || (pos > MAX_FLAG)) { |
218 | 0 | LM_ERR("invalid flag %.*s position(%d)\n", len, name, pos); |
219 | 0 | return -4; |
220 | 0 | } |
221 | 0 | if(registered_flags[pos] != 0) { |
222 | 0 | LM_WARN("%.*s: flag %d already in use under another name\n", len, |
223 | 0 | name, pos); |
224 | | /* continue */ |
225 | 0 | } |
226 | 0 | } else { |
227 | | /* alloc an empty flag */ |
228 | 0 | last_flag = crt_flag + (MAX_FLAG + 1); |
229 | 0 | for(; crt_flag != last_flag; crt_flag++) { |
230 | 0 | r = crt_flag % (MAX_FLAG + 1); |
231 | 0 | if(registered_flags[r] == 0) { |
232 | 0 | pos = r; |
233 | 0 | break; |
234 | 0 | } |
235 | 0 | } |
236 | 0 | if(pos == -1) { |
237 | 0 | LM_ERR("could not register %.*s - too many flags\n", len, name); |
238 | 0 | return -5; |
239 | 0 | } |
240 | 0 | } |
241 | 0 | registered_flags[pos]++; |
242 | |
|
243 | 0 | e = pkg_malloc(sizeof(struct flag_entry)); |
244 | 0 | if(e == 0) { |
245 | 0 | PKG_MEM_ERROR; |
246 | 0 | return -3; |
247 | 0 | } |
248 | 0 | e->name.s = name; |
249 | 0 | e->name.len = len; |
250 | 0 | e->no = pos; |
251 | 0 | clist_insert(&name2flags[h], e, next, prev); |
252 | 0 | return pos; |
253 | 0 | } |
254 | | |
255 | | |
256 | | /** |
257 | | * |
258 | | */ |
259 | | int setxflag(struct sip_msg *msg, flag_t flag) |
260 | 0 | { |
261 | 0 | uint32_t fi; |
262 | 0 | uint32_t fb; |
263 | 0 | fi = flag / (sizeof(flag_t) * CHAR_BIT); |
264 | 0 | fb = flag % (sizeof(flag_t) * CHAR_BIT); |
265 | 0 | msg->xflags[fi] |= 1u << fb; |
266 | 0 | return 1; |
267 | 0 | } |
268 | | |
269 | | /** |
270 | | * |
271 | | */ |
272 | | int resetxflag(struct sip_msg *msg, flag_t flag) |
273 | 0 | { |
274 | 0 | uint32_t fi; |
275 | 0 | uint32_t fb; |
276 | 0 | fi = flag / (sizeof(flag_t) * CHAR_BIT); |
277 | 0 | fb = flag % (sizeof(flag_t) * CHAR_BIT); |
278 | 0 | msg->xflags[fi] &= ~(1u << fb); |
279 | 0 | return 1; |
280 | 0 | } |
281 | | |
282 | | /** |
283 | | * |
284 | | */ |
285 | | int isxflagset(struct sip_msg *msg, flag_t flag) |
286 | 0 | { |
287 | 0 | uint32_t fi; |
288 | 0 | uint32_t fb; |
289 | 0 | fi = flag / (sizeof(flag_t) * CHAR_BIT); |
290 | 0 | fb = flag % (sizeof(flag_t) * CHAR_BIT); |
291 | 0 | return (msg->xflags[fi] & (1u << fb)) ? 1 : -1; |
292 | 0 | } |