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