PageRenderTime 143ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/smqueue/smnet.cpp

https://github.com/infil00p/openbts-ttsou
C++ | 542 lines | 367 code | 72 blank | 103 comment | 81 complexity | a2078dfd5bd574d9276e53c66fc54d9a MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. * Smnet.cpp - Network SIP listener for Short Messages (SMS's) for OpenBTS.
  3. * Written by John Gilmore, July 2009.
  4. *
  5. * Copyright 2009 Free Software Foundation, Inc.
  6. *
  7. * This program 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 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. * See the COPYING file in the main directory for details.
  20. */
  21. #include <time.h>
  22. #include <osipparser2/osip_message.h> /* from osipparser2 */
  23. #include <iostream>
  24. #include <fstream>
  25. #include "poll.h"
  26. #include <sys/types.h> // for sys/socket.h
  27. #include <sys/socket.h> // recvfrom
  28. #include <netdb.h> // getaddrinfo
  29. #include <errno.h>
  30. #include <fcntl.h>
  31. #include <cstdlib> // l64a
  32. #include <arpa/inet.h> // inet_ntop
  33. #include "smnet.h"
  34. #include "smqueue.h"
  35. using namespace std;
  36. namespace SMqueue {
  37. // Because the abort function isn't always accessible in C--?
  38. void
  39. SMnet::abfuckingort()
  40. {
  41. *((char *)0) = -1;
  42. }
  43. /*
  44. * Send a datagram on a handy socket
  45. * FIXME: Make the source host/port match the one in the SIP dgram!
  46. * Currently we just send on the first socket with right addr length!
  47. * Result is true if sent OK; false if not (and errno is set if false).
  48. */
  49. bool
  50. SMnet::send_dgram(char *buffer, size_t buffsize, char *toaddr,
  51. size_t toaddrsize)
  52. {
  53. ssize_t i;
  54. int flags = MSG_DONTWAIT;
  55. if (!sockets || numsockets == 0) {
  56. errno = EBADF;
  57. return false;
  58. }
  59. nfds_t j;
  60. for (j = 0; j < numsockets; j++) {
  61. if (
  62. sockinfo[j].socktype == SOCK_DGRAM &&
  63. sockinfo[j].addrlen == toaddrsize) {
  64. i = sendto (sockets[j].fd, buffer, buffsize,
  65. flags, (struct sockaddr *)toaddr, toaddrsize);
  66. if (i < 0)
  67. continue;
  68. if (i != (ssize_t) buffsize) {
  69. errno = EPIPE; // We could do better...
  70. return false;
  71. }
  72. return true; // Success!
  73. }
  74. } // else try another socket
  75. errno = EBADF;
  76. return false; // No socket worked.
  77. }
  78. /* Talk to the GSM engine... */
  79. bool
  80. SMnet::deliver_msg_datagram(SMqueue::short_msg_pending *smp)
  81. {
  82. char *scheme, *host, *port;
  83. int s, i;
  84. // Make sure the text is valid before writing it for debug,
  85. // or delivering it to a handset.
  86. smp->make_text_valid();
  87. // FIXME, kludge it.
  88. // Write to first file descriptor...
  89. // we should chk for matching address family, etc...
  90. // cout << endl << "--Deliver message:" << endl;
  91. // cout << smp->text << endl;
  92. // We need to have at least ONE socket open (for sending on).
  93. if (!sockets || numsockets == 0)
  94. return false;
  95. /* Get the addressing info (and the SIP msg itself) out of the msg */
  96. if (!smp->parse()) return false;
  97. scheme = smp->parsed->req_uri->scheme;
  98. host = smp->parsed->req_uri->host;
  99. port = smp->parsed->req_uri->port;
  100. struct addrinfo myhints;
  101. struct addrinfo *myaddrs, *ap;
  102. memset(&myhints, 0, sizeof(myhints));
  103. myhints.ai_family = AF_UNSPEC; // Any address family eg v4/6
  104. myhints.ai_socktype = SOCK_DGRAM; // Datagrams for now FIXME
  105. #ifdef AI_IDN
  106. myhints.ai_flags = AI_IDN; // Int'l dom names OK.
  107. #endif
  108. if (!scheme)
  109. scheme = (char * const)"sip";
  110. if (!port)
  111. port = scheme; // More specific port is better
  112. s = getaddrinfo(host, port, &myhints, &myaddrs);
  113. if (s != 0) {
  114. cerr << "deliver_msg_datagram() can't lookup addr/port: "
  115. << host << ":" << port << ", error " << s << endl;
  116. return false;
  117. }
  118. // Now deliver to some working address we got back.
  119. // For each address, find an open socket that has the right
  120. // kind of protocol and return address...
  121. // FIXME, do we need to match the bound address with the packet's
  122. // "return address"? Maybe...
  123. for (ap = myaddrs; ap != NULL; ap = ap->ai_next) {
  124. int flags = MSG_DONTWAIT;
  125. nfds_t j;
  126. i = 0;
  127. for (j = 0; j < numsockets; j++) {
  128. if (sockinfo[j].addrfam == ap->ai_family &&
  129. sockinfo[j].socktype == ap->ai_socktype &&
  130. sockinfo[j].protofam == ap->ai_protocol &&
  131. sockinfo[j].addrlen == ap->ai_addrlen) {
  132. i = sendto (sockets[j].fd,
  133. smp->text, smp->text_length,
  134. flags, ap->ai_addr, ap->ai_addrlen);
  135. if (i < 0) {
  136. break; // Try another address
  137. }
  138. }
  139. }
  140. if (i < 0) continue; // Errored, try another address
  141. if (i == 0) continue; // No match, try another address.
  142. break; // sent -- stop trying!
  143. }
  144. freeaddrinfo(myaddrs); // Don't leak memory.
  145. if (ap == NULL) { // If we walked off bottom of list,
  146. cerr << "Couldn't send datagram to " << host << ":"
  147. << port << " on any socket" << endl;
  148. return false; // we failed to send
  149. }
  150. return true; // Hey, we sent the message onward!
  151. }
  152. /*
  153. * Network listener for SIP Short Messages.
  154. * Timeout in milliseconds (negative means infinity).
  155. *
  156. * Result is <0 if error;
  157. * Result is >0 if buffer contains a received packet.
  158. * (Packet's source address is saved away for future access by
  159. * our caller.)
  160. * Result == 0 if caller was interested in writing, there's no received
  161. * packet yet, and it's OK to write now. OR if we timed out.
  162. */
  163. int
  164. SMnet::get_next_dgram (char *buffer, size_t bufferlen, int mstimeout)
  165. {
  166. int i, fd, flags;
  167. nfds_t j;
  168. short revents;
  169. socklen_t addrlen;
  170. size_t recvlength;
  171. i = poll_sockets(mstimeout);
  172. if (i < 0) // error
  173. return i;
  174. if (i == 0) // timeout
  175. return 0;
  176. for (j = 0; j < numsockets; j++) { // Walk the sockets.
  177. fd = sockets[j].fd;
  178. revents = sockets[j].revents;
  179. #ifdef POLLRDHUP
  180. if (revents & (POLLIN|POLLPRI|POLLRDHUP))
  181. #else
  182. if (revents & (POLLIN|POLLPRI))
  183. #endif
  184. { // input OK
  185. // FIXME, TCP and files aren't supported yet
  186. addrlen = sizeof(src_addr);
  187. flags = MSG_DONTWAIT|MSG_TRUNC;
  188. recvlength = recvfrom(fd, buffer, bufferlen, flags,
  189. (sockaddr *)&src_addr, &addrlen);
  190. if (recvlength < 0) {
  191. // Error on receive.
  192. cerr << "Error " << strerror(errno)
  193. << "on recvfrom" << endl;
  194. // We shouldn't loop -- or the error might make
  195. // an endless loop. Return.
  196. return -1;
  197. }
  198. if (addrlen > sizeof(src_addr)) {
  199. // Received address truncated. BUG in program!
  200. cerr << "recvfrom received address truncated!"
  201. << endl;
  202. // FIXME, print src_addr too
  203. abfuckingort();
  204. }
  205. recvaddrlen = addrlen; // Save for later
  206. if (recvlength > bufferlen) {
  207. // Received packet itself truncated.
  208. cerr << "recvfrom data packet truncated, "
  209. "buffer has "
  210. << bufferlen << " bytes, packet of "
  211. << recvlength << "!" << endl;
  212. // FIXME, print src_addr too
  213. return -1;
  214. }
  215. //
  216. // OK, we got a full packet from a particular address.
  217. // Pass it upstairs for further processing.
  218. //
  219. return recvlength;
  220. }
  221. if (revents & (POLLOUT)) { // output OK
  222. return 0; // Tell caller to retry write
  223. }
  224. if (revents & (POLLERR|POLLHUP|POLLNVAL)) { // errors
  225. cerr << "Poll error " << strerror(errno)
  226. << "huh!" << endl;
  227. return -1;
  228. }
  229. // If no bits set on this FD, loop to the next one.
  230. }
  231. cerr << "Poll() returned " << i << " without any pending I/O" << endl;
  232. return -1;
  233. }
  234. /*
  235. * Initialize short-message handling.
  236. * Make one or more sockets and set up to listen on them.
  237. * This function is xxx ought-to-be ipv6-agnostic, and is even
  238. * almost UDP/TCP-agnostic.
  239. */
  240. bool
  241. SMnet::listen_on_port(std::string port)
  242. {
  243. int s;
  244. int gotasocket = 0;
  245. struct addrinfo myhints;
  246. struct addrinfo *myaddrs, *ap;
  247. memset(&myhints, 0, sizeof(myhints));
  248. myhints.ai_family = AF_UNSPEC; // Any address family eg v4/6
  249. myhints.ai_socktype = SOCK_DGRAM; // Datagrams for now FIXME
  250. myhints.ai_flags = AI_PASSIVE; // From anybody
  251. s = getaddrinfo(NULL, (port.c_str()), &myhints, &myaddrs);
  252. if (s != 0) {
  253. cerr << "listen_on_port(" << port
  254. << ") can't get addr/port to listen on" << endl;
  255. return -1;
  256. }
  257. for (ap = myaddrs; ap != NULL; ap = ap->ai_next) {
  258. int fd, i;
  259. fd = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
  260. if (fd < 0)
  261. continue; // Try another
  262. // Set our port number & address.
  263. i = bind(fd, ap->ai_addr, ap->ai_addrlen);
  264. if (i < 0) {
  265. cerr << "listen_on_port(" << port
  266. << ") can't bind to addr '"
  267. << string_addr (ap, true) << "': "
  268. << strerror(errno) << endl;
  269. close(fd); // Don't leave it dangling
  270. continue; // Try another
  271. }
  272. (void) fcntl(fd, F_SETFL, O_NONBLOCK); // Non-blocking I/O
  273. #ifdef O_CLOEXEC
  274. (void) fcntl(fd, F_SETFD, O_CLOEXEC); // Close on exec child
  275. #endif
  276. // Now set up our class to poll on, and use, this socket.
  277. add_socket (fd, POLLIN|POLLPRI, ap->ai_family,
  278. ap->ai_socktype, ap->ai_protocol, ap->ai_addr,
  279. ap->ai_addrlen);
  280. // Be slightly verbose here.
  281. cerr << "Listening at address '"
  282. << string_addr (ap, true) << "'." << endl;
  283. gotasocket++;
  284. // And keep looping to make several sockets if we can!
  285. }
  286. freeaddrinfo(myaddrs); // Don't leak memory.
  287. if (!gotasocket)
  288. return false;
  289. return true;
  290. }
  291. /*
  292. * My hostname as known to the global network.
  293. *
  294. * FIXME, there is no kernel interface for finding this out. Our return
  295. * address depends what interface our packets go out. NAT and such make
  296. * it even more complicated. This would need to be a config-file setting.
  297. */
  298. char *
  299. SMnet::myhostname()
  300. {
  301. size_t plen = INET6_ADDRSTRLEN;
  302. struct sockaddr_storage sockadd;
  303. struct sockaddr *sp;
  304. char *p = 0;
  305. int i;
  306. socklen_t socklen;
  307. int flags;
  308. // Cache it once, return it forever.
  309. if (my_network_hostname)
  310. return my_network_hostname;
  311. // Get "my address" on some socket.
  312. sp = (struct sockaddr *)&sockadd;
  313. socklen = sizeof (sockadd);
  314. i = getsockname (sockets[0].fd, sp, (socklen_t *)&socklen);
  315. p = new char[plen];
  316. p[0] = 'x'; p[1] = '\0'; // In case of failure
  317. flags = NI_DGRAM|NI_NUMERICHOST|NI_NUMERICSERV;
  318. i = getnameinfo(sp, socklen, p, plen, (char *)0, 0, flags);
  319. if (i != 0) {
  320. cerr << "myhostname() can't find our name: error "
  321. << gai_strerror(i) << endl;
  322. }
  323. my_network_hostname = p;
  324. return my_network_hostname;
  325. }
  326. /* Make printable IP address */
  327. std::string
  328. SMnet::string_addr (struct addrinfo *myaddr, bool withport)
  329. {
  330. return string_addr (myaddr->ai_addr, myaddr->ai_addrlen, withport);
  331. }
  332. /* Make printable IP address */
  333. std::string
  334. SMnet::string_addr (struct sockaddr *sa, socklen_t len, bool withport)
  335. {
  336. size_t plen = NI_MAXHOST;
  337. size_t portlen = NI_MAXSERV;
  338. char *p = 0, *port = 0;
  339. int i;
  340. string ret;
  341. int flags;
  342. p = new char[plen];
  343. p[0] = '0'; p[1] = '\0'; // In case of failure
  344. if (withport) {
  345. port = new char[portlen];
  346. port[0]='0'; port[1] = '\0';
  347. }
  348. if (len != 0) {
  349. flags = NI_DGRAM|NI_NUMERICHOST|NI_NUMERICSERV;
  350. i = getnameinfo(sa, len, p, plen, port, portlen, flags);
  351. if (i != 0) {
  352. cerr << "string_addr() can't print IP address: error "
  353. << gai_strerror(i) << endl;
  354. if (0 == inet_ntop(sa->sa_family, sa->sa_data, p, plen)) {
  355. cerr << "string_addr() can't print IP address: inet_ntop error "
  356. << strerror(errno) << endl;
  357. }
  358. //FIXME snprintf(port, portlen, "%d", sa->port);
  359. }
  360. }
  361. if (withport)
  362. ret = string(p) + ":" + string(port);
  363. else
  364. ret = string(p);
  365. delete [] p;
  366. delete [] port;
  367. return ret;
  368. }
  369. /* Parse printable IP address and port */
  370. bool
  371. SMnet::parse_addr (const char *str, char *sockad, socklen_t maxlen, socklen_t *len)
  372. {
  373. char *p = strchr(str, ':');
  374. char *host, *port;
  375. if (p == NULL)
  376. return false;
  377. // Empty address
  378. if (!strcmp("0:0", str)) {
  379. *len = 0;
  380. return true;
  381. }
  382. host = new char[1 + p - str];
  383. strncpy(host, str, p-str);
  384. host[p-str] = '\0';
  385. port = p+1;
  386. struct addrinfo myhints;
  387. struct addrinfo *myaddrs, *ap;
  388. int s;
  389. memset(&myhints, 0, sizeof(myhints));
  390. myhints.ai_family = AF_UNSPEC; // Any address family eg v4/6
  391. myhints.ai_socktype = SOCK_DGRAM; // Datagrams for now FIXME
  392. s = getaddrinfo(host, port, &myhints, &myaddrs);
  393. if (s != 0) {
  394. cerr << "parse_addr() can't lookup addr/port: "
  395. << host << ":" << port << ", error " << s << endl;
  396. return false;
  397. }
  398. int seenone = false;
  399. // Now pick some working address we got back.
  400. for (ap = myaddrs; ap != NULL; ap = ap->ai_next) {
  401. if (ap->ai_addrlen > maxlen)
  402. continue;
  403. if (ap->ai_socktype != SOCK_DGRAM)
  404. continue;
  405. if (seenone) return false;
  406. seenone = true;
  407. // We found it!
  408. memcpy(sockad, ap->ai_addr, ap->ai_addrlen);
  409. *len = ap->ai_addrlen;
  410. }
  411. freeaddrinfo(myaddrs); // Don't leak memory.
  412. return seenone;
  413. }
  414. /*
  415. * Return a different random integer each time we are called.
  416. * They are all guaranteed to be positive numbers.
  417. */
  418. unsigned int
  419. SMnet::new_random_number()
  420. {
  421. #define RAND_DEVICE "/dev/urandom"
  422. union {
  423. char randbuf[4];
  424. int randnum;
  425. } randy;
  426. static int fallback;
  427. int i;
  428. if (random_fd <= 0) {
  429. random_fd = open (RAND_DEVICE, O_RDONLY);
  430. if (random_fd < 0) {
  431. cerr << "Can't open " << RAND_DEVICE << endl;
  432. }
  433. }
  434. do {
  435. if (random_fd > 0) {
  436. i = read(random_fd, &randy.randbuf, sizeof(randy.randbuf));
  437. if (i != sizeof(randy.randbuf)) {
  438. cerr << "Can't read from " << RAND_DEVICE << endl;
  439. randy.randnum = ++fallback;
  440. }
  441. } else {
  442. randy.randnum = ++fallback;
  443. }
  444. if (randy.randnum < 0)
  445. randy.randnum = -randy.randnum;
  446. // Avoid passing either 0 or -infinity to a64l
  447. // (MacOS is particularly finicky about that, but it really is undef.)
  448. } while (randy.randnum <= 0);
  449. return (unsigned int)randy.randnum;
  450. }
  451. /*
  452. * Return a different random string (a "call number" for a Call-ID in
  453. * SIP, RFC 3261) each time we are called. That string is good until the
  454. * next call, but may need to be copied if needed beyond that.
  455. */
  456. char *
  457. SMnet::new_call_number()
  458. {
  459. char *p;
  460. long randnum;
  461. randnum = new_random_number();
  462. p = l64a (randnum);
  463. if (!random_string) {
  464. random_string = new char[6+1];
  465. }
  466. strncpy(random_string, p, 6);
  467. random_string[6] = '\0';
  468. return random_string;
  469. }
  470. } // namespace SMlistener