1 /*
2 Copyright (C) 2003-2009 Thomas Ries <tries@gmx.net>
3
4 This file is part of Siproxd.
5
6 Siproxd 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 Siproxd is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warrantry 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 Siproxd; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22 #include <string.h>
23 #include <stdio.h>
24 #include <unistd.h>
25
26 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <sys/socket.h>
30
31 #include <osipparser2/osip_parser.h>
32
33 #include "siproxd.h"
34 #include "log.h"
35 #include "plugins.h"
36
37 static char const ident[]="$Id: plugins.c 499 2014-09-26 21:37:21Z hb9xar $";
38
39 /* configuration storage */
40 extern struct siproxd_config configuration;
41
42 /* Plugin "database" - queue header */
43 plugin_def_t *siproxd_plugins=NULL;
44
45 /* code */
46 typedef int (*func_plugin_init_t)(plugin_def_t *plugin_def);
47 typedef int (*func_plugin_process_t)(int stage, sip_ticket_t *ticket);
48 typedef int (*func_plugin_end_t)(plugin_def_t *plugin_def);
49
50
51 /*
52 * Load the plugins in the order as specified in the config file.
53 * This is done once, starts with empty plugin list
54 */
load_plugins(void)55 int load_plugins (void) {
56 int sts;
57 int i;
58 char path[PATH_STRING_SIZE];
59
60 lt_dlhandle handle=NULL;
61 plugin_def_t *cur=NULL;
62 plugin_def_t *last=siproxd_plugins;
63
64 func_plugin_init_t plugin_init = NULL;
65 func_plugin_process_t plugin_process = NULL;
66 func_plugin_end_t plugin_end = NULL;
67
68 /* initialize the libtool dynamic loader */
69 LTDL_SET_PRELOADED_SYMBOLS();
70 sts = lt_dlinit();
71 if (sts != 0) {
72 ERROR("ltdl (libtool dynamic loader) initialization failed.");
73 return STS_FAILURE;
74 }
75
76 /* find plugins to load from config file */
77 for (i=0; i<configuration.load_plugin.used; i++) {
78 /* construct the path where the plugin is */
79 if (configuration.plugin_dir) {
80 strcpy(path, configuration.plugin_dir);
81 strcat(path, configuration.load_plugin.string[i]);
82 } else {
83 strcpy(path, configuration.load_plugin.string[i]);
84 }
85
86 /* dlopen() the plugin */
87 DEBUGC(DBCLASS_PLUGIN, "load_plugins: opening plugin [%s]", path);
88 handle=lt_dlopen(path);
89
90 if (handle == NULL) {
91 /* complain and next plugin */
92 ERROR("plugin %s not found - skipped", configuration.load_plugin.string[i]);
93 continue;
94 }
95
96 /* find the plugin_process and plugin_end functions and store them */
97 plugin_init = lt_dlsym (handle, "plugin_init");
98 plugin_process = lt_dlsym (handle, "plugin_process");
99 plugin_end = lt_dlsym (handle, "plugin_end");
100
101 DEBUGC(DBCLASS_PLUGIN, "load_plugins: init=%p, process=%p, end=%p",
102 plugin_init, plugin_process, plugin_end);
103
104 /* all functions present? */
105 if (plugin_init && plugin_process && plugin_end) {
106 /* allocate an new item in plugins array */
107 cur=malloc(sizeof(plugin_def_t));
108 memset(cur,0,sizeof(plugin_def_t));
109
110 /* call the init function */
111 sts=(*plugin_init)(cur);
112
113 /* Tell the user something about the plugin we have just loaded */
114 INFO("Plugin '%s' [%s] loaded with %s, exemask=0x%X",
115 cur->name, cur->desc, (sts==STS_SUCCESS)?"success":"failure",
116 cur->exe_mask);
117
118 /* check return status from plugin - failure leads to unload */
119 if (sts != STS_SUCCESS) {
120 /* complain and unload the plugin */
121 ERROR("Plugin '%s' did fail to load.", cur->name);
122 sts=(*plugin_end)(cur);
123 free(cur);
124 continue;
125 }
126
127 /* check API version that the plugin was biuilt against */
128 if (cur->api_version != SIPROXD_API_VERSION) {
129 /* complain and unload the plugin */
130 ERROR("Plugin '%s' does not support correct API version. "
131 "Please compile plugin with correct siproxd version.",
132 cur->name);
133 sts=(*plugin_end)(cur);
134 free(cur);
135 continue;
136 }
137
138 /* store the function pointers */
139 cur->plugin_process = plugin_process;
140 cur->plugin_end = plugin_end;
141 cur->dlhandle = handle;
142
143 /* store forward pointer */
144 if (siproxd_plugins == NULL) {
145 /* first in chain */
146 siproxd_plugins = cur;
147 last=cur;
148 cur=NULL;
149 } else {
150 /* not first in chain */
151 last->next=(void*)cur;
152 last=cur;
153 cur=NULL;
154 }
155 } else {
156 /* complain and dlclose the handle...*/
157 ERROR("plugin %s does not provide correct API functions - skipped",
158 configuration.load_plugin.string[i]);
159 INFO("make sure to specify plugin_<name>.la to load and not the .so!");
160 lt_dlclose(handle);
161 }
162 }
163 return STS_SUCCESS;
164 }
165
166
167 /*
168 * Called at different stages of SIP processing.
169 */
call_plugins(int stage,sip_ticket_t * ticket)170 int call_plugins(int stage, sip_ticket_t *ticket) {
171 plugin_def_t *cur;
172 int sts;
173 func_plugin_process_t plugin_process;
174
175 /* sanity check, beware plugins from crappy stuff
176 * applies when SIP message has been parsed */
177 if ((stage > PLUGIN_PROCESS_RAW) && (!ticket || !ticket->sipmsg)) return STS_FAILURE;
178
179 /* for each plugin in plugins, do */
180 for (cur=siproxd_plugins; cur != NULL; cur = cur->next) {
181 /* check stage bitmask, if plugin wants to be called do so */
182 if (cur->exe_mask & stage) {
183 plugin_process=cur->plugin_process;
184 sts=(*plugin_process)(stage, ticket);
185 switch (stage) {
186 /* PLUGIN_PROCESS_RAW can be prematurely ended by plugin -
187 plugin determines that the UDP message is to be discarded */
188 case (PLUGIN_PROCESS_RAW):
189 /* return with the plugins status back to the caller */
190 if (sts == STS_FAILURE) {
191 DEBUGC(DBCLASS_PLUGIN, "call_plugins: PLUGIN_PROCESS_RAW "
192 "prematurely ending plugin processing in module "
193 "%s sts=STS_FAILURE", cur->name);
194 return sts;
195 }
196 break;
197 /* PLUGIN_VALIDATE can be prematurely ended by plugin -
198 plugin determines that the UDP message is to be discarded */
199 case (PLUGIN_VALIDATE):
200 /* return with the plugins status back to the caller */
201 if (sts == STS_FAILURE) {
202 DEBUGC(DBCLASS_PLUGIN, "call_plugins: PLUGIN_VALIDATE "
203 "prematurely ending plugin processing in module "
204 "%s sts=STS_FAILURE", cur->name);
205 return sts;
206 }
207 break;
208 /* PLUGIN_DETERMINE_TARGET can be prematurely ended by plugin -
209 plugin processes and sends the final SIP message itself */
210 case (PLUGIN_DETERMINE_TARGET):
211 /* return with the plugins status back to the caller */
212 if (sts == STS_SIP_SENT) {
213 DEBUGC(DBCLASS_PLUGIN, "call_plugins: PLUGIN_DETERMINE_TARGET "
214 "prematurely ending plugin processing in module "
215 "%s sts=STS_SIP_SENT", cur->name);
216 return sts;
217 }
218 break;
219 default:
220 break;
221 } /* switch*/
222 } /* if */
223 } /* for */
224
225 return STS_SUCCESS;
226 }
227
228
229 /*
230 * At termination of siproxd "unloads" the plugins.
231 * Actually gives the plugins the chance to cleanup whatever they want.
232 * The plugins are called in reversed order of loading (last loaded is
233 * unloaded first).
234 */
unload_plugins(void)235 int unload_plugins(void) {
236 plugin_def_t *cur, *last;
237 int sts;
238 func_plugin_end_t plugin_end;
239
240 /* for each plugin in plugins do (start at the end of the plugin list) */
241 DEBUGC(DBCLASS_PLUGIN, "unloading dynamic plugins");
242
243 /* call plugin_end function - the plugin may need to cleanup as well... */
244 while (siproxd_plugins) {
245 /* search the end */
246 last=NULL;
247 for (cur=siproxd_plugins; cur->next != NULL; cur = cur->next) {last=cur;}
248
249 plugin_end=cur->plugin_end;
250 DEBUGC(DBCLASS_PLUGIN, "unload_plugins: '%s' unloading ptr=%p",
251 cur->name, cur);
252 sts=(*plugin_end)(cur);
253 DEBUGC(DBCLASS_PLUGIN, "unload_plugins: status=%s",
254 (sts==STS_SUCCESS)?"success":"failure");
255
256 /* dlclose */
257 sts = lt_dlclose(cur->dlhandle);
258 if (sts != 0) {
259 ERROR("lt_dlclose() failed, ptr=%p", cur);
260 }
261
262 /* deallocate plugins list item */
263 if (last) last->next=NULL;
264 free(cur);
265
266 /* I don't like this */
267 if (cur == siproxd_plugins) siproxd_plugins=NULL;
268 }
269
270 /* shutdown ltdl */
271 sts = lt_dlexit();
272 if (sts != 0) {
273 ERROR("lt_dlexit() failed");
274 }
275
276 return STS_SUCCESS;
277 }
278