525
|
1 /********************************************************************************************************* |
|
2 * Software License Agreement (BSD License) * |
|
3 * Author: Sebastien Decugis <sdecugis@nict.go.jp> * |
|
4 * * |
|
5 * Copyright (c) 2010, WIDE Project and NICT * |
|
6 * All rights reserved. * |
|
7 * * |
|
8 * Redistribution and use of this software in source and binary forms, with or without modification, are * |
|
9 * permitted provided that the following conditions are met: * |
|
10 * * |
|
11 * * Redistributions of source code must retain the above * |
|
12 * copyright notice, this list of conditions and the * |
|
13 * following disclaimer. * |
|
14 * * |
|
15 * * Redistributions in binary form must reproduce the above * |
|
16 * copyright notice, this list of conditions and the * |
|
17 * following disclaimer in the documentation and/or other * |
|
18 * materials provided with the distribution. * |
|
19 * * |
|
20 * * Neither the name of the WIDE Project or NICT nor the * |
|
21 * names of its contributors may be used to endorse or * |
|
22 * promote products derived from this software without * |
|
23 * specific prior written permission of WIDE Project and * |
|
24 * NICT. * |
|
25 * * |
|
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * |
|
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * |
|
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * |
|
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * |
|
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * |
|
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * |
|
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * |
|
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * |
|
34 *********************************************************************************************************/ |
|
35 |
|
36 /* |
|
37 * This extension allows to perform some pattern-matching on an AVP |
|
38 * and send the message to a server accordingly. |
|
39 * See rt_ereg.conf.sample file for the format of the configuration file. |
|
40 */ |
|
41 |
|
42 #include "rtereg.h" |
|
43 |
|
44 /* The configuration structure */ |
|
45 struct rtereg_conf rtereg_conf; |
|
46 |
|
47 #ifndef HAVE_REG_STARTEND |
|
48 static char * buf = NULL; |
|
49 static size_t bufsz; |
|
50 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; |
|
51 #endif /* HAVE_REG_STARTEND */ |
|
52 |
|
53 static int proceed(char * value, size_t len, struct fd_list * candidates) |
|
54 { |
|
55 int i; |
|
56 |
|
57 for (i = 0; i < rtereg_conf.rules_nb; i++) { |
|
58 /* Does this pattern match the value? */ |
|
59 struct rtereg_rule * r = &rtereg_conf.rules[i]; |
|
60 int err = 0; |
|
61 struct fd_list * c; |
|
62 |
|
63 #ifdef HAVE_REG_STARTEND |
|
64 { |
|
65 regmatch_t pmatch[1]; |
|
66 memset(pmatch, 0, sizeof(pmatch)); |
|
67 pmatch[0].rm_so = 0; |
|
68 pmatch[0].rm_eo = len; |
|
69 err = regexec(&r->preg, value, 0, pmatch, REG_STARTEND); |
|
70 } |
|
71 #else /* HAVE_REG_STARTEND */ |
|
72 { |
|
73 /* We have a 0-terminated string */ |
|
74 err = regexec(&r->preg, value, 0, NULL, 0); |
|
75 } |
|
76 #endif /* HAVE_REG_STARTEND */ |
|
77 |
|
78 if (err == REG_NOMATCH) |
|
79 continue; |
|
80 |
|
81 if (err != 0) { |
|
82 char * errstr; |
|
83 size_t bl; |
|
84 |
|
85 /* Error while compiling the regex */ |
|
86 TRACE_DEBUG(INFO, "Error while executing the regular expression '%s':", r->pattern); |
|
87 |
|
88 /* Get the error message size */ |
|
89 bl = regerror(err, &r->preg, NULL, 0); |
|
90 |
|
91 /* Alloc the buffer for error message */ |
|
92 CHECK_MALLOC( errstr = malloc(bl) ); |
|
93 |
|
94 /* Get the error message content */ |
|
95 regerror(err, &r->preg, errstr, bl); |
|
96 TRACE_DEBUG(INFO, "\t%s", errstr); |
|
97 |
|
98 /* Free the buffer, return the error */ |
|
99 free(errstr); |
|
100 |
|
101 return (err == REG_ESPACE) ? ENOMEM : EINVAL; |
|
102 } |
|
103 |
|
104 /* From this point, the expression matched the AVP value */ |
|
105 TRACE_DEBUG(FULL, "[rt_ereg] Match: '%s' to value '%.*s' => '%s' += %d", |
|
106 r->pattern, |
|
107 len, |
|
108 value, |
|
109 r->server, |
|
110 r->score); |
|
111 |
|
112 for (c = candidates->next; c != candidates; c = c->next) { |
|
113 struct rtd_candidate * cand = (struct rtd_candidate *)c; |
|
114 |
|
115 if (strcmp(r->server, cand->diamid) == 0) { |
|
116 cand->score += r->score; |
|
117 break; |
|
118 } |
|
119 } |
|
120 }; |
|
121 |
|
122 return 0; |
|
123 } |
|
124 |
|
125 /* The callback called on new messages */ |
|
126 static int rtereg_out(void * cbdata, struct msg * msg, struct fd_list * candidates) |
|
127 { |
|
128 struct avp * avp = NULL; |
|
129 |
|
130 TRACE_ENTRY("%p %p %p", cbdata, msg, candidates); |
|
131 |
|
132 CHECK_PARAMS(msg && candidates); |
|
133 |
|
134 /* Check if it is worth processing the message */ |
|
135 if (FD_IS_LIST_EMPTY(candidates)) { |
|
136 return 0; |
|
137 } |
|
138 |
|
139 /* Now search the AVP in the message */ |
|
140 CHECK_FCT( fd_msg_search_avp ( msg, rtereg_conf.avp, &avp ) ); |
|
141 if (avp != NULL) { |
|
142 struct avp_hdr * ahdr = NULL; |
|
143 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) ); |
|
144 if (ahdr->avp_value != NULL) { |
|
145 int ret; |
|
146 |
|
147 #ifndef HAVE_REG_STARTEND |
|
148 /* Lock the buffer */ |
|
149 CHECK_POSIX( pthread_mutex_lock(&mtx) ); |
|
150 |
|
151 /* Augment the buffer if needed */ |
|
152 if (ahdr->avp_value->os.len >= bufsz) { |
|
153 CHECK_MALLOC_DO( buf = realloc(buf, ahdr->avp_value->os.len + 1), |
|
154 { pthread_mutex_unlock(&mtx); return ENOMEM; } ); |
|
155 } |
|
156 |
|
157 /* Copy the AVP value */ |
|
158 memcpy(buf, ahdr->avp_value->os.data, ahdr->avp_value->os.len); |
|
159 buf[ahdr->avp_value->os.len] = '\0'; |
|
160 |
|
161 /* Now apply the rules */ |
|
162 ret = proceed(buf, ahdr->avp_value->os.len, candidates); |
|
163 |
|
164 CHECK_POSIX(pthread_mutex_unlock(&mtx)); |
|
165 |
|
166 CHECK_FCT(ret); |
|
167 #else /* HAVE_REG_STARTEND */ |
|
168 CHECK_FCT( proceed(ahdr->avp_value->os.data, ahdr->avp_value->os.len, candidates) ); |
|
169 #endif /* HAVE_REG_STARTEND */ |
|
170 } |
|
171 } |
|
172 |
|
173 return 0; |
|
174 } |
|
175 |
|
176 /* handler */ |
|
177 static struct fd_rt_out_hdl * rtereg_hdl = NULL; |
|
178 |
|
179 /* entry point */ |
|
180 static int rtereg_entry(char * conffile) |
|
181 { |
|
182 TRACE_ENTRY("%p", conffile); |
|
183 |
|
184 /* Initialize the configuration */ |
|
185 memset(&rtereg_conf, 0, sizeof(rtereg_conf)); |
|
186 |
|
187 /* Parse the configuration file */ |
|
188 CHECK_FCT( rtereg_conf_handle(conffile) ); |
|
189 |
|
190 /* Register the callback */ |
|
191 CHECK_FCT( fd_rt_out_register( rtereg_out, NULL, 1, &rtereg_hdl ) ); |
|
192 |
|
193 /* We're done */ |
|
194 return 0; |
|
195 } |
|
196 |
|
197 /* Unload */ |
|
198 void fd_ext_fini(void) |
|
199 { |
|
200 int i; |
|
201 TRACE_ENTRY(); |
|
202 |
|
203 /* Unregister the cb */ |
|
204 CHECK_FCT_DO( fd_rt_out_unregister ( rtereg_hdl, NULL ), /* continue */ ); |
|
205 |
|
206 /* Destroy the data */ |
|
207 if (rtereg_conf.rules) |
|
208 for (i = 0; i < rtereg_conf.rules_nb; i++) { |
|
209 free(rtereg_conf.rules[i].pattern); |
|
210 free(rtereg_conf.rules[i].server); |
|
211 regfree(&rtereg_conf.rules[i].preg); |
|
212 } |
|
213 free(rtereg_conf.rules); |
|
214 #ifndef HAVE_REG_STARTEND |
|
215 free(buf); |
|
216 #endif /* HAVE_REG_STARTEND */ |
|
217 |
|
218 /* Done */ |
|
219 return ; |
|
220 } |
|
221 |
|
222 EXTENSION_ENTRY("rt_ereg", rtereg_entry); |