00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $")
00035
00036 #ifndef __linux__
00037 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__) || defined(__GLIBC__)
00038 #include <net/if_dl.h>
00039 #endif
00040 #endif
00041
00042 #if defined (SOLARIS)
00043 #include <sys/sockio.h>
00044 #elif defined(HAVE_GETIFADDRS)
00045 #include <ifaddrs.h>
00046 #endif
00047
00048 #include "asterisk/netsock.h"
00049 #include "asterisk/netsock2.h"
00050 #include "asterisk/utils.h"
00051 #include "asterisk/astobj.h"
00052
00053 struct ast_netsock {
00054 ASTOBJ_COMPONENTS(struct ast_netsock);
00055 struct ast_sockaddr bindaddr;
00056 int sockfd;
00057 int *ioref;
00058 struct io_context *ioc;
00059 void *data;
00060 };
00061
00062 struct ast_netsock_list {
00063 ASTOBJ_CONTAINER_COMPONENTS(struct ast_netsock);
00064 struct io_context *ioc;
00065 };
00066
00067 static void ast_netsock_destroy(struct ast_netsock *netsock)
00068 {
00069 ast_io_remove(netsock->ioc, netsock->ioref);
00070 close(netsock->sockfd);
00071 ast_free(netsock);
00072 }
00073
00074 struct ast_netsock_list *ast_netsock_list_alloc(void)
00075 {
00076 return ast_calloc(1, sizeof(struct ast_netsock_list));
00077 }
00078
00079 int ast_netsock_init(struct ast_netsock_list *list)
00080 {
00081 memset(list, 0, sizeof(*list));
00082 ASTOBJ_CONTAINER_INIT(list);
00083
00084 return 0;
00085 }
00086
00087 int ast_netsock_release(struct ast_netsock_list *list)
00088 {
00089 ASTOBJ_CONTAINER_DESTROYALL(list, ast_netsock_destroy);
00090 ASTOBJ_CONTAINER_DESTROY(list);
00091 ast_free(list);
00092
00093 return 0;
00094 }
00095
00096 struct ast_netsock *ast_netsock_find(struct ast_netsock_list *list, struct ast_sockaddr *addr)
00097 {
00098 struct ast_netsock *sock = NULL;
00099
00100 ASTOBJ_CONTAINER_TRAVERSE(list, !sock, {
00101 ASTOBJ_RDLOCK(iterator);
00102 if (!ast_sockaddr_cmp(&iterator->bindaddr, addr)) {
00103 sock = iterator;
00104 }
00105 ASTOBJ_UNLOCK(iterator);
00106 });
00107
00108 return sock;
00109 }
00110
00111 struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct io_context *ioc, struct ast_sockaddr *bindaddr, int tos, int cos, ast_io_cb callback, void *data)
00112 {
00113 int netsocket = -1;
00114 int *ioref;
00115
00116 struct ast_netsock *ns;
00117 const int reuseFlag = 1;
00118
00119
00120 netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
00121
00122 if (netsocket < 0) {
00123 ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
00124 return NULL;
00125 }
00126 if (setsockopt(netsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseFlag, sizeof reuseFlag) < 0) {
00127 ast_log(LOG_WARNING, "Error setting SO_REUSEADDR on sockfd '%d'\n", netsocket);
00128 }
00129 if (ast_bind(netsocket, bindaddr)) {
00130 ast_log(LOG_ERROR,
00131 "Unable to bind to %s: %s\n",
00132 ast_sockaddr_stringify(bindaddr),
00133 strerror(errno));
00134 close(netsocket);
00135 return NULL;
00136 }
00137
00138 ast_set_qos(netsocket, tos, cos, "IAX2");
00139
00140 ast_enable_packet_fragmentation(netsocket);
00141
00142 if (!(ns = ast_calloc(1, sizeof(*ns)))) {
00143 close(netsocket);
00144 return NULL;
00145 }
00146
00147
00148 if (!(ioref = ast_io_add(ioc, netsocket, callback, AST_IO_IN, ns))) {
00149 close(netsocket);
00150 ast_free(ns);
00151 return NULL;
00152 }
00153 ASTOBJ_INIT(ns);
00154 ns->ioref = ioref;
00155 ns->ioc = ioc;
00156 ns->sockfd = netsocket;
00157 ns->data = data;
00158 memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr));
00159 ASTOBJ_CONTAINER_LINK(list, ns);
00160
00161 return ns;
00162 }
00163
00164 int ast_netsock_set_qos(int sockfd, int tos, int cos, const char *desc)
00165 {
00166 return ast_set_qos(sockfd, tos, cos, desc);
00167 }
00168
00169 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)
00170 {
00171 struct ast_sockaddr addr;
00172
00173 if (ast_sockaddr_parse(&addr, bindinfo, 0)) {
00174 if (!ast_sockaddr_is_ipv4(&addr)) {
00175 ast_log(LOG_WARNING, "Only IPv4 addresses are supported at this time.\n");
00176 return NULL;
00177 }
00178
00179 if (!ast_sockaddr_port(&addr)) {
00180 ast_sockaddr_set_port(&addr, defaultport);
00181 }
00182
00183 return ast_netsock_bindaddr(list, ioc, &addr, tos, cos, callback, data);
00184 }
00185
00186 return NULL;
00187 }
00188
00189 int ast_netsock_sockfd(const struct ast_netsock *ns)
00190 {
00191 return ns ? ns-> sockfd : -1;
00192 }
00193
00194 const struct ast_sockaddr *ast_netsock_boundaddr(const struct ast_netsock *ns)
00195 {
00196 return &ns->bindaddr;
00197 }
00198
00199 void *ast_netsock_data(const struct ast_netsock *ns)
00200 {
00201 return ns->data;
00202 }
00203
00204 void ast_netsock_unref(struct ast_netsock *ns)
00205 {
00206 ASTOBJ_UNREF(ns, ast_netsock_destroy);
00207 }
00208
00209 char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
00210 {
00211 int x;
00212 char *os = s;
00213 if (maxlen < 18) {
00214 if (s && (maxlen > 0))
00215 *s = '\0';
00216 } else {
00217 for (x = 0; x < 5; x++) {
00218 sprintf(s, "%02x:", eid->eid[x]);
00219 s += 3;
00220 }
00221 sprintf(s, "%02x", eid->eid[5]);
00222 }
00223 return os;
00224 }
00225
00226 void ast_set_default_eid(struct ast_eid *eid)
00227 {
00228 #if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR)
00229 int s, x = 0;
00230 char eid_str[20];
00231 struct ifreq ifr;
00232 static const unsigned int MAXIF = 10;
00233
00234 s = socket(AF_INET, SOCK_STREAM, 0);
00235 if (s < 0)
00236 return;
00237 for (x = 0; x < MAXIF; x++) {
00238 static const char *prefixes[] = { "eth", "em" };
00239 unsigned int i;
00240
00241 for (i = 0; i < ARRAY_LEN(prefixes); i++) {
00242 memset(&ifr, 0, sizeof(ifr));
00243 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", prefixes[i], x);
00244 if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
00245 break;
00246 }
00247 }
00248
00249 if (i == ARRAY_LEN(prefixes)) {
00250
00251 for (i = 0; i < MAXIF; i++) {
00252 memset(&ifr, 0, sizeof(ifr));
00253 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "pci%u#%u", x, i);
00254 if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
00255 break;
00256 }
00257 }
00258 if (i == MAXIF) {
00259 continue;
00260 }
00261 }
00262
00263 memcpy(eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(*eid));
00264 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);
00265 close(s);
00266 return;
00267 }
00268 close(s);
00269 #else
00270 #if defined(ifa_broadaddr) && !defined(SOLARIS)
00271 char eid_str[20];
00272 struct ifaddrs *ifap;
00273
00274 if (getifaddrs(&ifap) == 0) {
00275 struct ifaddrs *p;
00276 for (p = ifap; p; p = p->ifa_next) {
00277 if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
00278 struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
00279 memcpy(&(eid->eid), sdp->sdl_data + sdp->sdl_nlen, 6);
00280 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);
00281 freeifaddrs(ifap);
00282 return;
00283 }
00284 }
00285 freeifaddrs(ifap);
00286 }
00287 #endif
00288 #endif
00289 ast_debug(1, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
00290 }
00291
00292 int ast_str_to_eid(struct ast_eid *eid, const char *s)
00293 {
00294 unsigned int eid_int[6];
00295 int x;
00296
00297 if (sscanf(s, "%2x:%2x:%2x:%2x:%2x:%2x", &eid_int[0], &eid_int[1], &eid_int[2],
00298 &eid_int[3], &eid_int[4], &eid_int[5]) != 6)
00299 return -1;
00300
00301 for (x = 0; x < 6; x++)
00302 eid->eid[x] = eid_int[x];
00303
00304 return 0;
00305 }
00306
00307 int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2)
00308 {
00309 return memcmp(eid1, eid2, sizeof(*eid1));
00310 }