1 /*
2  * Copyright (C) 2002-2003 Fhg Fokus
3  * Copyright (C) 2006 iptego GmbH
4  *
5  * This file is part of SEMS, a free SIP media server.
6  *
7  * SEMS is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version. This program is released under
11  * the GPL with the additional exemption that compiling, linking,
12  * and/or using OpenSSL is allowed.
13  *
14  * For a license to use the SEMS software under conditions
15  * other than those described here, or to purchase support for this
16  * software, please contact iptel.org by e-mail at the following addresses:
17  *    info@iptel.org
18  *
19  * SEMS is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28 
29 #include "AmPlugIn.h"
30 #include "AmConfig.h"
31 #include "AmApi.h"
32 #include "AmUtils.h"
33 //#include "AmSdp.h"
34 #include "AmSipDispatcher.h"
35 //#include "AmServer.h"
36 
37 #include "amci/amci.h"
38 #include "amci/codecs.h"
39 #include "log.h"
40 
41 #include <sys/types.h>
42 #include <dirent.h>
43 #include <dlfcn.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <libgen.h>
47 
48 #include <set>
49 #include <vector>
50 #include <algorithm>
51 using std::set;
52 
pcm16_bytes2samples(long h_codec,unsigned int num_bytes)53 static unsigned int pcm16_bytes2samples(long h_codec, unsigned int num_bytes)
54 {
55   return num_bytes / 2;
56 }
57 
pcm16_samples2bytes(long h_codec,unsigned int num_samples)58 static unsigned int pcm16_samples2bytes(long h_codec, unsigned int num_samples)
59 {
60   return num_samples * 2;
61 }
62 
tevent_bytes2samples(long h_codec,unsigned int num_bytes)63 static unsigned int tevent_bytes2samples(long h_codec, unsigned int num_bytes)
64 {
65   return num_bytes;
66 }
67 
tevent_samples2bytes(long h_codec,unsigned int num_samples)68 static unsigned int tevent_samples2bytes(long h_codec, unsigned int num_samples)
69 {
70   return num_samples;
71 }
72 
73 amci_codec_t _codec_pcm16 = {
74   CODEC_PCM16,
75   NULL,
76   NULL,
77   NULL,
78   NULL,
79   NULL,
80   pcm16_bytes2samples,
81   pcm16_samples2bytes,
82   NULL
83 };
84 
85 amci_codec_t _codec_tevent = {
86   CODEC_TELEPHONE_EVENT,
87   NULL,
88   NULL,
89   NULL,
90   NULL,
91   NULL,
92   tevent_bytes2samples,
93   tevent_samples2bytes,
94   NULL
95 };
96 
97 amci_payload_t _payload_tevent = {
98   -1,
99   "telephone-event",
100   8000, // telephone-event has always SR 8000
101   8000,
102   -1,
103   CODEC_TELEPHONE_EVENT,
104   -1
105 };
106 
107 AmPlugIn* AmPlugIn::_instance=0;
108 
AmPlugIn()109 AmPlugIn::AmPlugIn()
110   : dynamic_pl(DYNAMIC_PAYLOAD_TYPE_START)
111     //ctrlIface(NULL)
112 {
113 }
114 
115 
delete_plugin_factory(std::pair<string,AmPluginFactory * > pf)116 static void delete_plugin_factory(std::pair<string, AmPluginFactory*> pf)
117 {
118   DBG("decreasing reference to plug-in factory: %s\n", pf.first.c_str());
119   dec_ref(pf.second);
120 
121 }
122 
~AmPlugIn()123 AmPlugIn::~AmPlugIn()
124 {
125   std::for_each(module_objects.begin(), module_objects.end(), delete_plugin_factory);
126   std::for_each(name2seh.begin(), name2seh.end(), delete_plugin_factory);
127   std::for_each(name2base.begin(), name2base.end(), delete_plugin_factory);
128   std::for_each(name2di.begin(), name2di.end(), delete_plugin_factory);
129   std::for_each(name2logfac.begin(), name2logfac.end(), delete_plugin_factory);
130 
131   // if _DEBUG is set do not unload shared libs to allow better debugging
132 #ifndef _DEBUG
133   for(vector<void*>::iterator it=dlls.begin();it!=dlls.end();++it)
134     dlclose(*it);
135 #endif
136 }
137 
dispose()138 void AmPlugIn::dispose()
139 {
140   if (_instance) {
141     delete _instance;
142   }
143 }
144 
instance()145 AmPlugIn* AmPlugIn::instance()
146 {
147   if(!_instance)
148     _instance = new AmPlugIn();
149 
150   return _instance;
151 }
152 
init()153 void AmPlugIn::init() {
154   vector<string> excluded_payloads_v =
155     explode(AmConfig::ExcludePayloads, ";");
156   for (vector<string>::iterator it =
157 	 excluded_payloads_v.begin();
158        it != excluded_payloads_v.end();it++)
159     excluded_payloads.insert(*it);
160 
161   DBG("adding built-in codecs...\n");
162   addCodec(&_codec_pcm16);
163   addCodec(&_codec_tevent);
164   addPayload(&_payload_tevent);
165 }
166 
load(const string & directory,const string & plugins)167 int AmPlugIn::load(const string& directory, const string& plugins)
168 {
169   int err=0;
170 
171   vector<AmPluginFactory*> loaded_plugins;
172 
173   if (!plugins.length()) {
174     INFO("AmPlugIn: loading modules in directory '%s':\n", directory.c_str());
175 
176     DIR* dir = opendir(directory.c_str());
177     if (!dir){
178       ERROR("while opening plug-in directory (%s): %s\n",
179 	    directory.c_str(), strerror(errno));
180       return -1;
181     }
182 
183     vector<string> excluded_plugins = explode(AmConfig::ExcludePlugins, ";");
184     set<string> excluded_plugins_s;
185     for (vector<string>::iterator it = excluded_plugins.begin();
186 	 it != excluded_plugins.end();it++)
187       excluded_plugins_s.insert(*it);
188 
189     struct dirent* entry;
190 
191     while( ((entry = readdir(dir)) != NULL) && (err == 0) ){
192       string plugin_name = string(entry->d_name);
193 
194       if(plugin_name.find(".so",plugin_name.length()-3) == string::npos ){
195         continue;
196       }
197 
198       if (excluded_plugins_s.find(plugin_name.substr(0, plugin_name.length()-3))
199 	  != excluded_plugins_s.end()) {
200 	DBG("skipping excluded plugin %s\n", plugin_name.c_str());
201 	continue;
202       }
203 
204       string plugin_file = directory + "/" + plugin_name;
205 
206       DBG("loading %s ...\n",plugin_file.c_str());
207       if( (err = loadPlugIn(plugin_file, plugin_name, loaded_plugins)) < 0 ) {
208         ERROR("while loading plug-in '%s'\n",plugin_file.c_str());
209         return -1;
210       }
211     }
212 
213     closedir(dir);
214   }
215   else {
216     INFO("AmPlugIn: loading modules: '%s'\n", plugins.c_str());
217 
218     vector<string> plugins_list = explode(plugins, ";");
219     for (vector<string>::iterator it = plugins_list.begin();
220        it != plugins_list.end(); it++) {
221       string plugin_file = *it;
222       if (plugin_file == "sipctrl") {
223 	WARN("sipctrl is integrated into the core, loading sipctrl "
224 	     "module is not necessary any more\n");
225 	WARN("please update your configuration to not load sipctrl module\n");
226 	continue;
227       }
228 
229       if(plugin_file.find(".so",plugin_file.length()-3) == string::npos )
230         plugin_file+=".so";
231 
232       plugin_file = directory + "/"  + plugin_file;
233       DBG("loading %s...\n",plugin_file.c_str());
234       if( (err = loadPlugIn(plugin_file, plugin_file, loaded_plugins)) < 0 ) {
235         ERROR("while loading plug-in '%s'\n",plugin_file.c_str());
236         // be strict here: if plugin not loaded, stop!
237         return err;
238       }
239     }
240   }
241 
242   DBG("AmPlugIn: modules loaded.\n");
243   DBG("Initializing %zd plugins...\n", loaded_plugins.size());
244   for (vector<AmPluginFactory*>::iterator it =
245 	 loaded_plugins.begin(); it != loaded_plugins.end(); it++) {
246     int err = (*it)->onLoad();
247     if(err)
248       return err;
249   }
250 
251   return 0;
252 }
253 
registerLoggingPlugins()254 void AmPlugIn::registerLoggingPlugins() {
255   // init logging facilities
256   for(std::map<std::string,AmLoggingFacility*>::iterator it = name2logfac.begin();
257       it != name2logfac.end(); it++){
258     // register for receiving logging messages
259     register_log_hook(it->second);
260   }
261 }
262 
set_load_rtld_global(const string & plugin_name)263 void AmPlugIn::set_load_rtld_global(const string& plugin_name) {
264   rtld_global_plugins.insert(plugin_name);
265 }
266 
loadPlugIn(const string & file,const string & plugin_name,vector<AmPluginFactory * > & plugins)267 int AmPlugIn::loadPlugIn(const string& file, const string& plugin_name,
268 			 vector<AmPluginFactory*>& plugins)
269 {
270   AmPluginFactory* plugin = NULL; // default: not loaded
271   int dlopen_flags = RTLD_NOW;
272 
273   char* pname = strdup(plugin_name.c_str());
274   char* bname = basename(pname);
275 
276   // dsm, ivr and py_sems need RTLD_GLOBAL
277   if (!strcmp(bname, "dsm.so") || !strcmp(bname, "ivr.so") ||
278       !strcmp(bname, "py_sems.so") || !strcmp(bname, "sbc.so") ||
279       !strcmp(bname, "diameter_client.so") || !strcmp(bname, "registrar_client.so") ||
280       !strcmp(bname, "uac_auth.so") || !strcmp(bname, "msg_storage.so")
281       ) {
282       dlopen_flags = RTLD_NOW | RTLD_GLOBAL;
283       DBG("using RTLD_NOW | RTLD_GLOBAL to dlopen '%s'\n", file.c_str());
284   }
285 
286   // possibly others
287   for (std::set<string>::iterator it=rtld_global_plugins.begin();
288        it!=rtld_global_plugins.end();it++) {
289     if (!strcmp(bname, it->c_str())) {
290       dlopen_flags = RTLD_NOW | RTLD_GLOBAL;
291       DBG("using RTLD_NOW | RTLD_GLOBAL to dlopen '%s'\n", file.c_str());
292       break;
293     }
294   }
295   free(pname);
296 
297   void* h_dl = dlopen(file.c_str(),dlopen_flags);
298 
299   if(!h_dl){
300     ERROR("AmPlugIn::loadPlugIn: %s: %s\n",file.c_str(),dlerror());
301     return -1;
302   }
303 
304   FactoryCreate fc = NULL;
305   amci_exports_t* exports = (amci_exports_t*)dlsym(h_dl,"amci_exports");
306 
307   bool has_sym=false;
308   if(exports){
309     if(loadAudioPlugIn(exports))
310       goto error;
311     goto end;
312   }
313 
314   if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_SESSION_EXPORT_STR)) != NULL){
315     plugin = (AmPluginFactory*)fc();
316     if(loadAppPlugIn(plugin))
317       goto error;
318     has_sym=true;
319     if (NULL != plugin) plugins.push_back(plugin);
320   }
321   if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_SESSION_EVENT_HANDLER_EXPORT_STR)) != NULL){
322     plugin = (AmPluginFactory*)fc();
323     if(loadSehPlugIn(plugin))
324       goto error;
325     has_sym=true;
326     if (NULL != plugin) plugins.push_back(plugin);
327   }
328   if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_PLUGIN_EXPORT_STR)) != NULL){
329     plugin = (AmPluginFactory*)fc();
330     if(loadBasePlugIn(plugin))
331       goto error;
332     has_sym=true;
333     if (NULL != plugin) plugins.push_back(plugin);
334   }
335   if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_PLUGIN_CLASS_EXPORT_STR)) != NULL){
336     plugin = (AmPluginFactory*)fc();
337     if(loadDiPlugIn(plugin))
338       goto error;
339     has_sym=true;
340     if (NULL != plugin) plugins.push_back(plugin);
341   }
342 
343   if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_LOG_FACILITY_EXPORT_STR)) != NULL){
344     plugin = (AmPluginFactory*)fc();
345     if(loadLogFacPlugIn(plugin))
346       goto error;
347     has_sym=true;
348     if (NULL != plugin) plugins.push_back(plugin);
349   }
350 
351   if(!has_sym){
352     ERROR("Plugin type could not be detected (%s)(%s)\n",file.c_str(),dlerror());
353     goto error;
354   }
355 
356  end:
357   dlls.push_back(h_dl);
358   return 0;
359 
360  error:
361   dlclose(h_dl);
362   return -1;
363 }
364 
365 
fileFormat(const string & fmt_name,const string & ext)366 amci_inoutfmt_t* AmPlugIn::fileFormat(const string& fmt_name, const string& ext)
367 {
368   if(!fmt_name.empty()){
369 
370     std::map<std::string,amci_inoutfmt_t*>::iterator it = file_formats.find(fmt_name);
371     if ((it != file_formats.end()) &&
372 	(ext.empty() || (ext == it->second->ext)))
373       return it->second;
374   }
375   else if(!ext.empty()){
376 
377     std::map<std::string,amci_inoutfmt_t*>::iterator it = file_formats.begin();
378     for(;it != file_formats.end();++it){
379       if(ext == it->second->ext)
380 	return it->second;
381     }
382   }
383 
384   return 0;
385 }
386 
codec(int id)387 amci_codec_t* AmPlugIn::codec(int id)
388 {
389   std::map<int,amci_codec_t*>::const_iterator it = codecs.find(id);
390   if(it != codecs.end())
391     return it->second;
392 
393   return 0;
394 }
395 
payload(int payload_id) const396 amci_payload_t*  AmPlugIn::payload(int payload_id) const
397 {
398   std::map<int,amci_payload_t*>::const_iterator it = payloads.find(payload_id);
399   if(it != payloads.end())
400     return it->second;
401 
402   return 0;
403 }
404 
getSdpFormatParameters(int codec_id,bool is_offer,const string & fmt_params_in)405 string AmPlugIn::getSdpFormatParameters(int codec_id, bool is_offer, const string& fmt_params_in) {
406   amci_codec_t* c = codec(codec_id);
407   if (NULL == c)
408     return ""; // empty for unsupported codec
409 
410   if (NULL == c->negotiate_fmt)
411     return ""; // empty if codec doesn't know either
412 
413   char out_fmt[256] = { '\0' };
414   if ((c->negotiate_fmt)(is_offer ? 1:0, fmt_params_in.c_str(), out_fmt, 256) >=0 )
415     return string(out_fmt);
416 
417   return "";
418 }
419 
getDynPayload(const string & name,int rate,int encoding_param) const420 int AmPlugIn::getDynPayload(const string& name, int rate, int encoding_param) const {
421   // find a dynamic payload by name/rate and encoding_param (channels, if > 0)
422   for(std::map<int, amci_payload_t*>::const_iterator pl_it = payloads.begin();
423       pl_it != payloads.end(); ++pl_it)
424     if( (!strcasecmp(name.c_str(),pl_it->second->name)
425 	 && (rate == pl_it->second->advertised_sample_rate)) ) {
426       if ((encoding_param > 0) && (pl_it->second->channels > 0) &&
427 	  (encoding_param != pl_it->second->channels))
428 	continue;
429 
430       return pl_it->first;
431     }
432   // not found
433   return -1;
434 }
435 
436 /** return 0, or -1 in case of error. */
getPayloads(vector<SdpPayload> & pl_vec) const437 void AmPlugIn::getPayloads(vector<SdpPayload>& pl_vec) const
438 {
439   for (std::map<int,int>::const_iterator it = payload_order.begin(); it != payload_order.end(); ++it) {
440     std::map<int,amci_payload_t*>::const_iterator pl_it = payloads.find(it->second);
441     if(pl_it != payloads.end()){
442       // if channels==2 use that value; otherwise don't add channels param
443       pl_vec.push_back(SdpPayload(pl_it->first, pl_it->second->name, pl_it->second->advertised_sample_rate, pl_it->second->channels==2?2:0));
444     } else {
445       ERROR("Payload %d (from the payload_order map) was not found in payloads map!\n", it->second);
446     }
447   }
448 }
449 
subtype(amci_inoutfmt_t * iofmt,int subtype)450 amci_subtype_t* AmPlugIn::subtype(amci_inoutfmt_t* iofmt, int subtype)
451 {
452   if(!iofmt)
453     return 0;
454 
455   amci_subtype_t* st = iofmt->subtypes;
456   if(subtype<0) // default subtype wanted
457     return st;
458 
459   for(;;st++){
460     if(!st || st->type<0) break;
461     if(st->type == subtype)
462       return st;
463   }
464 
465   return 0;
466 }
467 
subtype(amci_inoutfmt_t * iofmt,const string & subtype_name)468 amci_subtype_t* AmPlugIn::subtype(amci_inoutfmt_t* iofmt, const string& subtype_name) {
469   if(!iofmt)
470     return NULL;
471 
472   DBG("looking for subtype '%s'\n", subtype_name.c_str());
473   amci_subtype_t* st = iofmt->subtypes;
474   if(subtype_name.empty()) // default subtype wanted
475     return st;
476 
477   for(;;st++){
478     if(!st || st->type<0) break;
479     if(st->name == subtype_name) {
480       return st;
481     }
482   }
483   return NULL;
484 }
485 
getFactory4App(const string & app_name)486 AmSessionFactory* AmPlugIn::getFactory4App(const string& app_name)
487 {
488   AmSessionFactory* res = NULL;
489 
490   name2app_mut.lock();
491   std::map<std::string,AmSessionFactory*>::iterator it = name2app.find(app_name);
492   if(it != name2app.end())
493     res = it->second;
494   name2app_mut.unlock();
495 
496   return res;
497 }
498 
getFactory4Seh(const string & name)499 AmSessionEventHandlerFactory* AmPlugIn::getFactory4Seh(const string& name)
500 {
501   std::map<std::string,AmSessionEventHandlerFactory*>::iterator it = name2seh.find(name);
502   if(it != name2seh.end())
503     return it->second;
504   return 0;
505 }
506 
getFactory4Di(const string & name)507 AmDynInvokeFactory* AmPlugIn::getFactory4Di(const string& name)
508 {
509   std::map<std::string,AmDynInvokeFactory*>::iterator it = name2di.find(name);
510   if(it != name2di.end())
511     return it->second;
512   return 0;
513 }
514 
getFactory4LogFaclty(const string & name)515 AmLoggingFacility* AmPlugIn::getFactory4LogFaclty(const string& name)
516 {
517   std::map<std::string,AmLoggingFacility*>::iterator it = name2logfac.find(name);
518   if(it != name2logfac.end())
519     return it->second;
520   return 0;
521 }
522 
loadAudioPlugIn(amci_exports_t * exports)523 int AmPlugIn::loadAudioPlugIn(amci_exports_t* exports)
524 {
525   if(!exports){
526     ERROR("audio plug-in doesn't contain any exports !\n");
527     return -1;
528   }
529 
530   if (exports->module_load) {
531     if (exports->module_load(AmConfig::ModConfigPath.c_str()) < 0) {
532       ERROR("initializing audio plug-in!\n");
533       return -1;
534     }
535   }
536 
537   for( amci_codec_t* c=exports->codecs;
538        c->id>=0; c++ ){
539 
540     if(addCodec(c))
541       goto error;
542   }
543 
544   for( amci_payload_t* p=exports->payloads;
545        p->name; p++ ){
546 
547     if(addPayload(p))
548       goto error;
549   }
550 
551   for(amci_inoutfmt_t* f = exports->file_formats;
552       f->name; f++ ){
553 
554     if(addFileFormat(f))
555       goto error;
556   }
557 
558   return 0;
559 
560  error:
561   return -1;
562 }
563 
564 
loadAppPlugIn(AmPluginFactory * f)565 int AmPlugIn::loadAppPlugIn(AmPluginFactory* f)
566 {
567   AmSessionFactory* sf = dynamic_cast<AmSessionFactory*>(f);
568   if(!sf){
569     ERROR("invalid application plug-in!\n");
570     return -1;
571   }
572 
573   name2app_mut.lock();
574 
575   if(name2app.find(sf->getName()) != name2app.end()){
576     ERROR("application '%s' already loaded !\n",sf->getName().c_str());
577     name2app_mut.unlock();
578     return -1;
579   }
580 
581   name2app.insert(std::make_pair(sf->getName(),sf));
582   DBG("application '%s' loaded.\n",sf->getName().c_str());
583 
584   inc_ref(sf);
585   if(!module_objects.insert(std::make_pair(sf->getName(),sf)).second){
586     // insertion failed
587     dec_ref(sf);
588   }
589   name2app_mut.unlock();
590 
591   return 0;
592 
593 }
594 
loadSehPlugIn(AmPluginFactory * f)595 int AmPlugIn::loadSehPlugIn(AmPluginFactory* f)
596 {
597   AmSessionEventHandlerFactory* sf = dynamic_cast<AmSessionEventHandlerFactory*>(f);
598   if(!sf){
599     ERROR("invalid session component plug-in!\n");
600     goto error;
601   }
602 
603   if(name2seh.find(sf->getName()) != name2seh.end()){
604     ERROR("session component '%s' already loaded !\n",sf->getName().c_str());
605     goto error;
606   }
607 
608   inc_ref(sf);
609   name2seh.insert(std::make_pair(sf->getName(),sf));
610   DBG("session component '%s' loaded.\n",sf->getName().c_str());
611 
612   return 0;
613 
614  error:
615   return -1;
616 }
617 
loadBasePlugIn(AmPluginFactory * f)618 int AmPlugIn::loadBasePlugIn(AmPluginFactory* f)
619 {
620   inc_ref(f);
621   if(!name2base.insert(std::make_pair(f->getName(),f)).second){
622     // insertion failed
623     dec_ref(f);
624   }
625   return 0;
626 }
627 
loadDiPlugIn(AmPluginFactory * f)628 int AmPlugIn::loadDiPlugIn(AmPluginFactory* f)
629 {
630   AmDynInvokeFactory* sf = dynamic_cast<AmDynInvokeFactory*>(f);
631   if(!sf){
632     ERROR("invalid component plug-in!\n");
633     goto error;
634   }
635 
636   if(name2di.find(sf->getName()) != name2di.end()){
637     ERROR("component '%s' already loaded !\n",sf->getName().c_str());
638     goto error;
639   }
640 
641   name2di.insert(std::make_pair(sf->getName(),sf));
642   DBG("component '%s' loaded.\n",sf->getName().c_str());
643 
644   return 0;
645 
646  error:
647   return -1;
648 }
649 
loadLogFacPlugIn(AmPluginFactory * f)650 int AmPlugIn::loadLogFacPlugIn(AmPluginFactory* f)
651 {
652   AmLoggingFacility* sf = dynamic_cast<AmLoggingFacility*>(f);
653   if(!sf){
654     ERROR("invalid logging facility plug-in!\n");
655     goto error;
656   }
657 
658   if(name2logfac.find(sf->getName()) != name2logfac.end()){
659     ERROR("logging facility '%s' already loaded !\n",
660 	  sf->getName().c_str());
661     goto error;
662   }
663 
664   name2logfac.insert(std::make_pair(sf->getName(),sf));
665   DBG("logging facility component '%s' loaded.\n",sf->getName().c_str());
666 
667   return 0;
668 
669  error:
670   return -1;
671 }
672 
addCodec(amci_codec_t * c)673 int AmPlugIn::addCodec(amci_codec_t* c)
674 {
675   if(codecs.find(c->id) != codecs.end()){
676     ERROR("codec id (%i) already supported\n",c->id);
677     return -1;
678   }
679   codecs.insert(std::make_pair(c->id,c));
680   DBG("codec id %i inserted\n",c->id);
681   return 0;
682 }
683 
addPayload(amci_payload_t * p)684 int AmPlugIn::addPayload(amci_payload_t* p)
685 {
686   if (excluded_payloads.find(p->name) !=
687       excluded_payloads.end()) {
688     DBG("Not enabling excluded payload '%s'\n",
689 	p->name);
690     return 0;
691   }
692 
693   amci_codec_t* c;
694   unsigned int i, id;
695   if( !(c = codec(p->codec_id)) ){
696     ERROR("in payload '%s': codec id (%i) not supported\n",
697 	  p->name, p->codec_id);
698     return -1;
699   }
700   if(p->payload_id != -1){
701     if(payloads.find(p->payload_id) != payloads.end()){
702       ERROR("payload id (%i) already supported\n",p->payload_id);
703       return -1;
704     }
705   }
706   else {
707     p->payload_id = dynamic_pl;
708     dynamic_pl++;
709   }
710 
711   payloads.insert(std::make_pair(p->payload_id,p));
712   id = p->payload_id;
713 
714   for (i = 0; i < AmConfig::CodecOrder.size(); i++) {
715       if (p->name == AmConfig::CodecOrder[i]) break;
716   }
717   if (i >= AmConfig::CodecOrder.size()) {
718       payload_order.insert(std::make_pair(id + 100, id));
719       DBG("payload '%s/%i' inserted with id %i and order %i\n",
720 	  p->name, p->sample_rate, id, id + 100);
721   } else {
722       payload_order.insert(std::make_pair(i, id));
723       DBG("payload '%s/%i' inserted with id %i and order %i\n",
724 	  p->name, p->sample_rate, id, i);
725   }
726 
727   return 0;
728 }
729 
addFileFormat(amci_inoutfmt_t * f)730 int AmPlugIn::addFileFormat(amci_inoutfmt_t* f)
731 {
732   if(file_formats.find(f->name) != file_formats.end()){
733     ERROR("file format '%s' already supported\n",f->name);
734     return -1;
735   }
736 
737   amci_subtype_t* st = f->subtypes;
738   for(; st->type >= 0; st++ ){
739 
740     if( !codec(st->codec_id) ){
741       ERROR("in '%s' subtype %i: codec id (%i) not supported\n",
742 	    f->name,st->type,st->codec_id);
743       return -1;
744     }
745 
746     if (st->sample_rate < 0) {
747       ERROR("in '%s' subtype %i: rate must be specified!"
748 	    " (ubr no longer supported)\n", f->name,st->type);
749       return -1;
750     }
751     if (st->channels < 0) {
752       ERROR("in '%s' subtype %i: channels must be specified!"
753 	    "(unspecified channel count no longer supported)\n", f->name,st->type);
754       return -1;
755     }
756 
757   }
758   DBG("file format %s inserted\n",f->name);
759   file_formats.insert(std::make_pair(f->name,f));
760 
761   return 0;
762 }
763 
registerFactory4App(const string & app_name,AmSessionFactory * f)764 bool AmPlugIn::registerFactory4App(const string& app_name, AmSessionFactory* f)
765 {
766   bool res;
767 
768   name2app_mut.lock();
769   std::map<std::string,AmSessionFactory*>::iterator it = name2app.find(app_name);
770   if(it != name2app.end()){
771     WARN("Application '%s' has already been registered and cannot be "
772 	 "registered a second time\n",
773 	 app_name.c_str());
774     res =  false;
775   } else {
776     name2app.insert(make_pair(app_name,f));
777     res = true;
778   }
779   name2app_mut.unlock();
780 
781   return res;
782 }
783 
784 // static alias to registerFactory4App
registerApplication(const string & app_name,AmSessionFactory * f)785 bool AmPlugIn::registerApplication(const string& app_name, AmSessionFactory* f) {
786   bool res = instance()->registerFactory4App(app_name, f);
787   if (res) {
788     DBG("Application '%s' registered.\n", app_name.c_str());
789   }
790   return res;
791 }
792 
findSessionFactory(const AmSipRequest & req,string & app_name)793 AmSessionFactory* AmPlugIn::findSessionFactory(const AmSipRequest& req, string& app_name)
794 {
795     string m_app_name;
796 
797     switch (AmConfig::AppSelect) {
798 
799     case AmConfig::App_RURIUSER:
800       m_app_name = req.user;
801       break;
802     case AmConfig::App_APPHDR:
803       m_app_name = getHeader(req.hdrs, APPNAME_HDR, true);
804       break;
805     case AmConfig::App_RURIPARAM:
806       m_app_name = get_header_param(req.r_uri, "app");
807       break;
808     case AmConfig::App_MAPPING:
809       m_app_name = ""; // no match if not found
810       run_regex_mapping(AmConfig::AppMapping, req.r_uri.c_str(), m_app_name);
811       break;
812     case AmConfig::App_SPECIFIED:
813       m_app_name = AmConfig::Application;
814       break;
815     }
816 
817     if (m_app_name.empty()) {
818       INFO("could not find any application matching configured criteria\n");
819       return NULL;
820     }
821 
822     AmSessionFactory* session_factory = getFactory4App(m_app_name);
823     if(!session_factory) {
824       ERROR("AmPlugIn::findSessionFactory: application '%s' not found !\n", m_app_name.c_str());
825     }
826 
827     app_name = m_app_name;
828     return session_factory;
829 }
830 
831 #define REGISTER_STUFF(comp_name, map_name, param_name)			\
832   if(instance()->map_name.find(param_name) != instance()->map_name.end()){	\
833   ERROR(comp_name "'%s' already registered !\n", param_name.c_str());	\
834   return false;								\
835   }									\
836   inc_ref(f);								\
837   instance()->map_name.insert(std::make_pair(param_name,f));		\
838   DBG(comp_name " '%s' registered.\n",param_name.c_str());		\
839   return true;
840 
registerSIPEventHandler(const string & seh_name,AmSessionEventHandlerFactory * f)841 bool AmPlugIn::registerSIPEventHandler(const string& seh_name,
842 				       AmSessionEventHandlerFactory* f) {
843   REGISTER_STUFF("SIP Event handler", name2seh, seh_name);
844 }
845 
registerDIInterface(const string & di_name,AmDynInvokeFactory * f)846 bool AmPlugIn::registerDIInterface(const string& di_name, AmDynInvokeFactory* f) {
847   REGISTER_STUFF("DI Interface", name2di, di_name);
848 }
849 
registerLoggingFacility(const string & lf_name,AmLoggingFacility * f)850 bool AmPlugIn::registerLoggingFacility(const string& lf_name, AmLoggingFacility* f) {
851   REGISTER_STUFF("Logging Facility", name2logfac, lf_name);
852 }
853 
854 #undef REGISTER_STUFF
855