sip_reg.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. * SIP Registration Agent -- by ww@styx.org
  3. *
  4. * This program is Free Software, released under the GNU General
  5. * Public License v2.0 http://www.gnu.org/licenses/gpl
  6. *
  7. * This program will register to a SIP proxy using the contact
  8. * supplied on the command line. This is useful if, for some
  9. * reason your SIP client cannot register to the proxy itself.
  10. * For example, if your SIP client registers to Proxy A, but
  11. * you want to be able to recieve calls that arrive at Proxy B,
  12. * you can use this program to register the client's contact
  13. * information to Proxy B.
  14. *
  15. * This program requires the eXosip library. To compile,
  16. * assuming your eXosip installation is in /usr/local,
  17. * use something like:
  18. *
  19. * gcc -O2 -I/usr/local/include -L/usr/local/lib sipreg.c \
  20. * -o sipreg \
  21. * -leXosip2 -losip2 -losipparser2 -lpthread
  22. *
  23. * It should compile and run on any POSIX compliant system
  24. * that supports pthreads.
  25. *
  26. */
  27. #if !defined(WIN32) && !defined(_WIN32_WCE)
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <sys/types.h>
  32. #include <sys/socket.h>
  33. #include <netinet/in.h>
  34. #include <netdb.h>
  35. #include <syslog.h>
  36. #ifndef OSIP_MONOTHREAD
  37. #include <pthread.h>
  38. #endif
  39. #include <string.h>
  40. #ifdef __linux
  41. #include <signal.h>
  42. #endif
  43. #endif
  44. #include <osip2/osip_mt.h>
  45. #include <eXosip2/eXosip.h>
  46. #if !defined(WIN32)
  47. #define _GNU_SOURCE
  48. #include <getopt.h>
  49. #endif
  50. #define PROG_NAME "sip_reg"
  51. #define SYSLOG_FACILITY LOG_DAEMON
  52. static volatile int keepRunning = 1;
  53. #ifdef __linux
  54. static void intHandler(int dummy) {
  55. keepRunning = 0;
  56. }
  57. #endif
  58. #if defined(WIN32)
  59. static void syslog_wrapper(int a, const char *fmt, ...) {
  60. va_list args;
  61. va_start(args, fmt);
  62. vfprintf(stdout, fmt, args);
  63. va_end(args);
  64. }
  65. #define LOG_INFO 0
  66. #define LOG_ERR 0
  67. #define LOG_WARNING 0
  68. #define LOG_DEBUG 0
  69. #elif defined(LOG_PERROR)
  70. /* If we can, we use syslog() to emit the debugging messages to stderr. */
  71. #define syslog_wrapper syslog
  72. #else
  73. #define syslog_wrapper(a, b...) \
  74. fprintf(stderr, b); \
  75. fprintf(stderr, "\n")
  76. #endif
  77. static void usage(void);
  78. static void usage(void) {
  79. printf(PROG_NAME
  80. " v%s\n"
  81. "\nUsage: " PROG_NAME
  82. " [required_options] [optional_options]\n"
  83. "\n[required_options]\n"
  84. " -r --proxy sip:proxyhost[:port]\n"
  85. " -u --from sip:user@host[:port]\n"
  86. "\n[optional_options]\n"
  87. " -d --debug (log to stderr and do not fork)\n"
  88. "\n[optional_sip_options]\n"
  89. " -U --username xxxx (authentication username)\n"
  90. " -P --password yyyy (authentication password)\n"
  91. " -t --transport UDP|TCP|TLS|DTLS (default UDP)\n"
  92. " -e --expiry number (default 3600)\n"
  93. "\n[very_optional_sip_options]\n"
  94. " -p --port number (default 5060)\n"
  95. " -c --contact sip:user@host[:port] (default automatic)\n"
  96. " -f --firewallip N.N.N.N\n"
  97. " -m --automasquerade (auto discover contact IP:PORT)\n"
  98. "\n"
  99. " -h --help\n",
  100. eXosip_get_version());
  101. }
  102. typedef struct regparam_t {
  103. int regid;
  104. int expiry;
  105. int auth;
  106. } regparam_t;
  107. struct eXosip_t *context_eXosip;
  108. int main(int argc, char *argv[]) {
  109. int c;
  110. int port = 5060;
  111. char *contact = NULL;
  112. char *fromuser = NULL;
  113. int automasquerade = 0;
  114. const char *firewallip = NULL;
  115. char *proxy = NULL;
  116. char transport[5];
  117. struct servent *service;
  118. char *username = NULL;
  119. char *password = NULL;
  120. struct regparam_t regparam = {0, 3600, 0};
  121. int debug = 0;
  122. int nofork = 0;
  123. int err;
  124. char prog_name[32];
  125. int optval;
  126. snprintf(prog_name, sizeof(prog_name), "%s (%s)", PROG_NAME, eXosip_get_version());
  127. #ifdef SIGPIPE
  128. signal(SIGPIPE, SIG_IGN);
  129. #endif
  130. #ifdef __linux
  131. signal(SIGINT, intHandler);
  132. #endif
  133. snprintf(transport, sizeof(transport), "%s", "UDP");
  134. for (;;) {
  135. #define short_options "du:r:U:P:t:p:c:e:mf:h"
  136. #ifdef _GNU_SOURCE
  137. int option_index = 0;
  138. static struct option long_options[] = {{"debug", no_argument, NULL, 'd'},
  139. {"from", required_argument, NULL, 'u'},
  140. {"proxy", required_argument, NULL, 'r'},
  141. {"username", required_argument, NULL, 'U'},
  142. {"password", required_argument, NULL, 'P'},
  143. {"transport", required_argument, NULL, 't'},
  144. {"port", required_argument, NULL, 'p'},
  145. {"contact", required_argument, NULL, 'c'},
  146. {"expiry", required_argument, NULL, 'e'},
  147. {"automasquerade", no_argument, NULL, 'm'},
  148. {"firewallip", required_argument, NULL, 'f'},
  149. {"help", no_argument, NULL, 'h'},
  150. {NULL, 0, NULL, 0}};
  151. c = getopt_long(argc, argv, short_options, long_options, &option_index);
  152. #else
  153. c = getopt(argc, argv, short_options);
  154. #endif
  155. if (c == -1)
  156. break;
  157. switch (c) {
  158. case 'c':
  159. contact = optarg;
  160. break;
  161. case 'd':
  162. nofork = 1;
  163. #ifdef LOG_PERROR
  164. debug = LOG_PERROR;
  165. #endif
  166. break;
  167. case 'e':
  168. regparam.expiry = atoi(optarg);
  169. break;
  170. case 'm':
  171. automasquerade = 1;
  172. break;
  173. case 'f':
  174. firewallip = optarg;
  175. break;
  176. case 'h':
  177. usage();
  178. exit(0);
  179. case 'p':
  180. service = getservbyname(optarg, "udp");
  181. if (service)
  182. port = ntohs(service->s_port);
  183. else
  184. port = atoi(optarg);
  185. break;
  186. case 't':
  187. snprintf(transport, sizeof(transport), "%s", optarg);
  188. break;
  189. case 'r':
  190. proxy = optarg;
  191. break;
  192. case 'u':
  193. fromuser = optarg;
  194. break;
  195. case 'U':
  196. username = optarg;
  197. break;
  198. case 'P':
  199. password = optarg;
  200. break;
  201. default:
  202. break;
  203. }
  204. }
  205. if (!proxy || !fromuser) {
  206. usage();
  207. exit(1);
  208. }
  209. if (!nofork) {
  210. err = daemon(1, 0);
  211. if (err < 0) {
  212. exit(1);
  213. }
  214. }
  215. #ifdef LOG_PERROR
  216. openlog(PROG_NAME, LOG_PID | debug, SYSLOG_FACILITY);
  217. #endif
  218. syslog_wrapper(LOG_INFO, "%s up and running [testing on [%s] REGISTER [%s] Expires [%d] From: [%s]%s%s%s]", prog_name, transport, proxy, regparam.expiry, fromuser, (username && password) ? " Username: [" : "",
  219. (username && password) ? username : "", (username && password) ? ":*****]" : "");
  220. if (contact != NULL)
  221. syslog_wrapper(LOG_INFO, "contact: %s", contact);
  222. syslog_wrapper(LOG_INFO, "local port: %d", port);
  223. if (osip_strcasecmp(transport, "UDP") != 0 && osip_strcasecmp(transport, "TCP") != 0 && osip_strcasecmp(transport, "TLS") != 0 && osip_strcasecmp(transport, "DTLS") != 0) {
  224. syslog_wrapper(LOG_ERR, "wrong transport parameter");
  225. usage();
  226. exit(1);
  227. }
  228. if (debug > 0)
  229. TRACE_INITIALIZE(6, NULL);
  230. context_eXosip = eXosip_malloc();
  231. if (eXosip_init(context_eXosip)) {
  232. syslog_wrapper(LOG_ERR, "eXosip_init failed");
  233. exit(1);
  234. }
  235. err = -1;
  236. if (osip_strcasecmp(transport, "UDP") == 0) {
  237. err = eXosip_listen_addr(context_eXosip, IPPROTO_UDP, NULL, port, AF_INET, 0);
  238. } else if (osip_strcasecmp(transport, "TCP") == 0) {
  239. err = eXosip_listen_addr(context_eXosip, IPPROTO_TCP, NULL, port, AF_INET, 0);
  240. } else if (osip_strcasecmp(transport, "TLS") == 0) {
  241. err = eXosip_listen_addr(context_eXosip, IPPROTO_TCP, NULL, port, AF_INET, 1);
  242. } else if (osip_strcasecmp(transport, "DTLS") == 0) {
  243. err = eXosip_listen_addr(context_eXosip, IPPROTO_UDP, NULL, port, AF_INET, 1);
  244. }
  245. if (err) {
  246. syslog_wrapper(LOG_ERR, "eXosip_listen_addr failed");
  247. eXosip_quit(context_eXosip);
  248. osip_free(context_eXosip);
  249. exit(1);
  250. }
  251. if (firewallip) {
  252. syslog_wrapper(LOG_INFO, "firewall address: %s:%i", firewallip, port);
  253. eXosip_masquerade_contact(context_eXosip, firewallip, port);
  254. }
  255. optval = automasquerade;
  256. eXosip_set_option(context_eXosip, EXOSIP_OPT_AUTO_MASQUERADE_CONTACT, &optval);
  257. if (automasquerade) {
  258. syslog_wrapper(LOG_INFO, "automasquerade enabled");
  259. }
  260. eXosip_set_user_agent(context_eXosip, prog_name);
  261. if (username && password) {
  262. if (eXosip_add_authentication_info(context_eXosip, username, username, password, NULL, NULL)) {
  263. syslog_wrapper(LOG_ERR, "eXosip_add_authentication_info failed");
  264. eXosip_quit(context_eXosip);
  265. osip_free(context_eXosip);
  266. exit(1);
  267. }
  268. }
  269. {
  270. osip_message_t *reg = NULL;
  271. int i;
  272. eXosip_lock(context_eXosip);
  273. regparam.regid = eXosip_register_build_initial_register(context_eXosip, fromuser, proxy, contact, regparam.expiry * 2, &reg);
  274. if (regparam.regid < 1) {
  275. eXosip_unlock(context_eXosip);
  276. syslog_wrapper(LOG_ERR, "eXosip_register_build_initial_register failed");
  277. eXosip_quit(context_eXosip);
  278. osip_free(context_eXosip);
  279. exit(1);
  280. }
  281. i = eXosip_register_send_register(context_eXosip, regparam.regid, reg);
  282. eXosip_unlock(context_eXosip);
  283. if (i != 0) {
  284. syslog_wrapper(LOG_ERR, "eXosip_register_send_register failed");
  285. eXosip_quit(context_eXosip);
  286. osip_free(context_eXosip);
  287. exit(1);
  288. }
  289. }
  290. for (; keepRunning;) {
  291. static int counter = 0;
  292. eXosip_event_t *event;
  293. counter++;
  294. if (counter % 60000 == 0) {
  295. struct eXosip_stats stats;
  296. memset(&stats, 0, sizeof(struct eXosip_stats));
  297. eXosip_lock(context_eXosip);
  298. eXosip_set_option(context_eXosip, EXOSIP_OPT_GET_STATISTICS, &stats);
  299. eXosip_unlock(context_eXosip);
  300. syslog_wrapper(LOG_INFO, "eXosip stats: inmemory=(tr:%i//reg:%i) average=(tr:%f//reg:%f)", stats.allocated_transactions, stats.allocated_registrations, stats.average_transactions, stats.average_registrations);
  301. }
  302. if (!(event = eXosip_event_wait(context_eXosip, 0, 1))) {
  303. #ifdef OSIP_MONOTHREAD
  304. eXosip_execute(context_eXosip);
  305. #endif
  306. eXosip_lock(context_eXosip);
  307. eXosip_automatic_action(context_eXosip);
  308. eXosip_unlock(context_eXosip);
  309. osip_usleep(10000);
  310. continue;
  311. }
  312. #ifdef OSIP_MONOTHREAD
  313. eXosip_execute(context_eXosip);
  314. #endif
  315. eXosip_lock(context_eXosip);
  316. eXosip_automatic_action(context_eXosip);
  317. switch (event->type) {
  318. case EXOSIP_REGISTRATION_SUCCESS:
  319. syslog_wrapper(LOG_INFO, "registrered successfully");
  320. break;
  321. case EXOSIP_REGISTRATION_FAILURE:
  322. break;
  323. case EXOSIP_CALL_INVITE: {
  324. osip_message_t *answer;
  325. int i;
  326. i = eXosip_call_build_answer(context_eXosip, event->tid, 405, &answer);
  327. if (i != 0) {
  328. syslog_wrapper(LOG_ERR, "failed to reject INVITE");
  329. break;
  330. }
  331. osip_free(answer->reason_phrase);
  332. answer->reason_phrase = osip_strdup("No Support for Incoming Calls");
  333. i = eXosip_call_send_answer(context_eXosip, event->tid, 405, answer);
  334. if (i != 0) {
  335. syslog_wrapper(LOG_ERR, "failed to reject INVITE");
  336. break;
  337. }
  338. syslog_wrapper(LOG_INFO, "INVITE rejected with 405");
  339. break;
  340. }
  341. case EXOSIP_MESSAGE_NEW: {
  342. osip_message_t *answer;
  343. int i;
  344. i = eXosip_message_build_answer(context_eXosip, event->tid, 405, &answer);
  345. if (i != 0) {
  346. syslog_wrapper(LOG_ERR, "failed to reject %s", event->request->sip_method);
  347. break;
  348. }
  349. i = eXosip_message_send_answer(context_eXosip, event->tid, 405, answer);
  350. if (i != 0) {
  351. syslog_wrapper(LOG_ERR, "failed to reject %s", event->request->sip_method);
  352. break;
  353. }
  354. syslog_wrapper(LOG_INFO, "%s rejected with 405", event->request->sip_method);
  355. break;
  356. }
  357. case EXOSIP_IN_SUBSCRIPTION_NEW: {
  358. osip_message_t *answer;
  359. int i;
  360. i = eXosip_insubscription_build_answer(context_eXosip, event->tid, 405, &answer);
  361. if (i != 0) {
  362. syslog_wrapper(LOG_ERR, "failed to reject %s", event->request->sip_method);
  363. break;
  364. }
  365. i = eXosip_insubscription_send_answer(context_eXosip, event->tid, 405, answer);
  366. if (i != 0) {
  367. syslog_wrapper(LOG_ERR, "failed to reject %s", event->request->sip_method);
  368. break;
  369. }
  370. syslog_wrapper(LOG_INFO, "%s rejected with 405", event->request->sip_method);
  371. break;
  372. }
  373. case EXOSIP_CALL_CLOSED:
  374. case EXOSIP_CALL_RELEASED:
  375. break;
  376. default:
  377. syslog_wrapper(LOG_DEBUG, "received unknown eXosip event (type, did, cid) = (%d, %d, %d)", event->type, event->did, event->cid);
  378. }
  379. eXosip_unlock(context_eXosip);
  380. eXosip_event_free(event);
  381. }
  382. eXosip_quit(context_eXosip);
  383. osip_free(context_eXosip);
  384. return 0;
  385. }