diff -Nru a/Makefile b/Makefile --- a/Makefile 2005-01-15 19:06:56 -07:00 +++ b/Makefile 2005-01-15 19:06:56 -07:00 @@ -97,6 +97,12 @@ # MALLOC_DEBUG = #-include $(PWD)/include/asterisk/astmm.h +# Uncomment to enable ASTOBJ dumping commands in the CLI +ASTOBJ_DEBUG = -DASTOBJ_DUMP + +# Uncomment to enable ASTOBJ statistics commands in the CLI +ASTOBJ_DEBUG += -DASTOBJ_STATS + # Where to install asterisk after compiling # Default -> leave empty INSTALL_PREFIX= @@ -194,6 +200,7 @@ CFLAGS+= $(DEBUG_THREADS) CFLAGS+= $(TRACE_FRAMES) CFLAGS+= $(MALLOC_DEBUG) +CFLAGS+= $(ASTOBJ_DEBUG) CFLAGS+= $(BUSYDETECT) CFLAGS+= $(OPTIONS) CFLAGS+=# -fomit-frame-pointer diff -Nru a/acl.c b/acl.c --- a/acl.c 2005-01-15 19:06:56 -07:00 +++ b/acl.c 2005-01-15 19:06:56 -07:00 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -43,14 +44,14 @@ #include #endif -struct ast_netsock { - ASTOBJ_COMPONENTS(struct ast_netsock); +ASTOBJ_DEFINE(ast_netsock, ast_netsock_destroy, 1, struct { struct sockaddr_in bindaddr; int sockfd; int *ioref; struct io_context *ioc; -}; +}); +ASTOBJ_LIST_DEFINE(ast_netsock_list, ast_netsock, 0, struct io_context *ioc); struct ast_ha { /* Host access rule */ @@ -323,14 +324,13 @@ return NULL; } - ns = malloc(sizeof(struct ast_netsock)); + ns = ast_netsock_new(NULL); if (ns) { - ASTOBJ_INIT(ns); ns->ioref = ioref; ns->ioc = ioc; ns->sockfd = netsocket; memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr)); - ASTOBJ_CONTAINER_LINK(list, ns); + ast_netsock_list_link(list, ns); } else { ast_log(LOG_WARNING, "Out of memory!\n"); ast_io_remove(ioc, ioref); @@ -346,17 +346,16 @@ free(netsock); } -int ast_netsock_init(struct ast_netsock_list *list) +int ast_netsock_init(struct ast_netsock_list **list) { - memset(list, 0, sizeof(struct ast_netsock_list)); - ASTOBJ_CONTAINER_INIT(list); + *list = ast_netsock_list_new(); return 0; } -int ast_netsock_release(struct ast_netsock_list *list) +int ast_netsock_release(struct ast_netsock_list **list) { - ASTOBJ_CONTAINER_DESTROYALL(list, ast_netsock_destroy); - ASTOBJ_CONTAINER_DESTROY(list); + ast_netsock_list_unlink_all(*list); + ast_netsock_list_destroy(list); return 0; } diff -Nru a/channels/chan_iax2.c b/channels/chan_iax2.c --- a/channels/chan_iax2.c 2005-01-15 19:06:56 -07:00 +++ b/channels/chan_iax2.c 2005-01-15 19:06:56 -07:00 @@ -134,7 +134,7 @@ static int timingfd = -1; /* Timing file descriptor */ -static struct ast_netsock_list netsock; +static struct ast_netsock_list *netsock; static int defaultsockfd = -1; static int usecnt; @@ -7432,7 +7432,7 @@ if (reload) { ast_log(LOG_NOTICE, "Ignoring bindaddr on reload\n"); } else { - if (!(ns = ast_netsock_bind(&netsock, io, v->value, portno, tos, socket_read, NULL))) { + if (!(ns = ast_netsock_bind(netsock, io, v->value, portno, tos, socket_read, NULL))) { ast_log(LOG_WARNING, "Unable apply binding to '%s' at line %d\n", v->value, v->lineno); } else { if (option_verbose > 1) { @@ -8078,7 +8078,7 @@ ast_log(LOG_ERROR, "Unable to register IAX switch\n"); if (defaultsockfd < 0) { - if (!(ns = ast_netsock_bindaddr(&netsock, io, &sin, tos, socket_read, NULL))) { + if (!(ns = ast_netsock_bindaddr(netsock, io, &sin, tos, socket_read, NULL))) { ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); return -1; } else { diff -Nru a/channels/chan_sip.c b/channels/chan_sip.c --- a/channels/chan_sip.c 2005-01-15 19:06:56 -07:00 +++ b/channels/chan_sip.c 2005-01-15 19:06:56 -07:00 @@ -419,10 +419,9 @@ char data[0]; }; -/* Structure for SIP user data. User's place calls to us */ -struct sip_user { +/* Structure for SIP user data. Users place calls to us */ +ASTOBJ_DEFINE(sip_user, sip_destroy_user, 1, struct { /* Users who can access various contexts */ - ASTOBJ_COMPONENTS(struct sip_user); char secret[80]; /* Password */ char md5secret[80]; /* Password in md5 */ char context[80]; /* Default context for incoming calls */ @@ -445,11 +444,10 @@ int outgoinglimit; struct ast_ha *ha; /* ACL setting */ struct ast_variable *vars; -}; +}); -/* Structure for SIP peer data, we place calls to peers if registred or fixed IP address (host) */ -struct sip_peer { - ASTOBJ_COMPONENTS(struct sip_peer); +/* Structure for SIP peer data, we place calls to peers if registered or fixed IP address (host) */ +ASTOBJ_DEFINE(sip_peer, sip_destroy_peer, 2, struct { char secret[80]; /* Password */ char md5secret[80]; /* Password in MD5 */ char context[80]; /* Default context for incoming calls */ @@ -490,7 +488,7 @@ struct sockaddr_in defaddr; /* Default IP address, used until registration */ struct ast_ha *ha; /* Access control list */ int lastmsg; -}; +}); AST_MUTEX_DEFINE_STATIC(sip_reload_lock); static int sip_reloading = 0; @@ -506,8 +504,7 @@ /* sip_registry: Registrations with other SIP proxies */ -struct sip_registry { - ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1); +ASTOBJ_DEFINE(sip_registry, sip_registry_destroy, 1, struct { int portno; /* Optional port override */ char username[80]; /* Who we are registering as */ char authuser[80]; /* Who we *authenticate* as */ @@ -534,23 +531,30 @@ char qop[80]; /* Quality of Protection. */ char lastmsg[256]; /* Last Message sent/received */ -}; +}); + +/*--- The user list: Users and Friends ---*/ +ASTOBJ_HASH_DEFINE(user_list, sip_user, 0, struct { }); + +struct user_list *userl; + +/*--- The peer list (indexed by name): Peers and Friends ---*/ +ASTOBJ_HASH_DEFINE(peer_list, sip_peer, 0, struct { }); + +struct peer_list *peerl; + +static inline unsigned int sip_peer_addrhash(const struct sockaddr_in entry); + +/*--- The peer list (indexed by address): Peers and Friends ---*/ +ASTOBJ_HASH_DEFINE_FULL(peer_addr_list, sip_peer, 1, addr, sip_peer_addrhash, ASTOBJ_HASH_DEFAULT_BUCKETS, + sip_peer_addrcmp, struct { }); + +struct peer_addr_list *peer_addrl; -/*--- The user list: Users and friends ---*/ -static struct ast_user_list { - ASTOBJ_CONTAINER_COMPONENTS(struct sip_user); -} userl; - -/*--- The peer list: Peers and Friends ---*/ -static struct ast_peer_list { - ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer); -} peerl; - -/*--- The register list: Other SIP proxys we register with and call ---*/ -static struct ast_register_list { - ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry); - int recheck; -} regl; +/*--- The register list: Other SIP proxies we register with and call ---*/ +ASTOBJ_LIST_DEFINE(registry_list, sip_registry, 0, struct { }); + +struct registry_list *regl; static int __sip_do_register(struct sip_registry *r); @@ -1135,6 +1139,9 @@ tmp = var; while(tmp) { + if (!peername && !strcasecmp(tmp->name, "name")) + peername = ast_strdupa(tmp->value); + if (!strcasecmp(tmp->name, "type") && !strcasecmp(tmp->value, "user")) { ast_destroy_realtime(var); @@ -1150,13 +1157,16 @@ return peer; } -static int sip_addrcmp(char *name, struct sockaddr_in *sin) +static inline unsigned int sip_peer_addrhash(const struct sockaddr_in entry) +{ + return entry.sin_addr.s_addr; +} + +static inline int sip_peer_addrcmp(struct sip_peer *p, const struct sockaddr_in entry, const struct sockaddr_in compare) { - /* We know name is the first field, so we can cast */ - struct sip_peer *p = (struct sip_peer *)name; - return !(!inaddrcmp(&p->addr, sin) || - (ast_test_flag(p, SIP_INSECURE) && - (p->addr.sin_addr.s_addr == sin->sin_addr.s_addr))); + return !(!inaddrcmp(&entry, &compare) || + (ast_test_flag(p, SIP_INSECURE) && + (entry.sin_addr.s_addr == compare.sin_addr.s_addr))); } /*--- find_peer: Locate peer by name or ip address */ @@ -1165,9 +1175,9 @@ struct sip_peer *p = NULL; if (peer) - p = ASTOBJ_CONTAINER_FIND(&peerl,peer); + p = peer_list_find(peerl, peer); else - p = ASTOBJ_CONTAINER_FIND_FULL(&peerl,sin,name,sip_addr_hashfunc,1,sip_addrcmp); + p = peer_addr_list_find(peer_addrl, *sin); if (!p) { p = realtime_peer(peer, sin); @@ -1228,7 +1238,7 @@ static struct sip_user *find_user(const char *name) { struct sip_user *u = NULL; - u = ASTOBJ_CONTAINER_FIND(&userl,name); + u = user_list_find(userl, name); if (!u) { u = realtime_user(name); } @@ -1312,7 +1322,7 @@ } memcpy(&r->recv, &r->sa, sizeof(r->recv)); } else { - ASTOBJ_UNREF(p,sip_destroy_peer); + sip_peer_unref(&p); } } if (!p && !found) { @@ -1346,7 +1356,7 @@ } else if (!p) return -1; else { - ASTOBJ_UNREF(p,sip_destroy_peer); + sip_peer_unref(&p); return 0; } } @@ -1489,7 +1499,7 @@ if (p->registry) { if (p->registry->call == p) p->registry->call = NULL; - ASTOBJ_UNREF(p->registry,sip_registry_destroy); + sip_registry_unref(&p->registry); } /* Unlink us from the owner if we have one */ if (p->owner) { @@ -1569,7 +1579,7 @@ if ( event == INC_OUT_USE ) { u->inUse++; } - ASTOBJ_UNREF(u,sip_destroy_user); + sip_user_unref(&u); return -1; } } @@ -1588,7 +1598,7 @@ if ( u->outgoinglimit > 0 ) { if ( u->outUse >= u->outgoinglimit ) { ast_log(LOG_ERROR, "Outgoing call from user '%s' rejected due to usage limit of %d\n", u->name, u->outgoinglimit); - ast_mutex_unlock(&userl.lock); + ast_mutex_unlock(userl.lock); if (u->temponly) { destroy_user(u); } @@ -1601,7 +1611,7 @@ default: ast_log(LOG_ERROR, "update_user_counter(%s,%d) called with no event!\n",u->name,event); } - ASTOBJ_UNREF(u,sip_destroy_user); + sip_user_unref(&u); return 0; } @@ -2448,11 +2458,9 @@ ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno); return -1; } - reg = malloc(sizeof(struct sip_registry)); + reg = sip_registry_new(NULL); if (reg) { - memset(reg, 0, sizeof(struct sip_registry)); regobjs++; - ASTOBJ_INIT(reg); strncpy(reg->contact, contact, sizeof(reg->contact) - 1); if (username) strncpy(reg->username, username, sizeof(reg->username)-1); @@ -2468,8 +2476,8 @@ reg->portno = porta ? atoi(porta) : 0; reg->callid_valid = 0; reg->ocseq = 101; - ASTOBJ_CONTAINER_LINK(®l, reg); - ASTOBJ_UNREF(reg,sip_registry_destroy); + registry_list_link(regl, reg); + sip_registry_unref(®); } else { ast_log(LOG_ERROR, "Out of memory\n"); return -1; @@ -4107,7 +4115,7 @@ static int sip_reregister(void *data) { /* if we are here, we know that we need to reregister. */ - struct sip_registry *r= ASTOBJ_REF((struct sip_registry *) data); + struct sip_registry *r = sip_registry_ref((struct sip_registry *) data); /* if we couldn't get a reference to the registry object, punt */ if (!r) @@ -4120,7 +4128,7 @@ r->expire = -1; __sip_do_register(r); - ASTOBJ_UNREF(r,sip_registry_destroy); + sip_registry_unref(&r); return 0; } @@ -4137,7 +4145,7 @@ { /* if we are here, our registration timed out, so we'll just do it over */ - struct sip_registry *r = ASTOBJ_REF((struct sip_registry *) data); + struct sip_registry *r = sip_registry_ref((struct sip_registry *) data); struct sip_pvt *p; int res; @@ -4151,7 +4159,7 @@ in the single SIP manager thread. */ p = r->call; if (p->registry) - ASTOBJ_UNREF(p->registry, sip_registry_destroy); + sip_registry_unref(&p->registry); r->call = NULL; ast_set_flag(p, SIP_NEEDDESTROY); /* Pretend to ACK anything just in case */ @@ -4161,7 +4169,7 @@ manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nUser: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate)); r->timeout = -1; res=transmit_register(r, "REGISTER", NULL, NULL); - ASTOBJ_UNREF(r,sip_registry_destroy); + sip_registry_unref(&r); return 0; } @@ -4215,7 +4223,7 @@ p->sa.sin_port = htons(r->portno); ast_set_flag(p, SIP_OUTGOING); /* Registration is outgoing call */ r->call=p; /* Save pointer to SIP packet */ - p->registry=ASTOBJ_REF(r); /* Add pointer to registry in packet */ + p->registry=sip_registry_ref(r); /* Add pointer to registry in packet */ if (!ast_strlen_zero(r->secret)) /* Secret (password) */ strncpy(p->peersecret, r->secret, sizeof(p->peersecret)-1); if (!ast_strlen_zero(r->md5secret)) @@ -4427,7 +4435,7 @@ p->expire = -1; ast_device_state_changed("SIP/%s", p->name); if (ast_test_flag(p, SIP_SELFDESTRUCT)) { - ASTOBJ_MARK(p); + sip_peer_mark(p); prune_peers(); } return 0; @@ -4847,7 +4855,7 @@ /*--- check_auth: Check user authorization from peer definition ---*/ /* Some actions, like REGISTER and INVITEs from peers require authentication (if peer have secret set) */ -static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata, int randlen, char *username, char *secret, char *md5secret, char *method, char *uri, int reliable, int ignore) +static int check_auth(struct sip_pvt *p, struct sip_request *req, char *randdata, int randlen, const char *username, char *secret, char *md5secret, char *method, char *uri, int reliable, int ignore) { int res = -1; char *response = "407 Proxy Authentication Required"; @@ -5045,7 +5053,7 @@ peer = find_peer(name, NULL); if (!(peer && ast_apply_ha(peer->ha, sin))) { if (peer) - ASTOBJ_UNREF(peer,sip_destroy_peer); + sip_peer_unref(&peer); } if (peer) { if (!ast_test_flag(peer, SIP_DYNAMIC)) { @@ -5071,7 +5079,8 @@ /* Create peer if we have autocreate mode enabled */ peer = temp_peer(name); if (peer) { - ASTOBJ_CONTAINER_LINK(&peerl, peer); + peer_list_link(peerl, peer); + peer_addr_list_link(peer_addrl, peer); peer->lastmsgssent = -1; sip_cancel_destroy(p); if (parse_contact(p, peer, req)) { @@ -5091,7 +5100,7 @@ if (res < 0) transmit_response(p, "403 Forbidden", &p->initreq); if (peer) - ASTOBJ_UNREF(peer,sip_destroy_peer); + sip_peer_unref(&peer); return res; } @@ -5627,7 +5636,7 @@ if (user) { if (!mailbox && debug) ast_verbose("Found user '%s', but fails host access\n", user->name); - ASTOBJ_UNREF(user,sip_destroy_user); + sip_user_unref(&user); } user = NULL; } @@ -5701,7 +5710,7 @@ else p->noncodeccapability &= ~AST_RTP_DTMF; } - ASTOBJ_UNREF(peer,sip_destroy_peer); + sip_peer_unref(&peer); } else { if (debug) ast_verbose("Found no matching peer or user for '%s:%d'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port)); @@ -5720,7 +5729,7 @@ } if (user) - ASTOBJ_UNREF(user,sip_destroy_user); + sip_user_unref(&user); return res; } @@ -5785,25 +5794,29 @@ char olimits[40] = ""; char iused[40]; char oused[40]; + struct sip_user *cur; + user_list_iterator *iter; if (argc != 3) return RESULT_SHOWUSAGE; ast_cli(fd, FORMAT, "Username", "incoming", "Limit","outgoing","Limit"); - ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do { - ASTOBJ_RDLOCK(iterator); - if (iterator->incominglimit) - snprintf(ilimits, sizeof(ilimits), "%d", iterator->incominglimit); + iter = user_list_open_iterator(userl); + while ((cur = user_list_iterator_next(userl, iter))) { + ASTOBJ_RDLOCK(cur); + if (cur->incominglimit) + snprintf(ilimits, sizeof(ilimits), "%d", cur->incominglimit); else strncpy(ilimits, "N/A", sizeof(ilimits) - 1); - if (iterator->outgoinglimit) - snprintf(olimits, sizeof(olimits), "%d", iterator->outgoinglimit); + if (cur->outgoinglimit) + snprintf(olimits, sizeof(olimits), "%d", cur->outgoinglimit); else strncpy(olimits, "N/A", sizeof(olimits) - 1); - snprintf(iused, sizeof(iused), "%d", iterator->inUse); - snprintf(oused, sizeof(oused), "%d", iterator->outUse); - ast_cli(fd, FORMAT2, iterator->name, iused, ilimits,oused,olimits); - ASTOBJ_UNLOCK(iterator); - } while (0) ); + snprintf(iused, sizeof(iused), "%d", cur->inUse); + snprintf(oused, sizeof(oused), "%d", cur->outUse); + ast_cli(fd, FORMAT2, cur->name, iused, ilimits,oused,olimits); + ASTOBJ_UNLOCK(cur); + }; + user_list_close_iterator(userl, &iter); return RESULT_SUCCESS; #undef FORMAT #undef FORMAT2 @@ -5830,6 +5843,8 @@ { regex_t regexbuf; int havepattern = 0; + struct sip_user *cur; + user_list_iterator *iter; #define FORMAT "%-15.15s %-15.15s %-15.15s %-15.15s %-5.5s%-5.5s\n" @@ -5844,23 +5859,24 @@ } ast_cli(fd, FORMAT, "Username", "Secret", "Accountcode", "Def.Context", "ACL", "NAT"); - ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do { - ASTOBJ_RDLOCK(iterator); + iter = user_list_open_iterator(userl); + while ((cur = user_list_iterator_next(userl, iter))) { + ASTOBJ_RDLOCK(cur); - if (havepattern && regexec(®exbuf, iterator->name, 0, NULL, 0)) { - ASTOBJ_UNLOCK(iterator); + if (havepattern && regexec(®exbuf, cur->name, 0, NULL, 0)) { + ASTOBJ_UNLOCK(cur); continue; } - ast_cli(fd, FORMAT, iterator->name, - iterator->secret, - iterator->accountcode, - iterator->context, - iterator->ha ? "Yes" : "No", - nat2str(ast_test_flag(iterator, SIP_NAT))); - ASTOBJ_UNLOCK(iterator); - } while (0) - ); + ast_cli(fd, FORMAT, cur->name, + cur->secret, + cur->accountcode, + cur->context, + cur->ha ? "Yes" : "No", + nat2str(ast_test_flag(cur, SIP_NAT))); + ASTOBJ_UNLOCK(cur); + }; + user_list_close_iterator(userl, &iter); if (havepattern) regfree(®exbuf); @@ -5883,6 +5899,8 @@ int total_peers = 0; int peers_online = 0; int peers_offline = 0; + struct sip_peer *cur; + peer_list_iterator *iter; if (argc > 4) @@ -5897,36 +5915,37 @@ ast_cli(fd, FORMAT2, "Name/username", "Host", "Dyn", "Nat", "ACL", "Mask", "Port", "Status"); - ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do { + iter = peer_list_open_iterator(peerl); + while ((cur = peer_list_iterator_next(peerl, iter))) { char nm[20] = ""; char status[20] = ""; char srch[2000]; - ASTOBJ_RDLOCK(iterator); + ASTOBJ_RDLOCK(cur); - if (havepattern && regexec(®exbuf, iterator->name, 0, NULL, 0)) { - ASTOBJ_UNLOCK(iterator); + if (havepattern && regexec(®exbuf, cur->name, 0, NULL, 0)) { + ASTOBJ_UNLOCK(cur); continue; } - ast_inet_ntoa(nm, sizeof(nm), iterator->mask); - if (!ast_strlen_zero(iterator->username)) - snprintf(name, sizeof(name), "%s/%s", iterator->name, iterator->username); + ast_inet_ntoa(nm, sizeof(nm), cur->mask); + if (!ast_strlen_zero(cur->username)) + snprintf(name, sizeof(name), "%s/%s", cur->name, cur->username); else - strncpy(name, iterator->name, sizeof(name) - 1); - if (iterator->maxms) { - if (iterator->lastms < 0) { + strncpy(name, cur->name, sizeof(name) - 1); + if (cur->maxms) { + if (cur->lastms < 0) { strncpy(status, "UNREACHABLE", sizeof(status) - 1); peers_offline++; - } else if (iterator->lastms > iterator->maxms) { - snprintf(status, sizeof(status), "LAGGED (%d ms)", iterator->lastms); + } else if (cur->lastms > cur->maxms) { + snprintf(status, sizeof(status), "LAGGED (%d ms)", cur->lastms); peers_online++; - } else if (iterator->lastms) { - snprintf(status, sizeof(status), "OK (%d ms)", iterator->lastms); + } else if (cur->lastms) { + snprintf(status, sizeof(status), "OK (%d ms)", cur->lastms); peers_online++; } else { /* Checking if port is 0 */ - if ( ntohs(iterator->addr.sin_port) == 0 ) { + if ( ntohs(cur->addr.sin_port) == 0 ) { peers_offline++; } else { peers_online++; @@ -5936,7 +5955,7 @@ } else { strncpy(status, "Unmonitored", sizeof(status) - 1); /* Checking if port is 0 */ - if ( ntohs(iterator->addr.sin_port) == 0 ) { + if ( ntohs(cur->addr.sin_port) == 0 ) { peers_offline++; } else { peers_online++; @@ -5944,24 +5963,25 @@ } snprintf(srch, sizeof(srch), FORMAT, name, - iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)", - ast_test_flag(iterator, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ - (ast_test_flag(iterator, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ - iterator->ha ? " A " : " ", /* permit/deny */ - nm, ntohs(iterator->addr.sin_port), status); + cur->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), cur->addr.sin_addr) : "(Unspecified)", + ast_test_flag(cur, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ + (ast_test_flag(cur, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ + cur->ha ? " A " : " ", /* permit/deny */ + nm, ntohs(cur->addr.sin_port), status); ast_cli(fd, FORMAT, name, - iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)", - ast_test_flag(iterator, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ - (ast_test_flag(iterator, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ - iterator->ha ? " A " : " ", /* permit/deny */ + cur->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), cur->addr.sin_addr) : "(Unspecified)", + ast_test_flag(cur, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ + (ast_test_flag(cur, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ + cur->ha ? " A " : " ", /* permit/deny */ nm, - ntohs(iterator->addr.sin_port), status); + ntohs(cur->addr.sin_port), status); - ASTOBJ_UNLOCK(iterator); + ASTOBJ_UNLOCK(cur); total_peers++; - } while(0) ); + }; + peer_list_close_iterator(peerl, &iter); ast_cli(fd,"%d sip peers [%d online , %d offline]\n",total_peers,peers_online,peers_offline); @@ -5973,19 +5993,57 @@ #undef FORMAT2 } -static int sip_show_objects(int fd, int argc, char *argv[]) +static int objects_show_peers(int fd, int argc, char *argv[]) { char tmp[256]; - if (argc != 3) - return RESULT_SHOWUSAGE; - ast_cli(fd, "-= User objects: %d static, %d realtime =-\n\n", suserobjs, ruserobjs); - ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &userl); - ast_cli(fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n\n", speerobjs, rpeerobjs, apeerobjs); - ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &peerl); - ast_cli(fd, "-= Registry objects: %d =-\n\n", regobjs); - ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), ®l); + ast_cli(fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n", speerobjs, rpeerobjs, apeerobjs); + peer_list_dump(peerl, tmp, sizeof(tmp), fd); + ast_cli(fd, "\n"); + return RESULT_SUCCESS; +} + +static int objects_show_users(int fd, int argc, char *argv[]) +{ + char tmp[256]; + ast_cli(fd, "-= User objects: %d static, %d realtime =-\n", suserobjs, ruserobjs); + user_list_dump(userl, tmp, sizeof(tmp), fd); + ast_cli(fd, "\n"); + return RESULT_SUCCESS; +} + +static int objects_show_registry(int fd, int argc, char *argv[]) +{ + char tmp[256]; + ast_cli(fd, "-= Registry objects: %d =-\n", regobjs); + registry_list_dump(regl, tmp, sizeof(tmp), fd); + ast_cli(fd, "\n"); + return RESULT_SUCCESS; +} + +static int objects_stats_peers(int fd, int argc, char *argv[]) +{ + ast_cli(fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n", speerobjs, rpeerobjs, apeerobjs); + peer_list_stats(peerl, fd); + ast_cli(fd, "\n"); + return RESULT_SUCCESS; +} + +static int objects_stats_users(int fd, int argc, char *argv[]) +{ + ast_cli(fd, "-= User objects: %d static, %d realtime =-\n", suserobjs, ruserobjs); + user_list_stats(userl, fd); + ast_cli(fd, "\n"); return RESULT_SUCCESS; } + +static int objects_stats_registry(int fd, int argc, char *argv[]) +{ + ast_cli(fd, "-= Registry objects: %d =-\n", regobjs); + registry_list_stats(regl, fd); + ast_cli(fd, "\n"); + return RESULT_SUCCESS; +} + /*--- print_group: Print call group and pickup group ---*/ static void print_group(int fd, unsigned int group) { @@ -6097,7 +6155,7 @@ ast_cli(fd, " Useragent : %s\n", peer->useragent); ast_cli(fd, " Full Contact : %s\n", peer->fullcontact); ast_cli(fd,"\n"); - ASTOBJ_UNREF(peer,sip_destroy_peer); + sip_peer_unref(&peer); } else { ast_cli(fd,"Peer %s not found.\n", argv[3]); ast_cli(fd,"\n"); @@ -6112,16 +6170,20 @@ #define FORMAT2 "%-30.30s %-12.12s %8.8s %-20.20s\n" #define FORMAT "%-30.30s %-12.12s %8d %-20.20s\n" char host[80]; + struct sip_registry *cur; + registry_list_iterator *iter; if (argc != 3) return RESULT_SHOWUSAGE; ast_cli(fd, FORMAT2, "Host", "Username", "Refresh", "State"); - ASTOBJ_CONTAINER_TRAVERSE(®l, 1, do { - ASTOBJ_RDLOCK(iterator); - snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : DEFAULT_SIP_PORT); - ast_cli(fd, FORMAT, host, iterator->username, iterator->refresh, regstate2str(iterator->regstate)); - ASTOBJ_UNLOCK(iterator); - } while(0)); + iter = registry_list_open_iterator(regl); + while ((cur = registry_list_iterator_next(regl, iter))) { + ASTOBJ_RDLOCK(cur); + snprintf(host, sizeof(host), "%s:%d", cur->hostname, cur->portno ? cur->portno : DEFAULT_SIP_PORT); + ast_cli(fd, FORMAT, host, cur->username, cur->refresh, regstate2str(cur->regstate)); + ASTOBJ_UNLOCK(cur); + }; + registry_list_close_iterator(regl, &iter); return RESULT_SUCCESS; #undef FORMAT #undef FORMAT2 @@ -6208,6 +6270,48 @@ return c; } +/*--- complete_sip_peer: Do completion on peer name ---*/ +static char *complete_sip_peer(char *word, int state) +{ + char *result = NULL; + int wordlen = strlen(word); + int which = 0; + struct sip_peer *cur; + peer_list_iterator *iter; + + iter = peer_list_open_iterator(peerl); + while ((cur = peer_list_iterator_next(peerl, iter))) { + /* locking of the object is not required because the name is immutable while it is in the list */ + if (!strncasecmp(word, cur->name, wordlen)) { + if (++which > state) { + result = strdup(cur->name); + break; + } + } + }; + peer_list_close_iterator(peerl, &iter); + + return result; +} + +/*--- complete_sip_show_peer: Support routine for 'sip show peer' CLI ---*/ +static char *complete_sip_show_peer(char *line, char *word, int pos, int state) +{ + if (pos == 3) + return complete_sip_peer(word, state); + + return NULL; +} + +/*--- complete_sip_debug_peer: Support routine for 'sip debug peer' CLI ---*/ +static char *complete_sip_debug_peer(char *line, char *word, int pos, int state) +{ + if (pos == 3) + return complete_sip_peer(word, state); + + return NULL; +} + /*--- complete_sipnotify: Support routine for 'sip notify' CLI ---*/ static char *complete_sipnotify(char *line, char *word, int pos, int state) { @@ -6235,21 +6339,8 @@ return c; } - if (pos > 2) { - int which = 0; - - /* do completion for peer name */ - - ASTOBJ_CONTAINER_TRAVERSE(&peerl, !c, do { - /* locking of the ASTOBJ is not required because I only compare the name */ - if (!strncasecmp(word, iterator->name, strlen(word))) { - if (++which > state) { - c = strdup(iterator->name); - } - } - } while(0) ); - return c; - } + if (pos > 2) + return complete_sip_peer(word, state); return NULL; } @@ -6481,7 +6572,7 @@ sipdebug = 1; } else ast_cli(fd, "Unable to get IP address of peer '%s'\n", argv[3]); - ASTOBJ_UNREF(peer,sip_destroy_peer); + sip_peer_unref(&peer); } else ast_cli(fd, "No such peer '%s'\n", argv[3]); return RESULT_SUCCESS; @@ -6849,13 +6940,29 @@ " Shows active SIP subscriptions for extension states\n"; static char show_objects_usage[] = -"Usage: sip show objects\n" +"Usage: objects show sip [peers|users|registry]\n" " Shows status of known SIP objects\n"; +static char stats_objects_usage[] = +"Usage: objects stats sip [peers|users|registry]\n" +" Shows counts/distribution of known SIP objects\n"; + static struct ast_cli_entry cli_notify = { { "sip", "notify", NULL }, sip_notify, "Send a notify packet to a SIP peer", notify_usage, complete_sipnotify }; -static struct ast_cli_entry cli_show_objects = - { { "sip", "show", "objects", NULL }, sip_show_objects, "Show all SIP object allocations", show_objects_usage }; + +static struct ast_cli_entry cli_objects_show_peers = + { { "objects", "show", "sip", "peers", NULL }, objects_show_peers, "Show all current SIP peer objects", show_objects_usage }; +static struct ast_cli_entry cli_objects_show_users = + { { "objects", "show", "sip", "users", NULL }, objects_show_users, "Show all current SIP user objects", show_objects_usage }; +static struct ast_cli_entry cli_objects_show_registry = + { { "objects", "show", "sip", "registry", NULL }, objects_show_registry, "Show all current SIP registry objects", show_objects_usage }; +static struct ast_cli_entry cli_objects_stats_peers = + { { "objects", "stats", "sip", "peers", NULL }, objects_stats_peers, "Show stats of current SIP peer objects", stats_objects_usage }; +static struct ast_cli_entry cli_objects_stats_users = + { { "objects", "stats", "sip", "users", NULL }, objects_stats_users, "Show stats of current SIP user objects", stats_objects_usage }; +static struct ast_cli_entry cli_objects_stats_registry = + { { "objects", "stats", "sip", "registry", NULL }, objects_stats_registry, "Show stats of current SIP registry objects", stats_objects_usage }; + static struct ast_cli_entry cli_show_users = { { "sip", "show", "users", NULL }, sip_show_users, "Show defined SIP users", show_users_usage }; static struct ast_cli_entry cli_show_subscriptions = @@ -6869,9 +6976,9 @@ static struct ast_cli_entry cli_debug_ip = { { "sip", "debug", "ip", NULL }, sip_do_debug, "Enable SIP debugging on IP", debug_usage }; static struct ast_cli_entry cli_debug_peer = - { { "sip", "debug", "peer", NULL }, sip_do_debug, "Enable SIP debugging on Peername", debug_usage }; + { { "sip", "debug", "peer", NULL }, sip_do_debug, "Enable SIP debugging on Peername", debug_usage, complete_sip_debug_peer }; static struct ast_cli_entry cli_show_peer = - { { "sip", "show", "peer", NULL }, sip_show_peer, "Show details on specific SIP peer", show_peer_usage }; + { { "sip", "show", "peer", NULL }, sip_show_peer, "Show details on specific SIP peer", show_peer_usage, complete_sip_show_peer }; static struct ast_cli_entry cli_show_peers = { { "sip", "show", "peers", NULL }, sip_show_peers, "Show defined SIP peers", show_peers_usage }; static struct ast_cli_entry cli_inuse_show = @@ -7158,7 +7265,7 @@ /* Schedule re-registration before we expire */ r->expire=ast_sched_add(sched, expires_ms, sip_reregister, r); - ASTOBJ_UNREF(r, sip_registry_destroy); + sip_registry_unref(&r); } else ast_log(LOG_WARNING, "Got 200 OK on REGISTER that isn't a register\n"); @@ -8195,6 +8302,8 @@ int lastpeernum = -1; int curpeernum; int reloading; + struct sip_peer *cur; + peer_list_iterator *iter; /* Add an I/O event to our UDP socket */ if (sipsock > -1) @@ -8287,20 +8396,22 @@ fastrestart = 0; curpeernum = 0; peer = NULL; - ASTOBJ_CONTAINER_TRAVERSE(&peerl, !peer, do { - if ((curpeernum > lastpeernum) && !ast_strlen_zero(iterator->mailbox) && ((t - iterator->lastmsgcheck) > global_mwitime)) { + iter = peer_list_open_iterator(peerl); + while ((cur = peer_list_iterator_next(peerl, iter))) { + if ((curpeernum > lastpeernum) && !ast_strlen_zero(cur->mailbox) && ((t - cur->lastmsgcheck) > global_mwitime)) { fastrestart = 1; lastpeernum = curpeernum; - peer = ASTOBJ_REF(iterator); + peer = sip_peer_ref(cur); + break; }; curpeernum++; - } while (0) - ); + }; + peer_list_close_iterator(peerl, &iter); if (peer) { ASTOBJ_WRLOCK(peer); sip_send_mwi_to_peer(peer); ASTOBJ_UNLOCK(peer); - ASTOBJ_UNREF(peer,sip_destroy_peer); + sip_peer_unref(&peer); } else { /* Reset where we come from */ lastpeernum = -1; @@ -8467,7 +8578,7 @@ } if (p) - ASTOBJ_UNREF(p,sip_destroy_peer); + sip_peer_unref(&p); return res; } @@ -8635,15 +8746,12 @@ char *varname = NULL, *varval = NULL; struct ast_variable *tmpvar = NULL; - user = (struct sip_user *)malloc(sizeof(struct sip_user)); + user = sip_user_new(name); if (user) { struct ast_flags userflags = {(0)}; struct ast_flags mask = {(0)}; - memset(user, 0, sizeof(struct sip_user)); suserobjs++; - ASTOBJ_INIT(user); - strncpy(user->name, name, sizeof(user->name)-1); oldha = user->ha; user->ha = NULL; /* set the usage flag to a sane staring value*/ @@ -8731,17 +8839,15 @@ static struct sip_peer *temp_peer(char *name) { struct sip_peer *peer; - peer = malloc(sizeof(struct sip_peer)); + + peer = sip_peer_new(name); if (!peer) return NULL; - memset(peer, 0, sizeof(struct sip_peer)); apeerobjs++; - ASTOBJ_INIT(peer); peer->expire = -1; peer->pokeexpire = -1; - strncpy(peer->name, name, sizeof(peer->name)-1); ast_copy_flags(peer, &global_flags, SIP_PROMISCREDIR | SIP_USEREQPHONE | SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_DTMF | SIP_NAT | SIP_REINVITE | SIP_INSECURE | SIP_PROG_INBAND | SIP_OSPAUTH); strncpy(peer->context, default_context, sizeof(peer->context)-1); strncpy(peer->language, default_language, sizeof(peer->language)-1); @@ -8770,22 +8876,23 @@ int found=0; time_t regseconds; - if (!realtime) + if (!realtime) { /* Note we do NOT use find_peer here, to avoid realtime recursion */ - peer = ASTOBJ_CONTAINER_FIND_UNLINK(&peerl, name); + peer = peer_list_find_unlink(peerl, name); + if (peer) + peer_addr_list_unlink(peer_addrl, peer); + } if (peer) { /* Already in the list, remove it and it will be added back (or FREE'd) */ found++; } else { - peer = malloc(sizeof(struct sip_peer)); + peer = sip_peer_new(name); if (peer) { - memset(peer, 0, sizeof(struct sip_peer)); if (realtime) rpeerobjs++; else speerobjs++; - ASTOBJ_INIT(peer); peer->expire = -1; peer->pokeexpire = -1; } @@ -8797,8 +8904,6 @@ peer->lastmsgssent = -1; if (!found) { - if (name) - strncpy(peer->name, name, sizeof(peer->name)-1); strncpy(peer->context, default_context, sizeof(peer->context)-1); strncpy(peer->language, default_language, sizeof(peer->language)-1); strncpy(peer->musicclass, global_musicclass, sizeof(peer->musicclass)-1); @@ -8827,9 +8932,7 @@ regseconds = 0; } else if (realtime && !strcasecmp(v->name, "ipaddr")) { inet_aton(v->value, &(peer->addr.sin_addr)); - } else if (realtime && !strcasecmp(v->name, "name")) - strncpy(peer->name, v->value, sizeof(peer->name)-1); - else if (!strcasecmp(v->name, "secret")) + } else if (!strcasecmp(v->name, "secret")) strncpy(peer->secret, v->value, sizeof(peer->secret)-1); else if (!strcasecmp(v->name, "md5secret")) strncpy(peer->md5secret, v->value, sizeof(peer->md5secret)-1); @@ -8869,7 +8972,7 @@ ast_clear_flag(peer, SIP_DYNAMIC); if (!obproxyfound || !strcasecmp(v->name, "outboundproxy")) { if (ast_get_ip_or_srv(&peer->addr, v->value, "_sip._udp")) { - ASTOBJ_UNREF(peer, sip_destroy_peer); + sip_peer_unref(&peer); return NULL; } } @@ -8882,7 +8985,7 @@ inet_aton("255.255.255.255", &peer->mask); } else if (!strcasecmp(v->name, "defaultip")) { if (ast_get_ip(&peer->defaddr, v->value)) { - ASTOBJ_UNREF(peer, sip_destroy_peer); + sip_peer_unref(&peer); return NULL; } } else if (!strcasecmp(v->name, "permit") || @@ -8957,7 +9060,7 @@ ast_copy_flags(peer, &peerflags, mask.flags); if (!found && ast_test_flag(peer, SIP_DYNAMIC)) reg_source_db(peer); - ASTOBJ_UNMARK(peer); + sip_peer_unmark(peer); } ast_free_ha(oldha); return peer; @@ -9201,15 +9304,16 @@ if (!strcasecmp(utype, "user") || !strcasecmp(utype, "friend")) { user = build_user(cat, ast_variable_browse(cfg, cat), 0); if (user) { - ASTOBJ_CONTAINER_LINK(&userl,user); - ASTOBJ_UNREF(user, sip_destroy_user); + user_list_link(userl, user); + sip_user_unref(&user); } } if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) { peer = build_peer(cat, ast_variable_browse(cfg, cat), 0); if (peer) { - ASTOBJ_CONTAINER_LINK(&peerl,peer); - ASTOBJ_UNREF(peer, sip_destroy_peer); + peer_list_link(peerl, peer); + peer_addr_list_link(peer_addrl, peer); + sip_peer_unref(&peer); } } else if (strcasecmp(utype, "user")) { ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, "sip.conf"); @@ -9527,38 +9631,47 @@ static void delete_users(void) { /* Delete all users */ - ASTOBJ_CONTAINER_DESTROYALL(&userl,sip_destroy_user); - ASTOBJ_CONTAINER_DESTROYALL(®l,sip_registry_destroy); - ASTOBJ_CONTAINER_MARKALL(&peerl); + user_list_unlink_all(userl); + registry_list_unlink_all(regl); + peer_list_mark_all(peerl); } /*--- prune_peers: Delete all peers marked for deletion ---*/ static void prune_peers(void) { /* Prune peers who still are supposed to be deleted */ - ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl,sip_destroy_peer); + peer_list_prune_marked(peerl); + peer_addr_list_prune_marked(peer_addrl); } /*--- sip_poke_all_peers: Send a poke to all known peers */ static void sip_poke_all_peers(void) { - ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do { - ASTOBJ_WRLOCK(iterator); - sip_poke_peer(iterator); - ASTOBJ_UNLOCK(iterator); - } while (0) - ); + struct sip_peer *cur; + peer_list_iterator *iter; + + iter = peer_list_open_iterator(peerl); + while ((cur = peer_list_iterator_next(peerl, iter))) { + ASTOBJ_WRLOCK(cur); + sip_poke_peer(cur); + ASTOBJ_UNLOCK(cur); + }; + peer_list_close_iterator(peerl, &iter); } /*--- sip_send_all_registers: Send all known registrations */ static void sip_send_all_registers(void) { - ASTOBJ_CONTAINER_TRAVERSE(®l, 1, do { - ASTOBJ_WRLOCK(iterator); - __sip_do_register(iterator); - ASTOBJ_UNLOCK(iterator); - } while (0) - ); + struct sip_registry *cur; + registry_list_iterator *iter; + + iter = registry_list_open_iterator(regl); + while ((cur = registry_list_iterator_next(regl, iter))) { + ASTOBJ_WRLOCK(cur); + __sip_do_register(cur); + ASTOBJ_UNLOCK(cur); + }; + registry_list_close_iterator(regl, &iter); } /*--- sip_do_reload: Reload module */ @@ -9600,9 +9713,10 @@ { int res; - ASTOBJ_CONTAINER_INIT(&userl); - ASTOBJ_CONTAINER_INIT(&peerl); - ASTOBJ_CONTAINER_INIT(®l); + userl = user_list_new(); + peerl = peer_list_new(); + peer_addrl = peer_addr_list_new(); + regl = registry_list_new(); sched = sched_context_create(); if (!sched) { ast_log(LOG_WARNING, "Unable to create schedule context\n"); @@ -9621,8 +9735,17 @@ return -1; } ast_cli_register(&cli_notify); +#ifdef ASTOBJ_DUMP + ast_cli_register(&cli_objects_show_peers); + ast_cli_register(&cli_objects_show_users); + ast_cli_register(&cli_objects_show_registry); +#endif +#ifdef ASTOBJ_STATS + ast_cli_register(&cli_objects_stats_peers); + ast_cli_register(&cli_objects_stats_users); + ast_cli_register(&cli_objects_stats_registry); +#endif ast_cli_register(&cli_show_users); - ast_cli_register(&cli_show_objects); ast_cli_register(&cli_show_subscriptions); ast_cli_register(&cli_show_channels); ast_cli_register(&cli_show_channel); @@ -9661,8 +9784,17 @@ ast_unregister_application(app_sipaddheader); ast_unregister_application(app_sipgetheader); ast_cli_unregister(&cli_notify); +#ifdef ASTOBJ_DUMP + ast_cli_unregister(&cli_objects_show_peers); + ast_cli_unregister(&cli_objects_show_users); + ast_cli_unregister(&cli_objects_show_registry); +#endif +#ifdef ASTOBJ_STATS + ast_cli_unregister(&cli_objects_stats_peers); + ast_cli_unregister(&cli_objects_stats_users); + ast_cli_unregister(&cli_objects_stats_registry); +#endif ast_cli_unregister(&cli_show_users); - ast_cli_unregister(&cli_show_objects); ast_cli_unregister(&cli_show_channels); ast_cli_unregister(&cli_show_channel); ast_cli_unregister(&cli_show_history); @@ -9729,9 +9861,14 @@ } /* Free memory for local network address mask */ ast_free_ha(localaddr); - ASTOBJ_CONTAINER_DESTROY(&userl); - ASTOBJ_CONTAINER_DESTROY(&peerl); - ASTOBJ_CONTAINER_DESTROY(®l); + user_list_unlink_all(userl); + user_list_destroy(&userl); + peer_addr_list_unlink_all(peer_addrl); + peer_addr_list_destroy(&peer_addrl); + peer_list_unlink_all(peerl); + peer_list_destroy(&peerl); + registry_list_unlink_all(regl); + registry_list_destroy(®l); return 0; } diff -Nru a/include/asterisk/acl.h b/include/asterisk/acl.h --- a/include/asterisk/acl.h 2005-01-15 19:06:56 -07:00 +++ b/include/asterisk/acl.h 2005-01-15 19:06:56 -07:00 @@ -21,7 +21,6 @@ #include #include -#include #define AST_SENSE_DENY 0 #define AST_SENSE_ALLOW 1 @@ -30,11 +29,7 @@ struct ast_ha; struct ast_netsock; - -struct ast_netsock_list { - ASTOBJ_CONTAINER_COMPONENTS(struct ast_netsock); - struct io_context *ioc; -}; +struct ast_netsock_list; extern void ast_free_ha(struct ast_ha *ha); extern struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path); @@ -44,17 +39,17 @@ extern int ast_ouraddrfor(struct in_addr *them, struct in_addr *us); extern int ast_lookup_iface(char *iface, struct in_addr *address); extern struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original); -extern int ast_netsock_init(struct ast_netsock_list *list); +extern int ast_netsock_init(struct ast_netsock_list **list); extern struct ast_netsock *ast_netsock_bind(struct ast_netsock_list *list, struct io_context *ioc, const char *bindinfo, int defaultport, int tos, ast_io_cb callback, void *data); extern struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct io_context *ioc, struct sockaddr_in *bindaddr, int tos, ast_io_cb callback, void *data); extern int ast_netsock_free(struct ast_netsock_list *list, struct ast_netsock *netsock); -extern int ast_netsock_release(struct ast_netsock_list *list); +extern int ast_netsock_release(struct ast_netsock_list **list); extern int ast_netsock_sockfd(struct ast_netsock *ns); /*! Compares the source address and port of two sockaddr_in */ -static inline int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2) +static inline int inaddrcmp(const struct sockaddr_in *sin1, const struct sockaddr_in *sin2) { - return ((sin1->sin_addr.s_addr != sin2->sin_addr.s_addr ) + return ((sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) || (sin1->sin_port != sin2->sin_port)); } diff -Nru a/include/asterisk/astobj.h b/include/asterisk/astobj.h --- a/include/asterisk/astobj.h 2005-01-15 19:06:56 -07:00 +++ b/include/asterisk/astobj.h 2005-01-15 19:06:56 -07:00 @@ -7,6 +7,9 @@ * * Mark Spencer * + * Function-model implementation written by + * Kevin P. Fleming + * * This program is free software, distributed under the terms of * the GNU General Public License */ @@ -14,29 +17,38 @@ #ifndef _ASTERISK_ASTOBJ_H #define _ASTERISK_ASTOBJ_H +#include #include #include +#include +#include +#ifdef ASTOBJ_DUMP +#include +#endif +#ifdef ASTOBJ_STATS +#include +#endif /*! \file astobj.h - \brief A set of macros implementing the asterisk object and container. Macros - are used for maximum performance, to support multiple inheritance, and - to be easily integrated into existing structures without additional - malloc calls, etc. + \brief A set of macros implementing reference-counted objects, list- and hash-based containers. */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif -#define ASTOBJ_DEFAULT_NAMELEN 80 -#define ASTOBJ_DEFAULT_BUCKETS 256 -#define ASTOBJ_DEFAULT_HASH ast_strhash - #define ASTOBJ_FLAG_MARKED (1 << 0) /* Object has been marked for future operation */ #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) #define __builtin_expect(exp, c) (exp) +#define astobj_unused +#define astobj_warn_unused_result +#define astobj_aligned +#else +#define astobj_unused __attribute__ ((__unused__)) +#define astobj_warn_unused_result __attribute__ ((__warn_unused_result__)) +#define astobj_aligned __attribute__ ((__aligned__)) #endif /* C++ is simply a syntactic crutch for those who cannot think for themselves @@ -46,248 +58,640 @@ #define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock) #define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock) -#ifdef ASTOBJ_CONTAINER_HASHMODEL -#define __ASTOBJ_HASH(type,hashes) \ - type *next[hashes] -#else -#define __ASTOBJ_HASH(type,hashes) \ - type *next[1] -#endif - -#define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \ - char name[namelen]; \ - int refcount; \ - int objflags; \ - __ASTOBJ_HASH(type,hashes) - -#define ASTOBJ_COMPONENTS_NOLOCK(type) \ - ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1) - -#define ASTOBJ_COMPONENTS(type) \ - ASTOBJ_COMPONENTS_NOLOCK(type); \ - ast_mutex_t _lock; - -#define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \ - ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes); \ - ast_mutex_t _lock; - -#define ASTOBJ_REF(object) \ - ({ \ - ASTOBJ_WRLOCK(object); \ - (object)->refcount++; \ - ASTOBJ_UNLOCK(object); \ - (object); \ - }) - -#define ASTOBJ_UNREF(object,destructor) \ - do { \ - int newcount = 0; \ - ASTOBJ_WRLOCK(object); \ - if (__builtin_expect((object)->refcount, 1)) \ - newcount = --((object)->refcount); \ - else \ - ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \ - ASTOBJ_UNLOCK(object); \ - if (newcount == 0) { \ - ast_mutex_destroy(&(object)->_lock); \ - destructor((object)); \ - } \ - (object) = NULL; \ - } while(0) - -#define ASTOBJ_MARK(object) \ - do { \ - ASTOBJ_WRLOCK(object); \ - (object)->objflags |= ASTOBJ_FLAG_MARKED; \ - ASTOBJ_UNLOCK(object); \ - } while(0) - -#define ASTOBJ_UNMARK(object) \ - do { \ - ASTOBJ_WRLOCK(object); \ - (object)->objflags &= ~ASTOBJ_FLAG_MARKED; \ - ASTOBJ_UNLOCK(object); \ - } while(0) - -#define ASTOBJ_INIT(object) \ - do { \ - ast_mutex_init(&(object)->_lock); \ - object->name[0] = '\0'; \ - object->refcount = 1; \ - } while(0) - -/* Containers for objects -- current implementation is linked lists, but - should be able to be converted to hashes relatively easily */ - -#define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock) -#define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock) -#define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock) - -#ifdef ASTOBJ_CONTAINER_HASHMODEL -#error "Hash model for object containers not yet implemented!" +#ifdef AST_HAVE_ATOMIC +#define ASTOBJ_COUNTER AST_ATOMIC_T +#define ASTOBJ_READ(obj, field) AST_ATOMIC_READ((obj)->field) +#define ASTOBJ_SET(obj, field, val) AST_ATOMIC_SET((obj)->field, val) +#define ASTOBJ_INC(obj, field) AST_ATOMIC_INC((obj)->field) +#define ASTOBJ_DEC(obj, field) AST_ATOMIC_DEC((obj)->field) +#define ASTOBJ_DEC_TEST_ZERO(obj, field) AST_ATOMIC_DEC_AND_TEST_ZERO((obj)->field) #else -/* Linked lists */ -#define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \ - type *head - -#define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \ - do { \ - ast_mutex_init(&(container)->_lock); \ - } while(0) - -#define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \ - do { \ - ast_mutex_destroy(&(container)->_lock); \ - } while(0) - -#define ASTOBJ_CONTAINER_TRAVERSE(container,continue,eval) \ - do { \ - typeof((container)->head) iterator; \ - typeof((container)->head) next; \ - ASTOBJ_CONTAINER_RDLOCK(container); \ - next = (container)->head; \ - while((continue) && (iterator = next)) { \ - next = iterator->next[0]; \ - eval; \ - } \ - ASTOBJ_CONTAINER_UNLOCK(container); \ - } while(0) - -#define ASTOBJ_CONTAINER_FIND(container,namestr) \ - ({ \ - typeof((container)->head) found = NULL; \ - ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \ - if (!(strcasecmp(iterator->name, (namestr)))) \ - found = ASTOBJ_REF(iterator); \ - } while (0)); \ - found; \ - }) - -#define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \ - ({ \ - typeof((container)->head) found = NULL; \ - ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \ - ASTOBJ_RDLOCK(iterator); \ - if (!(comparefunc(iterator->field, (data)))) { \ - found = ASTOBJ_REF(iterator); \ - } \ - ASTOBJ_UNLOCK(iterator); \ - } while (0)); \ - found; \ - }) - -#define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \ - do { \ - typeof((container)->head) iterator; \ - ASTOBJ_CONTAINER_WRLOCK(container); \ - while((iterator = (container)->head)) { \ - (container)->head = (iterator)->next[0]; \ - ASTOBJ_UNREF(iterator,destructor); \ - } \ - ASTOBJ_CONTAINER_UNLOCK(container); \ - } while(0) - -#define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \ - ({ \ - typeof((container)->head) found = NULL; \ - typeof((container)->head) prev = NULL; \ - ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \ - if (!(strcasecmp(iterator->name, (namestr)))) { \ - found = iterator; \ - found->next[0] = NULL; \ - ASTOBJ_CONTAINER_WRLOCK(container); \ - if (prev) \ - prev->next[0] = next; \ - else \ - (container)->head = next; \ - ASTOBJ_CONTAINER_UNLOCK(container); \ - } \ - prev = iterator; \ - } while (0)); \ - found; \ - }) - -#define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \ - ({ \ - typeof((container)->head) found = NULL; \ - typeof((container)->head) prev = NULL; \ - ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \ - ASTOBJ_RDLOCK(iterator); \ - if (!(comparefunc(iterator->field, (data)))) { \ - found = iterator; \ - found->next[0] = NULL; \ - ASTOBJ_CONTAINER_WRLOCK(container); \ - if (prev) \ - prev->next[0] = next; \ - else \ - (container)->head = next; \ - ASTOBJ_CONTAINER_UNLOCK(container); \ - } \ - ASTOBJ_UNLOCK(iterator); \ - prev = iterator; \ - } while (0)); \ - found; \ +#define ASTOBJ_COUNTER int +#define ASTOBJ_READ(obj, field) (obj)->field +#define ASTOBJ_SET(obj, field, val) (obj)->field = val +#define ASTOBJ_INC(obj, field) \ + ASTOBJ_WRLOCK(obj); \ + obj->field++; \ + ASTOBJ_UNLOCK(obj); +#define ASTOBJ_DEC(obj, field) \ + ASTOBJ_WRLOCK(obj); \ + obj->field--; \ + ASTOBJ_UNLOCK(obj); +#define ASTOBJ_DEC_TEST_ZERO(obj, field) ({ \ + int newcount = 0; \ + ASTOBJ_WRLOCK(obj); \ + newcount = --((obj)->field); \ + ASTOBJ_UNLOCK(obj); \ + (newcount == 0); \ }) +#endif -#define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \ - do { \ - typeof((container)->head) prev = NULL; \ - ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { \ - ASTOBJ_RDLOCK(iterator); \ - if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \ - ASTOBJ_CONTAINER_WRLOCK(container); \ - if (prev) \ - prev->next[0] = next; \ - else \ - (container)->head = next; \ - ASTOBJ_CONTAINER_UNLOCK(container); \ - ASTOBJ_UNLOCK(iterator); \ - ASTOBJ_UNREF(iterator,destructor); \ - continue; \ - } \ - ASTOBJ_UNLOCK(iterator); \ - prev = iterator; \ - } while (0)); \ - } while(0) - -#define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \ - do { \ - ASTOBJ_CONTAINER_WRLOCK(container); \ - (newobj)->next[0] = (container)->head; \ - (container)->head = ASTOBJ_REF(newobj); \ - ASTOBJ_CONTAINER_UNLOCK(container); \ - } while(0) - -#endif /* List model */ - -/* Common to hash and linked list models */ -#define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \ - ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS) +#ifdef ASTOBJ_STATS +#define ASTOBJ_STAT_COUNT struct { ASTOBJ_COUNTER count; } +#define ASTOBJ_STAT_INC(obj) ASTOBJ_INC(obj, count) +#define ASTOBJ_STAT_DEC(obj) ASTOBJ_DEC(obj, count) +#else +#define ASTOBJ_STAT_COUNT +#define ASTOBJ_STAT_INC(obj) +#define ASTOBJ_STAT_DEC(obj) +#endif -#define ASTOBJ_CONTAINER_COMPONENTS(type) \ +#define ASTOBJ_DEFINE(type, destructor, indexes, fields) \ +struct type { \ + const char *name; \ ast_mutex_t _lock; \ - ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) - -#define ASTOBJ_CONTAINER_INIT(container) \ - ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS) - -#define ASTOBJ_CONTAINER_DESTROY(container) \ - ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS) - -#define ASTOBJ_CONTAINER_LINK(container,newobj) \ - ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp) - -#define ASTOBJ_CONTAINER_MARKALL(container) \ - ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_MARK(iterator)) + ASTOBJ_COUNTER refcount; \ + unsigned int objflags; \ + struct type *next[indexes]; \ + fields; \ +} astobj_aligned; \ +static void destructor(struct type *); \ +static astobj_warn_unused_result inline struct type *type ## _new(const char *name) \ +{ \ + struct type *obj = NULL; \ + int size = sizeof(*obj); \ + int namesize = 0; \ + if (name) \ + size += (namesize = strlen(name)) + 1; \ + obj = calloc(1, size); \ + if (obj) { \ + ast_mutex_init(&obj->_lock); \ + ASTOBJ_SET(obj, refcount, 1); \ + obj->name = (char *) obj + sizeof(*obj); \ + if (namesize) \ + memcpy((void *) obj->name, name, namesize); \ + } \ + return obj; \ +} \ +static astobj_warn_unused_result inline struct type *type ## _ref(struct type *obj) \ +{ \ + ASTOBJ_INC(obj, refcount); \ + return obj; \ +} \ +static inline void type ## _unref(struct type **obj) \ +{ \ + if (__builtin_expect(ASTOBJ_DEC_TEST_ZERO(*obj, refcount), 0)) { \ + ast_mutex_destroy(&((*obj)->_lock)); \ + destructor(*obj); \ + } \ + *obj = NULL; \ +} \ +static astobj_unused inline void type ## _mark(struct type *obj) \ +{ \ + ASTOBJ_WRLOCK(obj); \ + obj->objflags |= ASTOBJ_FLAG_MARKED; \ + ASTOBJ_UNLOCK(obj); \ +} \ +static astobj_unused inline void type ## _unmark(struct type *obj) \ +{ \ + ASTOBJ_WRLOCK(obj); \ + obj->objflags &= ~ASTOBJ_FLAG_MARKED; \ + ASTOBJ_UNLOCK(obj); \ +} \ +static astobj_unused inline void type ## _dump(struct type *obj, char *s, int slen) \ +{ \ + snprintf(s, slen, "refcount: %6d\tobjflags: %8d\tname: %s\n", ASTOBJ_READ(obj, refcount), obj->objflags, obj->name); \ +} + +#define ASTOBJ_BUCKET_RDLOCK(container, bucketno) ast_mutex_lock(&(container)->bucket[bucketno]._lock) +#define ASTOBJ_BUCKET_WRLOCK(container, bucketno) ast_mutex_lock(&(container)->bucket[bucketno]._lock) +#define ASTOBJ_BUCKET_UNLOCK(container, bucketno) ast_mutex_unlock(&(container)->bucket[bucketno]._lock) + +/* TODO: + implement multiple iterators for HASH + implement stats counting + implement stats reporting + */ -#define ASTOBJ_CONTAINER_UNMARKALL(container) \ - ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_UNMARK(iterator)) +#define ASTOBJ_LIST_DEFINE_FULL(type, objtype, index, indexfield, comparefunc, fields) \ +typedef struct { \ + ast_mutex_t _lock; \ + struct objtype *next; \ +} astobj_aligned type ## _iterator; \ +typedef struct { \ + ast_mutex_t _lock; \ + ASTOBJ_STAT_COUNT; \ + struct objtype *head; \ + struct objtype *tail; \ +} astobj_aligned type ## _bucket; \ +struct type { \ + ast_mutex_t _lock; \ + type ## _bucket bucket[1]; \ + type ## _iterator iterator; \ + fields; \ +} astobj_aligned; \ +typedef typeof(((struct objtype *) NULL)->indexfield) __ ## type ## _indextype; \ +static astobj_unused inline int comparefunc(struct objtype *obj, const __ ## type ## _indextype entry, const __ ## type ## _indextype compare); \ +static astobj_warn_unused_result inline struct type *type ## _new(void) \ +{ \ + struct type *ctr = NULL; \ + ctr = calloc(1, sizeof(*ctr)); \ + if (ctr) { \ + ast_mutex_init(&(ctr->iterator._lock)); \ + ast_mutex_init(&(ctr->bucket[0]._lock)); \ + } \ + return ctr; \ +} \ +static inline void type ## _destroy(struct type **ctr) \ +{ \ + ast_mutex_destroy(&((*ctr)->bucket[0]._lock)); \ + ast_mutex_destroy(&((*ctr)->iterator._lock)); \ + free(*ctr); \ + *ctr = NULL; \ +} \ +static inline void type ## _link(struct type *ctr, struct objtype *obj) \ +{ \ + ASTOBJ_BUCKET_WRLOCK(ctr, 0); \ + obj->next[index] = ctr->bucket[0].head; \ + ctr->bucket[0].head = objtype ## _ref(obj); \ + if (!ctr->bucket[0].tail) \ + ctr->bucket[0].tail = ctr->bucket[0].head; \ + ASTOBJ_BUCKET_UNLOCK(ctr, 0); \ + ASTOBJ_STAT_INC(&(ctr->bucket[0])); \ +} \ +static astobj_unused inline void type ## _link_tail(struct type *ctr, struct objtype *obj) \ +{ \ + ASTOBJ_BUCKET_WRLOCK(ctr, 0); \ + ctr->bucket[0].tail->next[index] = objtype ## _ref(obj); \ + ctr->bucket[0].tail = obj; \ + ASTOBJ_BUCKET_UNLOCK(ctr, 0); \ + ASTOBJ_STAT_INC(&(ctr->bucket[0])); \ +} \ +static astobj_unused inline void type ## _link_after(struct type *ctr, struct objtype *prev, struct objtype *obj) \ +{ \ + ASTOBJ_BUCKET_WRLOCK(ctr, 0); \ + obj->next[index] = prev->next[index]; \ + prev->next[index] = objtype ## _ref(obj); \ + if (ctr->bucket[0].tail == prev) \ + ctr->bucket[0].tail = obj; \ + ASTOBJ_BUCKET_UNLOCK(ctr, 0); \ + ASTOBJ_STAT_INC(&(ctr->bucket[0])); \ +} \ +static astobj_unused inline void type ## _unlink_all(struct type *ctr) \ +{ \ + struct objtype *cur; \ + ASTOBJ_BUCKET_WRLOCK(ctr, 0); \ + while((cur = ctr->bucket[0].head)) { \ + ctr->bucket[0].head = cur->next[index]; \ + objtype ## _unref(&cur); \ + ASTOBJ_STAT_DEC(&(ctr->bucket[0])); \ + } \ + ctr->bucket[0].tail = NULL; \ + ASTOBJ_BUCKET_UNLOCK(ctr, 0); \ +} \ +static astobj_unused astobj_warn_unused_result inline type ## _iterator *type ## _open_iterator(struct type *ctr) \ +{ \ + type ## _iterator *iter = &ctr->iterator; \ + ASTOBJ_WRLOCK(iter); \ + /* not needed until support for multiple iterators is in place, \ + since this container has only a single bucket */ \ + /* ASTOBJ_BUCKET_RDLOCK(ctr, 0); */ \ + iter->next = ctr->bucket[0].head; \ + return iter; \ +} \ +static astobj_unused astobj_warn_unused_result inline struct objtype *type ## _iterator_next(struct type *ctr, type ## _iterator *iter) \ +{ \ + struct objtype *result = iter->next; \ + if (iter->next) \ + iter->next = iter->next->next[index]; \ + return result; \ +} \ +static astobj_unused astobj_warn_unused_result inline struct objtype *type ## _iterator_peek(struct type *ctr, type ## _iterator *iter) \ +{ \ + return iter->next; \ +} \ +static astobj_unused inline void type ## _close_iterator(struct type *ctr, type ## _iterator **iter) \ +{ \ + /* not needed until support for multiple iterators is in place, \ + since this container has only a single bucket */ \ + /* ASTOBJ_BUCKET_UNLOCK(ctr, 0); */ \ + ASTOBJ_UNLOCK(*iter); \ + *iter = NULL; \ +} \ +static inline void type ## _unlink(struct type *ctr, struct objtype *obj) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + struct objtype *prev = NULL; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + if (cur == obj) { \ + ASTOBJ_BUCKET_WRLOCK(ctr, 0); \ + cur->next[index] = NULL; \ + if (prev) \ + prev->next[index] = type ## _iterator_peek(ctr, iterator); \ + else \ + ctr->bucket[0].head = type ## _iterator_peek(ctr, iterator); \ + if (cur == ctr->bucket[0].tail) \ + ctr->bucket[0].tail = prev; \ + ASTOBJ_BUCKET_UNLOCK(ctr, 0); \ + objtype ## _unref(&cur); \ + ASTOBJ_STAT_DEC(&(ctr->bucket[0])); \ + break; \ + } \ + prev = cur; \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused astobj_warn_unused_result inline struct objtype *type ## _find(struct type *ctr, const __ ## type ## _indextype compare) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + struct objtype *found = NULL; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + if (!comparefunc(cur, cur->indexfield, compare)) { \ + found = objtype ## _ref(cur); \ + break; \ + } \ + } \ + type ## _close_iterator(ctr, &iterator); \ + return found; \ +} \ +static astobj_unused astobj_warn_unused_result inline struct objtype *type ## _find_unlink(struct type *ctr, const __ ## type ## _indextype compare) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + struct objtype *found = NULL; \ + struct objtype *prev = NULL; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + if (!comparefunc(cur, cur->indexfield, compare)) { \ + found = cur; \ + ASTOBJ_BUCKET_WRLOCK(ctr, 0); \ + found->next[index] = NULL; \ + if (prev) \ + prev->next[index] = type ## _iterator_peek(ctr, iterator); \ + else \ + ctr->bucket[0].head = type ## _iterator_peek(ctr, iterator); \ + if (cur == ctr->bucket[0].tail) \ + ctr->bucket[0].tail = prev; \ + ASTOBJ_BUCKET_UNLOCK(ctr, 0); \ + ASTOBJ_STAT_DEC(&(ctr->bucket[0])); \ + break; \ + } \ + prev = cur; \ + } \ + type ## _close_iterator(ctr, &iterator); \ + return found; \ +} \ +static astobj_unused inline void type ## _prune_marked(struct type *ctr) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + struct objtype *prev = NULL; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + ASTOBJ_RDLOCK(cur); \ + if (cur->objflags & ASTOBJ_FLAG_MARKED) { \ + ASTOBJ_BUCKET_WRLOCK(ctr, 0); \ + if (prev) \ + prev->next[index] = type ## _iterator_peek(ctr, iterator); \ + else \ + ctr->bucket[0].head = type ## _iterator_peek(ctr, iterator); \ + if (cur == ctr->bucket[0].tail) \ + ctr->bucket[0].tail = prev; \ + ASTOBJ_BUCKET_UNLOCK(ctr, 0); \ + ASTOBJ_UNLOCK(cur); \ + objtype ## _unref(&cur); \ + ASTOBJ_STAT_DEC(&(ctr->bucket[0])); \ + continue; \ + } \ + ASTOBJ_UNLOCK(cur); \ + prev = cur; \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused inline void type ## _mark_all(struct type *ctr) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + objtype ## _mark(cur); \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused inline void type ## _unmark_all(struct type *ctr) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + objtype ## _unmark(cur); \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused inline void type ## _dump(struct type *ctr, char *s, int slen, int fd) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + objtype ## _dump(cur, s, slen); \ + ast_cli(fd, s); \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused inline void type ## _stats(struct type *ctr, int fd) \ +{ \ + ast_cli(fd, "Count: %d\n", ASTOBJ_READ(&(ctr->bucket[0]), count)); \ +} + +#define ASTOBJ_LIST_DEFINE(type, objtype, index, fields) \ +ASTOBJ_LIST_DEFINE_FULL(type, objtype, index, name, __ ## type ## _namecmp, fields); \ +static astobj_unused inline int __ ## type ## _namecmp(struct objtype *obj, const char *entry, const char *compare) \ +{ \ + return strcasecmp(entry, compare); \ +} \ -#define ASTOBJ_DUMP(s,slen,obj) \ - snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount); +#define ASTOBJ_HASH_SINGLE_BUCKET (1 << 0) +#define ASTOBJ_HASH_BUCKET_LOCKED (2 << 0) -#define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \ - ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0)) +#define ASTOBJ_HASH_DEFINE_FULL(type, objtype, index, indexfield, hashfunc, buckets, comparefunc, fields) \ +typedef struct { \ + ast_mutex_t _lock; \ + unsigned int bucket; \ + unsigned int flags; \ + struct objtype *next; \ +} astobj_aligned type ## _iterator; \ +typedef struct { \ + ast_mutex_t _lock; \ + ASTOBJ_STAT_COUNT; \ + struct objtype *head; \ +} astobj_aligned type ## _bucket; \ +struct type { \ + ast_mutex_t _lock; \ + type ## _bucket bucket[buckets]; \ + type ## _iterator iterator; \ + fields; \ +} astobj_aligned ; \ +typedef typeof(((struct objtype *) NULL)->indexfield) __ ## type ## _indextype; \ +static astobj_unused inline int comparefunc(struct objtype *obj, const __ ## type ## _indextype entry, const __ ## type ## _indextype compare); \ +static inline unsigned int __ ## type ## _makehash(const __ ## type ## _indextype entry) \ +{ \ + return hashfunc(entry) % buckets; \ +} \ +static astobj_warn_unused_result inline struct type *type ## _new(void) \ +{ \ + struct type *ctr = NULL; \ + unsigned int i; \ + ctr = calloc(1, sizeof(*ctr)); \ + if (ctr) { \ + ast_mutex_init(&(ctr->iterator._lock)); \ + for (i = 0; i < buckets; i++) \ + ast_mutex_init(&(ctr->bucket[i]._lock)); \ + } \ + return ctr; \ +} \ +static inline void type ## _destroy(struct type **ctr) \ +{ \ + unsigned int i; \ + for (i = 0; i < buckets; i++) \ + ast_mutex_destroy(&((*ctr)->bucket[i]._lock)); \ + ast_mutex_destroy(&((*ctr)->iterator._lock)); \ + free(*ctr); \ + *ctr = NULL; \ +} \ +static inline void type ## _link(struct type *ctr, struct objtype *obj) \ +{ \ + unsigned int i = __ ## type ## _makehash(obj->indexfield); \ + ASTOBJ_BUCKET_WRLOCK(ctr, i); \ + obj->next[index] = ctr->bucket[i].head; \ + ctr->bucket[i].head = objtype ## _ref(obj); \ + ASTOBJ_BUCKET_UNLOCK(ctr, i); \ + ASTOBJ_STAT_INC(&(ctr->bucket[i])); \ +} \ +static astobj_unused inline void type ## _unlink_all(struct type *ctr) \ +{ \ + unsigned int i; \ + struct objtype *cur; \ + for (i = 0; i < buckets; i++) { \ + ASTOBJ_BUCKET_WRLOCK(ctr, i); \ + while((cur = ctr->bucket[i].head)) { \ + ctr->bucket[i].head = cur->next[index]; \ + objtype ## _unref(&cur); \ + ASTOBJ_STAT_DEC(&(ctr->bucket[i])); \ + } \ + ASTOBJ_BUCKET_UNLOCK(ctr, i); \ + } \ +} \ +static astobj_unused astobj_warn_unused_result inline type ## _iterator *type ## _open_iterator(struct type *ctr) \ +{ \ + type ## _iterator *iter = &ctr->iterator; \ + ASTOBJ_WRLOCK(iter); \ + for (iter->bucket = 0; iter->bucket < buckets; iter->bucket++) { \ + ASTOBJ_BUCKET_RDLOCK(ctr, iter->bucket); \ + if ((iter->next = ctr->bucket[iter->bucket].head)) \ + break; \ + ASTOBJ_BUCKET_UNLOCK(ctr, iter->bucket); \ + } \ + if (iter->next) \ + ast_set_flag(iter, ASTOBJ_HASH_BUCKET_LOCKED); \ + return iter; \ +} \ +static astobj_unused astobj_warn_unused_result inline type ## _iterator *type ## _open_bucket_iterator(struct type *ctr, unsigned int bucketno) \ +{ \ + type ## _iterator *iter = &ctr->iterator; \ + ASTOBJ_WRLOCK(iter); \ + iter->bucket = bucketno; \ + if ((iter->next = ctr->bucket[bucketno].head)) { \ + ASTOBJ_BUCKET_RDLOCK(ctr, bucketno); \ + ast_set_flag(iter, ASTOBJ_HASH_BUCKET_LOCKED | ASTOBJ_HASH_SINGLE_BUCKET); \ + } \ + return iter; \ +} \ +static astobj_unused astobj_warn_unused_result inline struct objtype *type ## _iterator_next(struct type *ctr, type ## _iterator *iter) \ +{ \ + struct objtype *result = iter->next; \ + if (iter->next) { \ + iter->next = iter->next->next[index]; \ + if (!iter->next && !ast_test_flag(iter, ASTOBJ_HASH_SINGLE_BUCKET)) { \ + ASTOBJ_BUCKET_UNLOCK(ctr, iter->bucket); \ + for (iter->bucket++; iter->bucket < buckets; iter->bucket++) { \ + ASTOBJ_BUCKET_RDLOCK(ctr, iter->bucket); \ + if ((iter->next = ctr->bucket[iter->bucket].head)) \ + break; \ + ASTOBJ_BUCKET_UNLOCK(ctr, iter->bucket); \ + } \ + if (iter->next) \ + ast_set_flag(iter, ASTOBJ_HASH_BUCKET_LOCKED); \ + } \ + } \ + return result; \ +} \ +static astobj_unused astobj_warn_unused_result inline struct objtype *type ## _iterator_peek(struct type *ctr, type ## _iterator *iter) \ +{ \ + return iter->next; \ +} \ +static astobj_unused inline void type ## _close_iterator(struct type *ctr, type ## _iterator **iter) \ +{ \ + if (ast_test_flag(*iter, ASTOBJ_HASH_BUCKET_LOCKED)) \ + ASTOBJ_BUCKET_UNLOCK(ctr, (*iter)->bucket); \ + ast_clear_flag(*iter, AST_FLAGS_ALL); \ + ASTOBJ_UNLOCK(*iter); \ + *iter = NULL; \ +} \ +static inline void type ## _unlink(struct type *ctr, struct objtype *obj) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + struct objtype *prev = NULL; \ + iterator = type ## _open_bucket_iterator(ctr, __ ## type ## _makehash(obj->indexfield)); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + if (cur == obj) { \ + ASTOBJ_BUCKET_WRLOCK(ctr, iterator->bucket); \ + cur->next[index] = NULL; \ + if (prev) \ + prev->next[index] = type ## _iterator_peek(ctr, iterator); \ + else \ + ctr->bucket[iterator->bucket].head = type ## _iterator_peek(ctr, iterator); \ + ASTOBJ_BUCKET_UNLOCK(ctr, iterator->bucket); \ + objtype ## _unref(&cur); \ + ASTOBJ_STAT_DEC(&(ctr->bucket[iterator->bucket])); \ + break; \ + } \ + prev = cur; \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused astobj_warn_unused_result inline struct objtype *type ## _find(struct type *ctr, const __ ## type ## _indextype compare) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + struct objtype *found = NULL; \ + iterator = type ## _open_bucket_iterator(ctr, __ ## type ## _makehash(compare)); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + if (!comparefunc(cur, cur->indexfield, compare)) { \ + found = objtype ## _ref(cur); \ + break; \ + } \ + } \ + type ## _close_iterator(ctr, &iterator); \ + return found; \ +} \ +static astobj_unused astobj_warn_unused_result inline struct objtype *type ## _find_unlink(struct type *ctr, const __ ## type ## _indextype compare) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + struct objtype *found = NULL; \ + struct objtype *prev = NULL; \ + iterator = type ## _open_bucket_iterator(ctr, __ ## type ## _makehash(compare)); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + if (!comparefunc(cur, cur->indexfield, compare)) { \ + found = cur; \ + ASTOBJ_BUCKET_WRLOCK(ctr, iterator->bucket); \ + found->next[index] = NULL; \ + if (prev) \ + prev->next[index] = type ## _iterator_peek(ctr, iterator); \ + else \ + ctr->bucket[iterator->bucket].head = type ## _iterator_peek(ctr, iterator); \ + ASTOBJ_BUCKET_UNLOCK(ctr, iterator->bucket); \ + ASTOBJ_STAT_DEC(&(ctr->bucket[iterator->bucket])); \ + break; \ + } \ + prev = cur; \ + } \ + type ## _close_iterator(ctr, &iterator); \ + return found; \ +} \ +static astobj_unused inline void type ## _prune_marked(struct type *ctr) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + struct objtype *prev = NULL; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + ASTOBJ_RDLOCK(cur); \ + if (cur->objflags & ASTOBJ_FLAG_MARKED) { \ + ASTOBJ_BUCKET_WRLOCK(ctr, iterator->bucket); \ + if (prev) \ + prev->next[index] = type ## _iterator_peek(ctr, iterator); \ + else \ + ctr->bucket[iterator->bucket].head = type ## _iterator_peek(ctr, iterator); \ + ASTOBJ_BUCKET_UNLOCK(ctr, iterator->bucket); \ + ASTOBJ_UNLOCK(cur); \ + objtype ## _unref(&cur); \ + ASTOBJ_STAT_DEC(&(ctr->bucket[iterator->bucket])); \ + continue; \ + } \ + ASTOBJ_UNLOCK(cur); \ + prev = cur; \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused inline void type ## _mark_all(struct type *ctr) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + objtype ## _mark(cur); \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused inline void type ## _unmark_all(struct type *ctr) \ +{ \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + iterator = type ## _open_iterator(ctr); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + objtype ## _unmark(cur); \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused inline void type ## _dump(struct type *ctr, char *s, int slen, int fd) \ +{ \ + unsigned int i; \ + type ## _iterator *iterator; \ + struct objtype *cur; \ + for (i = 0; i < buckets; i++) { \ + ast_cli(fd, "Bucket: %d\n", i); \ + iterator = type ## _open_bucket_iterator(ctr, i); \ + while ((cur = type ## _iterator_next(ctr, iterator))) { \ + objtype ## _dump(cur, s, slen); \ + ast_cli(fd, s); \ + } \ + } \ + type ## _close_iterator(ctr, &iterator); \ +} \ +static astobj_unused inline void type ## _stats(struct type *ctr, int fd) \ +{ \ + int bucket_max = 0; \ + double scale; \ + unsigned int i; \ + int total = 0; \ + double mean; \ + double deviation = 0; \ + for (i = 0; i < buckets; i++) { \ + int count = ASTOBJ_READ(&(ctr->bucket[i]), count); \ + total += count; \ + if (count > bucket_max) \ + bucket_max = count; \ + } \ + scale = (bucket_max <= 60) ? 1 : ((double) 60 / bucket_max); \ + mean = total / buckets; \ + for (i = 0; i < buckets; i++) { \ + int count = ASTOBJ_READ(&(ctr->bucket[i]), count); \ + deviation += abs(mean - count); \ + ast_cli(fd, "Bucket %4d: %6d\t", i, count); \ + count *= scale; \ + while (count--) \ + ast_cli(fd, "%c", '*'); \ + ast_cli(fd, "\n"); \ + } \ + deviation /= buckets; \ + ast_cli(fd, "Total : %6d Distribution Efficiency: %6.2f%%\n", total, 100 * (1 - (deviation / mean))); \ +} + +#define ASTOBJ_HASH_DEFAULT_BUCKETS 16 + +#define ASTOBJ_HASH_DEFINE(type, objtype, index, fields) \ +ASTOBJ_HASH_DEFINE_FULL(type, objtype, index, name, ast_strhash, ASTOBJ_HASH_DEFAULT_BUCKETS, __ ## type ## _namecmp, fields); \ +static inline int __ ## type ## _namecmp(struct objtype *obj, const char *entry, const char *compare) \ +{ \ + return strcasecmp(entry, compare); \ +} \ #if defined(__cplusplus) || defined(c_plusplus) } diff -Nru a/include/asterisk/atomic.h b/include/asterisk/atomic.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asterisk/atomic.h 2005-01-15 19:06:56 -07:00 @@ -0,0 +1,39 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * Atomic operations for Asterisk + * + * Copyright (C) 2005 Star Networks, LLC. + * Kevin P. Fleming + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#ifndef _ASTERISK_ATOMIC_H +#define _ASTERISK_ATOMIC_H + +#ifdef __linux__ + +/* Note: + The following define causes all the atomic operations from the Linux kernel + atomic.h header to use LOCK prefixes to ensure multiprocessor safety. + + If you know for an abolute fact that your build will _never_ be used on any + type of multiprocessor system (real or virtual), then you can undefine the + following define... but if you do so and then run on an SMP/SMT machine, + it will crash and burn spectacularly. +*/ +#define CONFIG_SMP + +#include +#define AST_HAVE_ATOMIC +#define AST_ATOMIC_T atomic_t +#define AST_ATOMIC_READ(x) atomic_read(&x) +#define AST_ATOMIC_SET(x, val) atomic_set(&x, val) +#define AST_ATOMIC_INC(x) atomic_inc(&x) +#define AST_ATOMIC_DEC(x) atomic_dec(&x) +#define AST_ATOMIC_DEC_AND_TEST_ZERO(x) atomic_dec_and_test(&x) +#endif /* __linux__ */ + +#endif diff -Nru a/include/asterisk/utils.h b/include/asterisk/utils.h --- a/include/asterisk/utils.h 2005-01-15 19:06:56 -07:00 +++ b/include/asterisk/utils.h 2005-01-15 19:06:56 -07:00 @@ -152,4 +152,21 @@ extern char *ast_strcasestr(const char *, const char *); +/* String hashing function + djb2 algorithm + + This algorithm was first reported by Dan Bernstein + many years ago in comp.lang.c +*/ + +static inline unsigned int ast_strhash(const char *string) +{ + unsigned int hash = 5381; + char c; + + while ((c = *string++)) + hash = ((hash << 5) + hash) + c; + return hash; +} + #endif