/* Copyright (C) 2012-2015 Doubango Telecom <http://www.doubango.org> * Copyright (C) 2012 Diop Mamadou Ibrahima * * This file is part of Open Source 'webrtc2sip' project * <http://code.google.com/p/webrtc2sip/> * * 'webrtc2sip' is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 'webrtc2sip' is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 'webrtc2sip'. */ #include "mp_engine.h" #include <libxml/tree.h> static char* sConfigXmlPath = NULL; #define kSQLiteConnectionInfo "./c2c_sqlite.db" #define kSQLiteName "sqlite" #define kMySQLConnectionInfo NULL #define kMySQLName "mysql" #define mp_list_count(list) tsk_list_count((list), tsk_null, tsk_null) #define mp_str_is(str, val) tsk_striequals((const char*)(str), val) #define mp_str_is_star(str) mp_str_is((str), "*") #define mp_str_is_yes(str) mp_str_is((str), "yes") #define mp_strn_update(ppstr, newstr, n) if(ppstr){ if(*ppstr) free(*ppstr); *ppstr = tsk_strndup(newstr, n); } using namespace webrtc2sip; static int parseConfigNode(xmlNode *pNode, MPObjectWrapper<MPEngine*> oEngine) { xmlNode *pCurrNode; int iRet; tsk_params_L_t* pParams = tsk_null; if(!pNode || !oEngine) { TSK_DEBUG_ERROR("Invalid argument"); return (-1); } for(pCurrNode = pNode; pCurrNode; pCurrNode = pCurrNode->next) { switch(pCurrNode->type) { case XML_ELEMENT_NODE: { break; } case XML_TEXT_NODE: { if(!pCurrNode->content) { break; } if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "debug-level")) { TSK_DEBUG_INFO("debug-level = %s\n", (const char*)pCurrNode->content); if(!oEngine->setDebugLevel((const char*)pCurrNode->content)){ TSK_DEBUG_ERROR("Failed to set debug-level = %s\n", (const char*)pCurrNode->content); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "transport")) { if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && mp_list_count(pParams) == 3) { const char* pcProto = ((const tsk_param_t*)pParams->head->data)->name; const char* pcLocalIP = ((const tsk_param_t*)pParams->head->next->data)->name; const char* pcLocalPort = ((const tsk_param_t*)pParams->head->next->next->data)->name; TSK_DEBUG_INFO("transport = %s://%s:%s", pcProto, pcLocalIP, pcLocalPort); if(!oEngine->addTransport(pcProto, mp_str_is_star(pcLocalPort) ? TNET_SOCKET_PORT_ANY : atoi(pcLocalPort), mp_str_is_star(pcLocalIP) ? TNET_SOCKET_HOST_ANY : pcLocalIP)) { TSK_DEBUG_ERROR("Failed to add 'transport': %s://%s:%s", pcLocalPort, pcLocalIP, pcLocalPort); } } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "enable-rtp-symetric")) // available since 2.1.0 { TSK_DEBUG_INFO("enable-rtp-symetric = %s", (const char*)pCurrNode->content); if(!(oEngine->setRtpSymetricEnabled(mp_str_is_yes(pCurrNode->content)))) { TSK_DEBUG_ERROR("Failed to set 'enable-rtp-symetric': %s", (const char*)pCurrNode->content); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "enable-100rel")) // available since 2.0.0 { TSK_DEBUG_INFO("enable-100rel = %s", (const char*)pCurrNode->content); if(!(oEngine->set100relEnabled(mp_str_is_yes(pCurrNode->content)))) { TSK_DEBUG_ERROR("Failed to set 'enable-100rel': %s", (const char*)pCurrNode->content); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "enable-media-coder")) // available since 2.0.0 { TSK_DEBUG_INFO("enable-media-coder = %s", (const char*)pCurrNode->content); if(!(oEngine->setMediaCoderEnabled(mp_str_is_yes(pCurrNode->content)))) { TSK_DEBUG_ERROR("Failed to set 'enable-media-coder': %s", (const char*)pCurrNode->content); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "enable-videojb")) // available since 2.0.0 { TSK_DEBUG_INFO("enable-videojb = %s", (const char*)pCurrNode->content); if(!(oEngine->setVideoJbEnabled(mp_str_is_yes(pCurrNode->content)))) { TSK_DEBUG_ERROR("Failed to set 'enable-videojb': %s", (const char*)pCurrNode->content); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "video-size-pref")) // available since 2.1.0 { const char* pcPrefVideoSize = (const char*)pCurrNode->content; TSK_DEBUG_INFO("video-size-pref = %s", pcPrefVideoSize); if(!oEngine->setPrefVideoSize(pcPrefVideoSize)) { TSK_DEBUG_ERROR("Failed to set 'video-size-pref': %s", pcPrefVideoSize); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "rtp-buffsize")) // available since 2.0.0 { TSK_DEBUG_INFO("rtp-buffsize = %s", (const char*)pCurrNode->content); if(!(oEngine->setRtpBuffSize(atoi((const char*)pCurrNode->content)))) { TSK_DEBUG_ERROR("Failed to set 'rtp-buffsize': %s", (const char*)pCurrNode->content); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "avpf-tail-length")) // available since 2.0.0 { if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && mp_list_count(pParams) == 2) { const char* pcMin = ((const tsk_param_t*)pParams->head->data)->name; const char* pcMax = ((const tsk_param_t*)pParams->head->next->data)->name; TSK_DEBUG_INFO("avpf-tail-length = [%s-%s]", pcMin, pcMax); if(!oEngine->setAvpfTail(atoi(pcMin), atoi(pcMax))) { TSK_DEBUG_ERROR("Failed to set 'avpf-tail-length': [%s-%s]", pcMin, pcMax); } } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "srtp-mode")) // available since 2.0.0 { TSK_DEBUG_INFO("srtp-mode = %s", (const char*)pCurrNode->content); if(!(oEngine->setSRTPMode((const char*)pCurrNode->content))) { TSK_DEBUG_ERROR("Failed to set 'srtp-mode': %s", (const char*)pCurrNode->content); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "srtp-type")) // available since 2.1.0 { TSK_DEBUG_INFO("srtp-type = %s", (const char*)pCurrNode->content); if(!(oEngine->setSRTPType((const char*)pCurrNode->content))) { TSK_DEBUG_ERROR("Failed to set 'srtp-type': %s", (const char*)pCurrNode->content); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "ssl-certificates")) // available since 2.0.0 { if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && mp_list_count(pParams) >= 3) { const char* pcPrivateKey = ((const tsk_param_t*)pParams->head->data)->name; const char* pcPublicKey = ((const tsk_param_t*)pParams->head->next->data)->name; const char* pcCA = ((const tsk_param_t*)pParams->head->next->next->data)->name; const char* pcVerify = pParams->head->next->next->next ? ((const tsk_param_t*)pParams->head->next->next->next->data)->name : "no"; // available since 2.1.0 TSK_DEBUG_INFO("ssl-certificates = \n%s;\n%s;\n%s;\n%s", pcPrivateKey, pcPublicKey, pcCA, pcVerify); if(!oEngine->setSSLCertificates(mp_str_is_star(pcPrivateKey) ? NULL : pcPrivateKey, mp_str_is_star(pcPublicKey) ? NULL : pcPublicKey, mp_str_is_star(pcCA) ? NULL : pcCA, mp_str_is_yes(pcVerify))) { TSK_DEBUG_ERROR("Failed to set 'ssl-certificates': %s;\n%s;\n%s", pcPrivateKey, pcPublicKey, pcCA); } } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "codecs")) // available since 2.0.0 { const char* pcCodecs = (const char*)pCurrNode->content; TSK_DEBUG_INFO("codecs = %s", pcCodecs); if(!oEngine->setCodecs(pcCodecs)) { TSK_DEBUG_ERROR("Failed to set 'codecs': %s", pcCodecs); } break; } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "codec-opus-maxrates")) // available since 2.5.0 { if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && mp_list_count(pParams) == 2) { const char* pcMaxPlaybackRate = ((const tsk_param_t*)pParams->head->data)->name; const char* pcMaxCaptureRate = ((const tsk_param_t*)pParams->head->next->data)->name; TSK_DEBUG_INFO("codec-opus-maxrates = %s;%s", pcMaxPlaybackRate, pcMaxCaptureRate); if(!oEngine->setCodecOpusMaxRates(atoi(pcMaxPlaybackRate), atoi(pcMaxCaptureRate))) { TSK_DEBUG_ERROR("Failed to set 'codec-opus-maxrates': %s;%s", pcMaxPlaybackRate, pcMaxCaptureRate); } } break; } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "stun-server")) // available since 2.5.1 { size_t nCount; if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && (nCount = mp_list_count(pParams)) >= 2) { const char* pcServerIP = ((const tsk_param_t*)pParams->head->data)->name; const char* pcServerPort = ((const tsk_param_t*)pParams->head->next->data)->name; const char* pcUsrName = (nCount >= 3) ? ((const tsk_param_t*)pParams->head->next->next->data)->name : NULL; const char* pcUsrPwd = (nCount >= 4) ? ((const tsk_param_t*)pParams->head->next->next->next->data)->name : NULL; TSK_DEBUG_INFO("stun-server = %s;%s;-;-", pcServerIP, pcServerPort); if(!oEngine->setStunServer(pcServerIP, atoi(pcServerPort), mp_str_is_star(pcUsrName) ? NULL : pcUsrName, mp_str_is_star(pcUsrPwd) ? NULL : pcUsrPwd)) { TSK_DEBUG_ERROR("Failed to set 'stun-server': %s;%s;-;-", pcServerIP, pcServerPort); } } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "enable-icestun")) // available since 2.5.1 { const char* pcEnabled = (const char*)pCurrNode->content; TSK_DEBUG_INFO("enable-icestun = %s", pcEnabled); if(!oEngine->setIceStunEnabled(mp_str_is_yes(pcEnabled))) { TSK_DEBUG_ERROR("Failed to set 'enable-icestun': %s", pcEnabled); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "max-fds")) // available since 2.6.1 { const char* pcMaxFds = (const char*)pCurrNode->content; TSK_DEBUG_INFO("max-fds = %s", pcMaxFds); if(!oEngine->setMaxFds(atoi(pcMaxFds))) { TSK_DEBUG_ERROR("Failed to set 'max-fds': %s", pcMaxFds); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "nameserver")) // available since 2.0.0 { const char* pcDNSServer = (const char*)pCurrNode->content; TSK_DEBUG_INFO("nameserver = %s", pcDNSServer); if(!oEngine->addDNSServer(pcDNSServer)) { TSK_DEBUG_ERROR("Failed to set 'nameserver': %s", pcDNSServer); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "database")) // available since 2.3.0 { if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && mp_list_count(pParams) >= 2) { const char* pcDbType = ((const tsk_param_t*)pParams->head->data)->name; const char* pcDbConnectionInfo = ((const tsk_param_t*)pParams->head->next->data)->name; TSK_DEBUG_INFO("database = %s;%s", pcDbType, pcDbConnectionInfo); if(mp_str_is_star(pcDbConnectionInfo)) { if(tsk_striequals(kSQLiteName, pcDbType)) { pcDbConnectionInfo = kSQLiteConnectionInfo; } else if(tsk_striequals(kMySQLName, pcDbType)) { pcDbConnectionInfo = kMySQLConnectionInfo; } } if(!oEngine->setDbInfo(pcDbType, pcDbConnectionInfo)) { TSK_DEBUG_ERROR("Failed to set 'database': %s", (const char*)pCurrNode->content); } } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "account-mail")) // available since 2.3.0 { if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && mp_list_count(pParams) >= 7) { const char* pcSmtpScheme = ((const tsk_param_t*)pParams->head->data)->name; const char* pcLocalIP = ((const tsk_param_t*)pParams->head->next->data)->name; const char* pcLocalPort = ((const tsk_param_t*)pParams->head->next->next->data)->name; const char* pcSmtpHost = ((const tsk_param_t*)pParams->head->next->next->next->data)->name; const char* pcSmtpPort = ((const tsk_param_t*)pParams->head->next->next->next->next->data)->name; const char* pcEmail = ((const tsk_param_t*)pParams->head->next->next->next->next->next->data)->name; const char* pcAuthName = ((const tsk_param_t*)pParams->head->next->next->next->next->next->next->data)->name; const char* pcAuthPassword = ((const tsk_param_t*)pParams->head->next->next->next->next->next->next->next->data)->name; TSK_DEBUG_INFO("account-mail = %s;%s;%s;%s;%s;%s;password", pcSmtpScheme, pcLocalIP, pcLocalPort, pcSmtpHost, pcSmtpPort, pcAuthName); if(!oEngine->setMailAccountInfo(pcSmtpScheme, mp_str_is_star(pcLocalIP) ? NULL : pcLocalIP, mp_str_is_star(pcLocalPort) ? 0 : atoi(pcLocalPort), pcSmtpHost, atoi(pcSmtpPort), pcEmail, pcAuthName, pcAuthPassword)) { TSK_DEBUG_ERROR("Failed to set 'account-mail': %s", (const char*)pCurrNode->content); } } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "account-sip-caller")) // available since 2.3.0 { if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && mp_list_count(pParams) >= 5) { const char* pcDisplayName = ((const tsk_param_t*)pParams->head->data)->name; const char* pcImpu = ((const tsk_param_t*)pParams->head->next->data)->name; const char* pcImpi = ((const tsk_param_t*)pParams->head->next->next->data)->name; const char* pcRealm = ((const tsk_param_t*)pParams->head->next->next->next->data)->name; const char* pcPassword = ((const tsk_param_t*)pParams->head->next->next->next->next->data)->name; TSK_DEBUG_INFO("account-sip-caller = %s;%s;%s;%s;password", pcDisplayName, pcImpu, pcImpi, pcRealm); if(!oEngine->addAccountSipCaller(mp_str_is_star(pcDisplayName) ? NULL : pcDisplayName, pcImpu, pcImpi, pcRealm, pcPassword)) { TSK_DEBUG_ERROR("Failed to add 'account-sip-caller': %s", (const char*)pCurrNode->content); } } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "account-http-domain")) // available since 2.7.0 { const char* pcHttpDomain = (const char*)pCurrNode->content; TSK_DEBUG_INFO("account-http-domain = %s", pcHttpDomain); if(!oEngine->setHttpDomain(mp_str_is_star(pcHttpDomain) ? NULL : pcHttpDomain)) { TSK_DEBUG_ERROR("Failed to set 'account-http-domain': %s", pcHttpDomain); } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "account-recaptcha")) // available since 2.7.0 { if((pParams = tsk_params_fromstring((const char*)pCurrNode->content, ";", tsk_true)) && mp_list_count(pParams) >= 2) { const char* pcSiteVerifyUrl = ((const tsk_param_t*)pParams->head->data)->name; const char* pcSecret = ((const tsk_param_t*)pParams->head->next->data)->name; TSK_DEBUG_INFO("account-recaptcha = %s;<secret>", pcSiteVerifyUrl); if(!oEngine->setRecaptchaInfo(pcSiteVerifyUrl, pcSecret)) { TSK_DEBUG_ERROR("Failed to set 'account-recaptcha'"); } } } else if(pCurrNode->parent && tsk_striequals(pCurrNode->parent->name, "dtmf-type")) // available since 2.4.0 { const char* pcDtmfType = (const char*)pCurrNode->content; TSK_DEBUG_INFO("dtmf-type = %s", pcDtmfType); if(!oEngine->setDtmfType(pcDtmfType)) { TSK_DEBUG_ERROR("Failed to set 'dtmf-type': %s", pcDtmfType); } } break; } } TSK_OBJECT_SAFE_FREE(pParams); if(pCurrNode->children && (iRet = parseConfigNode(pCurrNode->children, oEngine))) { return (iRet); } } return (0); } static int parseConfigRoot(MPObjectWrapper<MPEngine*> oEngine, const char* xmlPath = NULL) { xmlDoc *pDoc; xmlNode *pRootElement; if(!oEngine) { TSK_DEBUG_ERROR("Invalid parameter"); return (-1); } if(!xmlPath) { xmlPath = "./config.xml"; } if(!(pDoc = xmlReadFile(xmlPath, NULL, 0))) { TSK_DEBUG_ERROR("Failed to read xml config file at [%s]", xmlPath); return (-2); } if(!(pRootElement = xmlDocGetRootElement(pDoc))) { TSK_DEBUG_ERROR("Failed to get root element for xml config file at %s", xmlPath); xmlFreeDoc(pDoc); return (-3); } int iRet = parseConfigNode(pRootElement, oEngine); xmlCleanupParser(); return (iRet); } static int printUsage() { fprintf(stdout, "Usage: webrtc2sip [OPTION]\n\n" "--config=PATH override the default path to the config.xml file\n" "--help display this help and exit\n" "--version output version information and exit\n" ); return 0; } static int parseArgument(const char* arg, const char** name, tsk_size_t* name_size, const char** value, tsk_size_t* value_size) { int32_t index, arg_size; if(tsk_strnullORempty(arg) || !name || !name_size || !value || !value_size){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } *name = *value = tsk_null; *name_size = *value_size = 0; arg_size = tsk_strlen(arg); *name = arg; index = tsk_strindexOf(arg, arg_size, "="); if(index <= 0){ *name_size = arg_size; return 0; } *name_size = index; *value = &arg[index + 1]; *value_size = (arg_size - index - 1); return 0; } static int parseArguments(int argc, char** argv) { int i, ret; const char *name, *value; tsk_size_t name_size, value_size; if(argc <= 1 || !argv){ return 0; } for(i = 1; i < argc; ++i){ if((ret = parseArgument(argv[i], &name, &name_size, &value, &value_size))){ printUsage(); return ret; } if(tsk_strniequals("--config", name, name_size)){ if(!value || !value_size){ fprintf(stderr, "--config requires valid PATH\n"); printUsage(); exit(-1); } mp_strn_update(&sConfigXmlPath, value, value_size); } else if(tsk_strniequals("--help", name, name_size)){ printUsage(); exit(-1); } else if(tsk_strniequals("--version", name, name_size)){ fprintf(stdout, "%d.%d.%d\n", WEBRTC2SIP_VERSION_MAJOR, WEBRTC2SIP_VERSION_MINOR, WEBRTC2SIP_VERSION_MICRO); exit(-1); } else{ fprintf(stderr, "'%.*s' not valid as command argument\n", (int)name_size, name); exit(-1); } } return 0; } int main(int argc, char** argv) { bool bRet; int iRet, i = 0; char command[1024] = { 0 }; printf("*******************************************************************\n" "Copyright (C) 2012-2015 Doubango Telecom <http://www.doubango.org>\n" "PRODUCT: webrtc2sip\n" "HOME PAGE: http://webrtc2sip.org\n" "LICENCE: GPLv3 or proprietary\n" "VERSION: %s\n" "'quit' to quit the application.\n" "*******************************************************************\n\n" , WEBRTC2SIP_VERSION_STRING); // parse command arguments if ((iRet = parseArguments(argc, argv)) != 0) { return iRet; } // create engine MPObjectWrapper<MPEngine*> oEngine = MPEngine::New(); // parse "config.xml" file if ((iRet = parseConfigRoot(oEngine, sConfigXmlPath))) { return iRet; } if (!(bRet = oEngine->start())) { exit (-1); } while (fgets(command, sizeof(command), stdin) != NULL) { if (tsk_strnicmp(command, "quit", 4) == 0) { printf("+++ quit() +++"); break; } // FIXME: https://code.google.com/p/webrtc2sip/issues/detail?id=96 tsk_thread_sleep(1); } oEngine->stop(); return 0; }