netsock.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Kevin P. Fleming <kpfleming@digium.com>
  7. * Mark Spencer <markster@digium.com>
  8. *
  9. * See http://www.asterisk.org for more information about
  10. * the Asterisk project. Please do not directly contact
  11. * any of the maintainers of this project for assistance;
  12. * the project provides a web site, mailing lists and IRC
  13. * channels for your use.
  14. *
  15. * This program is free software, distributed under the terms of
  16. * the GNU General Public License Version 2. See the LICENSE file
  17. * at the top of the source tree.
  18. */
  19. /*! \file
  20. *
  21. * \brief Network socket handling
  22. *
  23. * \author Kevin P. Fleming <kpfleming@digium.com>
  24. * \author Mark Spencer <markster@digium.com>
  25. */
  26. /*** MODULEINFO
  27. <support_level>core</support_level>
  28. ***/
  29. #include "asterisk.h"
  30. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  31. #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__)
  32. #include <net/if_dl.h>
  33. #endif
  34. #if defined (SOLARIS)
  35. #include <sys/sockio.h>
  36. #elif defined(HAVE_GETIFADDRS)
  37. #include <ifaddrs.h>
  38. #endif
  39. #include "asterisk/netsock.h"
  40. #include "asterisk/utils.h"
  41. #include "asterisk/astobj.h"
  42. struct ast_netsock {
  43. ASTOBJ_COMPONENTS(struct ast_netsock);
  44. struct sockaddr_in bindaddr;
  45. int sockfd;
  46. int *ioref;
  47. struct io_context *ioc;
  48. void *data;
  49. };
  50. struct ast_netsock_list {
  51. ASTOBJ_CONTAINER_COMPONENTS(struct ast_netsock);
  52. struct io_context *ioc;
  53. };
  54. static void ast_netsock_destroy(struct ast_netsock *netsock)
  55. {
  56. ast_io_remove(netsock->ioc, netsock->ioref);
  57. close(netsock->sockfd);
  58. ast_free(netsock);
  59. }
  60. struct ast_netsock_list *ast_netsock_list_alloc(void)
  61. {
  62. return ast_calloc(1, sizeof(struct ast_netsock_list));
  63. }
  64. int ast_netsock_init(struct ast_netsock_list *list)
  65. {
  66. memset(list, 0, sizeof(*list));
  67. ASTOBJ_CONTAINER_INIT(list);
  68. return 0;
  69. }
  70. int ast_netsock_release(struct ast_netsock_list *list)
  71. {
  72. ASTOBJ_CONTAINER_DESTROYALL(list, ast_netsock_destroy);
  73. ASTOBJ_CONTAINER_DESTROY(list);
  74. ast_free(list);
  75. return 0;
  76. }
  77. struct ast_netsock *ast_netsock_find(struct ast_netsock_list *list,
  78. struct sockaddr_in *sa)
  79. {
  80. struct ast_netsock *sock = NULL;
  81. ASTOBJ_CONTAINER_TRAVERSE(list, !sock, {
  82. ASTOBJ_RDLOCK(iterator);
  83. if (!inaddrcmp(&iterator->bindaddr, sa))
  84. sock = iterator;
  85. ASTOBJ_UNLOCK(iterator);
  86. });
  87. return sock;
  88. }
  89. struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct io_context *ioc, struct sockaddr_in *bindaddr, int tos, int cos, ast_io_cb callback, void *data)
  90. {
  91. int netsocket = -1;
  92. int *ioref;
  93. struct ast_netsock *ns;
  94. const int reuseFlag = 1;
  95. /* Make a UDP socket */
  96. netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  97. if (netsocket < 0) {
  98. ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
  99. return NULL;
  100. }
  101. if (setsockopt(netsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseFlag, sizeof reuseFlag) < 0) {
  102. ast_log(LOG_WARNING, "Error setting SO_REUSEADDR on sockfd '%d'\n", netsocket);
  103. }
  104. if (bind(netsocket,(struct sockaddr *)bindaddr, sizeof(struct sockaddr_in))) {
  105. ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(bindaddr->sin_addr), ntohs(bindaddr->sin_port), strerror(errno));
  106. close(netsocket);
  107. return NULL;
  108. }
  109. ast_netsock_set_qos(netsocket, tos, cos, "IAX2");
  110. ast_enable_packet_fragmentation(netsocket);
  111. if (!(ns = ast_calloc(1, sizeof(*ns)))) {
  112. close(netsocket);
  113. return NULL;
  114. }
  115. /* Establish I/O callback for socket read */
  116. if (!(ioref = ast_io_add(ioc, netsocket, callback, AST_IO_IN, ns))) {
  117. close(netsocket);
  118. ast_free(ns);
  119. return NULL;
  120. }
  121. ASTOBJ_INIT(ns);
  122. ns->ioref = ioref;
  123. ns->ioc = ioc;
  124. ns->sockfd = netsocket;
  125. ns->data = data;
  126. memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr));
  127. ASTOBJ_CONTAINER_LINK(list, ns);
  128. return ns;
  129. }
  130. int ast_netsock_set_qos(int netsocket, int tos, int cos, const char *desc)
  131. {
  132. int res;
  133. if ((res = setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))))
  134. ast_log(LOG_WARNING, "Unable to set %s TOS to %d, may be you have no root privileges\n", desc, tos);
  135. else if (tos)
  136. ast_verb(2, "Using %s TOS bits %d\n", desc, tos);
  137. #if defined(linux)
  138. if (setsockopt(netsocket, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos)))
  139. ast_log(LOG_WARNING, "Unable to set %s CoS to %d\n", desc, cos);
  140. else if (cos)
  141. ast_verb(2, "Using %s CoS mark %d\n", desc, cos);
  142. #endif
  143. return res;
  144. }
  145. struct ast_netsock *ast_netsock_bind(struct ast_netsock_list *list, struct io_context *ioc, const char *bindinfo, int defaultport, int tos, int cos, ast_io_cb callback, void *data)
  146. {
  147. struct sockaddr_in sin;
  148. char *tmp;
  149. char *host;
  150. char *port;
  151. int portno;
  152. memset(&sin, 0, sizeof(sin));
  153. sin.sin_family = AF_INET;
  154. sin.sin_port = htons(defaultport);
  155. tmp = ast_strdupa(bindinfo);
  156. host = strsep(&tmp, ":");
  157. port = tmp;
  158. if (port && ((portno = atoi(port)) > 0))
  159. sin.sin_port = htons(portno);
  160. inet_aton(host, &sin.sin_addr);
  161. return ast_netsock_bindaddr(list, ioc, &sin, tos, cos, callback, data);
  162. }
  163. int ast_netsock_sockfd(const struct ast_netsock *ns)
  164. {
  165. return ns ? ns-> sockfd : -1;
  166. }
  167. const struct sockaddr_in *ast_netsock_boundaddr(const struct ast_netsock *ns)
  168. {
  169. return &(ns->bindaddr);
  170. }
  171. void *ast_netsock_data(const struct ast_netsock *ns)
  172. {
  173. return ns->data;
  174. }
  175. void ast_netsock_unref(struct ast_netsock *ns)
  176. {
  177. ASTOBJ_UNREF(ns, ast_netsock_destroy);
  178. }
  179. char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
  180. {
  181. int x;
  182. char *os = s;
  183. if (maxlen < 18) {
  184. if (s && (maxlen > 0))
  185. *s = '\0';
  186. } else {
  187. for (x = 0; x < 5; x++) {
  188. sprintf(s, "%02x:", (unsigned)eid->eid[x]);
  189. s += 3;
  190. }
  191. sprintf(s, "%02x", (unsigned)eid->eid[5]);
  192. }
  193. return os;
  194. }
  195. void ast_set_default_eid(struct ast_eid *eid)
  196. {
  197. #if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR)
  198. int s, x = 0;
  199. char eid_str[20];
  200. struct ifreq ifr;
  201. static const unsigned int MAXIF = 10;
  202. s = socket(AF_INET, SOCK_STREAM, 0);
  203. if (s < 0)
  204. return;
  205. for (x = 0; x < MAXIF; x++) {
  206. static const char *prefixes[] = { "eth", "em" };
  207. unsigned int i;
  208. for (i = 0; i < ARRAY_LEN(prefixes); i++) {
  209. memset(&ifr, 0, sizeof(ifr));
  210. snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", prefixes[i], x);
  211. if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
  212. break;
  213. }
  214. }
  215. if (i == ARRAY_LEN(prefixes)) {
  216. /* Try pciX#[1..N] */
  217. for (i = 0; i < MAXIF; i++) {
  218. memset(&ifr, 0, sizeof(ifr));
  219. snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "pci%d#%u", x, i);
  220. if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
  221. break;
  222. }
  223. }
  224. if (i == MAXIF) {
  225. continue;
  226. }
  227. }
  228. memcpy(eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(*eid));
  229. ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr.ifr_name);
  230. close(s);
  231. return;
  232. }
  233. close(s);
  234. #else
  235. #if defined(ifa_broadaddr) && !defined(SOLARIS)
  236. char eid_str[20];
  237. struct ifaddrs *ifap;
  238. if (getifaddrs(&ifap) == 0) {
  239. struct ifaddrs *p;
  240. for (p = ifap; p; p = p->ifa_next) {
  241. if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
  242. struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
  243. memcpy(&(eid->eid), sdp->sdl_data + sdp->sdl_nlen, 6);
  244. ast_debug(1, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), p->ifa_name);
  245. freeifaddrs(ifap);
  246. return;
  247. }
  248. }
  249. freeifaddrs(ifap);
  250. }
  251. #endif
  252. #endif
  253. ast_debug(1, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
  254. }
  255. int ast_str_to_eid(struct ast_eid *eid, const char *s)
  256. {
  257. unsigned int eid_int[6];
  258. int x;
  259. if (sscanf(s, "%2x:%2x:%2x:%2x:%2x:%2x", &eid_int[0], &eid_int[1], &eid_int[2],
  260. &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
  261. return -1;
  262. for (x = 0; x < 6; x++)
  263. eid->eid[x] = eid_int[x];
  264. return 0;
  265. }
  266. int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
  267. {
  268. return memcmp(eid1, eid2, sizeof(*eid1));
  269. }