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
00033
00034
00035
00036
00037
00038 #include "asterisk.h"
00039
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00041
00042 #include <sys/types.h>
00043 #include <sys/socket.h>
00044 #include <fcntl.h>
00045 #include <netdb.h>
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <unistd.h>
00049 #include <string.h>
00050 #include <time.h>
00051 #include <errno.h>
00052 #include <arpa/inet.h>
00053 #include <signal.h>
00054
00055 #include "asterisk/file.h"
00056 #include "asterisk/logger.h"
00057 #include "asterisk/channel.h"
00058 #include "asterisk/config.h"
00059 #include "asterisk/options.h"
00060 #include "asterisk/pbx.h"
00061 #include "asterisk/module.h"
00062 #include "asterisk/cli.h"
00063 #include "asterisk/lock.h"
00064 #define AST_API_MODULE
00065 #include "asterisk/pktccops.h"
00066
00067 #define DEFAULT_COPS_PORT "2126"
00068
00069 #define COPS_HEADER_SIZE 8
00070 #define COPS_OBJECT_HEADER_SIZE 4
00071 #define GATE_SET_OBJ_SIZE 144
00072 #define GATEID_OBJ_SIZE 8
00073 #define GATE_INFO_OBJ_SIZE 24
00074
00075 #define PKTCCOPS_SCOMMAND_GATE_ALLOC 1
00076 #define PKTCCOPS_SCOMMAND_GATE_ALLOC_ACK 2
00077 #define PKTCCOPS_SCOMMAND_GATE_ALLOC_ERR 3
00078 #define PKTCCOPS_SCOMMAND_GATE_SET 4
00079 #define PKTCCOPS_SCOMMAND_GATE_SET_ACK 5
00080 #define PKTCCOPS_SCOMMAND_GATE_SET_ERR 6
00081 #define PKTCCOPS_SCOMMAND_GATE_INFO 7
00082 #define PKTCCOPS_SCOMMAND_GATE_INFO_ACK 8
00083 #define PKTCCOPS_SCOMMAND_GATE_INFO_ERR 9
00084 #define PKTCCOPS_SCOMMAND_GATE_DELETE 10
00085 #define PKTCCOPS_SCOMMAND_GATE_DELETE_ACK 11
00086 #define PKTCCOPS_SCOMMAND_GATE_DELETE_ERR 12
00087 #define PKTCCOPS_SCOMMAND_GATE_OPEN 13
00088 #define PKTCCOPS_SCOMMAND_GATE_CLOSE 14
00089
00090 AST_MUTEX_DEFINE_STATIC(pktccops_lock);
00091 static pthread_t pktccops_thread = AST_PTHREADT_NULL;
00092 static uint16_t cops_trid = 0;
00093
00094 struct pktcobj {
00095 uint16_t length;
00096 unsigned char cnum;
00097 unsigned char ctype;
00098 char *contents;
00099 struct pktcobj *next;
00100 };
00101
00102 struct copsmsg {
00103 unsigned char verflag;
00104 unsigned char opcode;
00105 uint16_t clienttype;
00106 uint32_t length;
00107 struct pktcobj *object;
00108 char *msg;
00109 };
00110
00111 struct gatespec {
00112 int direction;
00113 int protocolid;
00114 int flags;
00115 int sessionclass;
00116 uint32_t srcip;
00117 uint32_t dstip;
00118 uint16_t srcp;
00119 uint16_t dstp;
00120 int diffserv;
00121 uint16_t t1;
00122 uint16_t t7;
00123 uint16_t t8;
00124 uint32_t r;
00125 uint32_t b;
00126 uint32_t p;
00127 uint32_t m;
00128 uint32_t mm;
00129 uint32_t rate;
00130 uint32_t s;
00131 };
00132
00133
00134 struct cops_cmts {
00135 AST_LIST_ENTRY(cops_cmts) list;
00136 char name[80];
00137 char host[80];
00138 char port[80];
00139 uint16_t t1;
00140 uint16_t t7;
00141 uint16_t t8;
00142 uint32_t keepalive;
00143
00144 uint32_t handle;
00145 int state;
00146 time_t contime;
00147 time_t katimer;
00148 int sfd;
00149 int need_delete;
00150 };
00151
00152 struct cops_ippool {
00153 AST_LIST_ENTRY(cops_ippool) list;
00154 uint32_t start;
00155 uint32_t stop;
00156 struct cops_cmts *cmts;
00157 };
00158
00159 static uint16_t t1 = 250;
00160 static uint16_t t7 = 200;
00161 static uint16_t t8 = 300;
00162 static uint32_t keepalive = 60;
00163 static int pktccopsdebug = 0;
00164 static int pktcreload = 0;
00165 static int gateinfoperiod = 60;
00166 static int gatetimeout = 150;
00167
00168 AST_LIST_HEAD_STATIC(cmts_list, cops_cmts);
00169 AST_LIST_HEAD_STATIC(ippool_list, cops_ippool);
00170 AST_LIST_HEAD_STATIC(gate_list, cops_gate);
00171
00172 static int pktccops_add_ippool(struct cops_ippool *ippool);
00173 static struct cops_gate *cops_gate_cmd(int cmd, struct cops_cmts *cmts, uint16_t trid, uint32_t mta, uint32_t actcount, float bitrate, uint32_t psize, uint32_t ssip, uint16_t ssport, struct cops_gate *gate);
00174 static void pktccops_unregister_ippools(void);
00175 static int load_pktccops_config(void);
00176
00177 static uint32_t ftoieeef(float n)
00178 {
00179 uint32_t res;
00180 memcpy(&res, &n, 4);
00181 return htonl(res);
00182 }
00183
00184 static uint16_t cops_constructgatespec(struct gatespec *gs, char *res)
00185 {
00186 if (res == NULL) {
00187 return 0;
00188 }
00189
00190 *res = (char) gs->direction;
00191 *(res + 1) = (char) gs->protocolid;
00192 *(res + 2) = (char) gs->flags;
00193 *(res + 3) = (char) gs->sessionclass;
00194
00195 *((uint32_t *) (res + 4)) = gs->srcip;
00196 *((uint32_t *) (res + 8)) = gs->dstip;
00197
00198 *((uint16_t *) (res + 12)) = gs->srcp;
00199 *((uint16_t *) (res + 14)) = gs->dstp;
00200
00201 *(res + 16) = (char) gs->diffserv;
00202 *(res + 17) = 0;
00203 *(res + 18) = 0;
00204 *(res + 19) = 0;
00205
00206 *((uint16_t *) (res + 20)) = gs->t1;
00207 *(res + 22) = 0;
00208 *(res + 23) = 0;
00209
00210 *((uint16_t *) (res + 24)) = gs->t7;
00211 *((uint16_t *) (res + 26)) = gs->t8;
00212
00213 *((uint32_t *) (res + 28)) = gs->r;
00214 *((uint32_t *) (res + 32)) = gs->b;
00215 *((uint32_t *) (res + 36)) = gs->p;
00216 *((uint32_t *) (res + 40)) = gs->m;
00217 *((uint32_t *) (res + 44)) = gs->mm;
00218 *((uint32_t *) (res + 48)) = gs->rate;
00219 *((uint32_t *) (res + 52)) = gs->s;
00220 return 56;
00221 };
00222
00223 static uint16_t cops_construct_gate (int cmd, char *p, uint16_t trid,
00224 uint32_t mtahost, uint32_t actcount, float rate, uint32_t psizegateid,
00225 uint32_t ssip, uint16_t ssport, uint32_t gateid, struct cops_cmts *cmts)
00226 {
00227 struct gatespec gs;
00228 int offset = 0;
00229
00230 ast_debug(3, "CMD: %d\n", cmd);
00231
00232
00233 *(p + offset++) = 0;
00234 *(p + offset++) = 8;
00235 *(p + offset++) = 1;
00236 *(p + offset++) = 1;
00237 *((uint16_t *) (p + offset)) = htons(trid);
00238 offset += 2;
00239 *(p + offset++) = 0;
00240 *(p + offset++) = (cmd == GATE_DEL) ? PKTCCOPS_SCOMMAND_GATE_DELETE : (cmd != GATE_INFO) ? PKTCCOPS_SCOMMAND_GATE_SET : PKTCCOPS_SCOMMAND_GATE_INFO;
00241
00242
00243 *(p + offset++) = 0;
00244 *(p + offset++) = 8;
00245 *(p + offset++) = 2;
00246 *(p + offset++) = 1;
00247 *((uint32_t *) (p + offset)) = htonl(mtahost);
00248 offset += 4;
00249
00250 if (cmd == GATE_INFO || cmd == GATE_SET_HAVE_GATEID || cmd == GATE_DEL) {
00251
00252 *(p + offset++) = 0;
00253 *(p + offset++) = 8;
00254 *(p + offset++) = 3;
00255 *(p + offset++) = 1;
00256 *((uint32_t *) (p + offset)) = htonl(gateid);
00257 offset += 4;
00258 if (cmd == GATE_INFO || cmd == GATE_DEL) {
00259 return offset;
00260 }
00261
00262 }
00263
00264
00265 *(p + offset++) = 0;
00266 *(p + offset++) = 8;
00267 *(p + offset++) = 4;
00268 *(p + offset++) = 1;
00269 *((uint32_t *) (p + offset)) = htonl(actcount);
00270 offset += 4;
00271
00272
00273
00274 gs.direction = 0;
00275 gs.protocolid = 17;
00276 gs.flags = 0;
00277 gs.sessionclass = 1;
00278 gs.srcip = htonl(ssip);
00279 gs.dstip = htonl(mtahost);
00280 gs.srcp = htons(ssport);
00281 gs.dstp = 0;
00282
00283 gs.diffserv = 0;
00284 gs.t1 = htons(cmts->t1);
00285 gs.t7 = htons(cmts->t7);
00286 gs.t8 = htons(cmts->t8);
00287 gs.r = ftoieeef(rate);
00288 gs.b = ftoieeef(psizegateid);
00289 gs.p = ftoieeef(rate);
00290 gs.m = htonl((uint32_t) psizegateid);
00291 gs.mm = htonl((uint32_t) psizegateid);
00292 gs.rate = ftoieeef(rate);
00293 gs.s = htonl(800);
00294
00295
00296 *(p + offset) = 0;
00297 offset++;
00298 *(p + offset) = 60;
00299 offset++;
00300 *(p + offset) = 5;
00301 offset++;
00302 *(p + offset) = 1;
00303 offset++;
00304 offset += cops_constructgatespec(&gs, p + offset);
00305
00306
00307 gs.direction = 1;
00308 gs.srcip = htonl(mtahost);
00309 gs.dstip = htonl(ssip);
00310 gs.srcp = 0;
00311 gs.dstp = htons(ssport);
00312 *(p + offset) = 0;
00313 offset++;
00314 *(p + offset) = 60;
00315 offset++;
00316 *(p + offset) = 5;
00317 offset++;
00318 *(p + offset) = 1;
00319 offset++;
00320 offset += cops_constructgatespec(&gs, p + offset);
00321
00322 return(offset);
00323 }
00324
00325 static int cops_getmsg (int sfd, struct copsmsg *recmsg)
00326 {
00327 int len, lent;
00328 char buf[COPS_HEADER_SIZE];
00329 struct pktcobj *pobject = NULL;
00330 uint16_t *ubuf = (uint16_t *) buf;
00331 recmsg->msg = NULL;
00332 recmsg->object = NULL;
00333 len = recv(sfd, buf, COPS_HEADER_SIZE, MSG_DONTWAIT);
00334 if (len < COPS_HEADER_SIZE) {
00335 return len;
00336 }
00337 recmsg->verflag = *buf;
00338 recmsg->opcode = *(buf + 1);
00339 recmsg->clienttype = ntohs(*((uint16_t *) (buf + 2)));
00340 recmsg->length = ntohl(*((uint32_t *) (buf + 4)));
00341
00342 if (recmsg->clienttype != 0x8008 ) {
00343 if (!(recmsg->msg = malloc(recmsg->length - COPS_HEADER_SIZE))) {
00344 return -1;
00345 }
00346 lent = recv(sfd, recmsg->msg, recmsg->length - COPS_HEADER_SIZE, MSG_DONTWAIT);
00347 if (lent < recmsg->length - COPS_HEADER_SIZE) {
00348 return lent;
00349 }
00350 len += len;
00351 } else {
00352
00353 while (len < recmsg->length) {
00354 if (len == COPS_HEADER_SIZE) {
00355
00356 if (!(recmsg->object = malloc(sizeof(struct pktcobj)))) {
00357 return -1;
00358 }
00359 pobject = recmsg->object;
00360 } else {
00361 if (!(pobject->next = malloc(sizeof(struct pktcobj)))) {
00362 return -1;
00363 }
00364 pobject = pobject->next;
00365 }
00366 pobject->next = NULL;
00367 lent = recv(sfd, buf, COPS_OBJECT_HEADER_SIZE, MSG_DONTWAIT);
00368 if (lent < COPS_OBJECT_HEADER_SIZE) {
00369 ast_debug(3, "Too short object header len: %i\n", lent);
00370 return lent;
00371 }
00372 len += lent;
00373 pobject->length = ntohs(*ubuf);
00374 pobject->cnum = *(buf + 2);
00375 pobject->ctype = *(buf + 3);
00376 if (!(pobject->contents = malloc(pobject->length - COPS_OBJECT_HEADER_SIZE))) {
00377 return -1;
00378 }
00379 lent = recv(sfd, pobject->contents, pobject->length - COPS_OBJECT_HEADER_SIZE, MSG_DONTWAIT);
00380 if (lent < pobject->length - COPS_OBJECT_HEADER_SIZE) {
00381 ast_debug(3, "Too short object content len: %i\n", lent);
00382 return lent;
00383 }
00384 len += lent;
00385 }
00386 }
00387 return len;
00388 }
00389
00390 static int cops_sendmsg (int sfd, struct copsmsg * sendmsg)
00391 {
00392 char *buf;
00393 int bufpos;
00394 struct pktcobj *pobject;
00395
00396 if (sfd < 0) {
00397 return -1;
00398 }
00399
00400 ast_debug(3, "COPS: sending opcode: %i len: %i\n", sendmsg->opcode, sendmsg->length);
00401 if (sendmsg->length < COPS_HEADER_SIZE) {
00402 ast_log(LOG_WARNING, "COPS: invalid msg size!!!\n");
00403 return -1;
00404 }
00405 if (!(buf = malloc((size_t) sendmsg->length))) {
00406 return -1;
00407 }
00408 *buf = sendmsg->verflag ;
00409 *(buf + 1) = sendmsg->opcode;
00410 *((uint16_t *)(buf + 2)) = htons(sendmsg->clienttype);
00411 *((uint32_t *)(buf + 4)) = htonl(sendmsg->length);
00412
00413 if (sendmsg->msg != NULL) {
00414 memcpy(buf + COPS_HEADER_SIZE, sendmsg->msg, sendmsg->length - COPS_HEADER_SIZE);
00415 } else if (sendmsg->object != NULL) {
00416 bufpos = 8;
00417 pobject = sendmsg->object;
00418 while(pobject != NULL) {
00419 ast_debug(3, "COPS: Sending Object : cnum: %i ctype %i len: %i\n", pobject->cnum, pobject->ctype, pobject->length);
00420 if (sendmsg->length < bufpos + pobject->length) {
00421 ast_log(LOG_WARNING, "COPS: Invalid msg size len: %i objectlen: %i\n", sendmsg->length, pobject->length);
00422 free(buf);
00423 return -1;
00424 }
00425 *(uint16_t *) (buf + bufpos) = htons(pobject->length);
00426 *(buf + bufpos + 2) = pobject->cnum;
00427 *(buf + bufpos + 3) = pobject->ctype;
00428 if (sendmsg->length < pobject->length + bufpos) {
00429 ast_log(LOG_WARNING, "COPS: Error sum of object len more the msg len %i < %i\n", sendmsg->length, pobject->length + bufpos);
00430 free(buf);
00431 return -1;
00432 }
00433 memcpy((buf + bufpos + 4), pobject->contents, pobject->length - 4);
00434 bufpos += pobject->length;
00435 pobject = pobject->next;
00436 }
00437 }
00438
00439 errno = 0;
00440 #ifdef HAVE_MSG_NOSIGNAL
00441 #define SENDFLAGS MSG_NOSIGNAL | MSG_DONTWAIT
00442 #else
00443 #define SENDFLAGS MSG_DONTWAIT
00444 #endif
00445 if (send(sfd, buf, sendmsg->length, SENDFLAGS) == -1) {
00446 ast_log(LOG_WARNING, "COPS: Send failed errno=%i\n", errno);
00447 free(buf);
00448 return -2;
00449 }
00450 #undef SENDFLAGS
00451 free(buf);
00452 return 0;
00453 }
00454
00455 static void cops_freemsg(struct copsmsg *p)
00456 {
00457 struct pktcobj *pnext;
00458 free(p->msg);
00459 p->msg = NULL;
00460 while (p->object != NULL) {
00461 pnext = p->object->next;
00462 ast_free(p->object->contents);
00463 p->object->contents = NULL;
00464 ast_free(p->object);
00465 p->object = pnext;
00466 }
00467 p->object = NULL;
00468 }
00469
00470 struct cops_gate * AST_OPTIONAL_API_NAME(ast_pktccops_gate_alloc)(int cmd,
00471 struct cops_gate *gate, uint32_t mta, uint32_t actcount, float bitrate,
00472 uint32_t psize, uint32_t ssip, uint16_t ssport,
00473 int (* const got_dq_gi) (struct cops_gate *gate),
00474 int (* const gate_remove) (struct cops_gate *gate))
00475 {
00476 while (pktcreload) {
00477 sched_yield();
00478 }
00479
00480 if (cmd == GATE_SET_HAVE_GATEID && gate) {
00481 ast_debug(3, "------- gate modify gateid 0x%x ssip: 0x%x\n", gate->gateid, ssip);
00482
00483 ast_log(LOG_WARNING, "Modify GateID not implemented\n");
00484 }
00485
00486 if ((gate = cops_gate_cmd(cmd, NULL, cops_trid++, mta, actcount, bitrate, psize, ssip, ssport, gate))) {
00487 ast_debug(3, "COPS: Allocating gate for mta: 0x%x\n", mta);
00488 gate->got_dq_gi = got_dq_gi;
00489 gate->gate_remove = gate_remove;
00490 return(gate);
00491 } else {
00492 ast_debug(3, "COPS: Couldn't allocate gate for mta: 0x%x\n", mta);
00493 return NULL;
00494 }
00495 }
00496
00497 static struct cops_gate *cops_gate_cmd(int cmd, struct cops_cmts *cmts,
00498 uint16_t trid, uint32_t mta, uint32_t actcount, float bitrate,
00499 uint32_t psize, uint32_t ssip, uint16_t ssport, struct cops_gate *gate)
00500 {
00501 struct copsmsg *gateset;
00502 struct cops_gate *new;
00503 struct cops_ippool *ippool;
00504
00505 if (cmd == GATE_DEL) {
00506 if (gate == NULL) {
00507 return NULL;
00508 } else {
00509 cmts = gate->cmts;
00510 }
00511 }
00512
00513 if (!cmts) {
00514 AST_LIST_LOCK(&ippool_list);
00515 AST_LIST_TRAVERSE(&ippool_list, ippool, list) {
00516 if (mta >= ippool->start && mta <= ippool->stop) {
00517 cmts = ippool->cmts;
00518 break;
00519 }
00520 }
00521 AST_LIST_UNLOCK(&ippool_list);
00522 if (!cmts) {
00523 ast_log(LOG_WARNING, "COPS: couldn't find cmts for mta: 0x%x\n", mta);
00524 return NULL;
00525 }
00526 if (cmts->sfd < 0) {
00527 ast_log(LOG_WARNING, "CMTS: %s not connected\n", cmts->name);
00528 return NULL;
00529 }
00530 }
00531
00532 if (cmd == GATE_SET) {
00533 new = ast_calloc(1, sizeof(*new));
00534 new->gateid = 0;
00535 new->trid = trid;
00536 new->mta = mta;
00537 new->state = GATE_ALLOC_PROGRESS;
00538 new->checked = time(NULL);
00539 new->allocated = time(NULL);
00540 new->cmts = cmts;
00541 new->got_dq_gi = NULL;
00542 new->gate_remove = NULL;
00543 new->gate_open = NULL;
00544 new->tech_pvt = NULL;
00545 new->deltimer = 0;
00546 AST_LIST_LOCK(&gate_list);
00547 AST_LIST_INSERT_HEAD(&gate_list, new, list);
00548 AST_LIST_UNLOCK(&gate_list);
00549 gate = new;
00550 } else {
00551 if (gate) {
00552 gate->trid = trid;
00553 }
00554 }
00555
00556 gate->in_transaction = time(NULL);
00557
00558 if (!(gateset = malloc(sizeof(struct copsmsg)))) {
00559 free(gateset);
00560 return NULL;
00561 }
00562 gateset->msg = NULL;
00563 gateset->verflag = 0x10;
00564 gateset->opcode = 2;
00565 gateset->clienttype = 0x8008;
00566
00567
00568 gateset->object = malloc(sizeof(struct pktcobj));
00569 if (!gateset->object) {
00570 cops_freemsg(gateset);
00571 free(gateset);
00572 return NULL;
00573 }
00574 gateset->object->length = COPS_OBJECT_HEADER_SIZE + 4;
00575 gateset->object->cnum = 1;
00576 gateset->object->ctype = 1;
00577 if (!(gateset->object->contents = malloc(sizeof(uint32_t)))) {
00578 cops_freemsg(gateset);
00579 free(gateset);
00580 return NULL;
00581 }
00582 *((uint32_t *) gateset->object->contents) = htonl(cmts->handle);
00583
00584
00585 if (!(gateset->object->next = malloc(sizeof(struct pktcobj)))) {
00586 cops_freemsg(gateset);
00587 free(gateset);
00588 return NULL;
00589 }
00590 gateset->object->next->length = COPS_OBJECT_HEADER_SIZE + 4;
00591 gateset->object->next->cnum = 2;
00592 gateset->object->next->ctype = 1;
00593 if (!(gateset->object->next->contents = malloc(sizeof(uint32_t)))) {
00594 cops_freemsg(gateset);
00595 free(gateset);
00596 return NULL;
00597 }
00598 *((uint32_t *) gateset->object->next->contents) = htonl(0x00080000);
00599
00600
00601 if (!(gateset->object->next->next = malloc(sizeof(struct pktcobj)))) {
00602 cops_freemsg(gateset);
00603 free(gateset);
00604 return NULL;
00605 }
00606 gateset->object->next->next->length = COPS_OBJECT_HEADER_SIZE + 4;
00607 gateset->object->next->next->cnum = 6;
00608 gateset->object->next->next->ctype = 1;
00609 if (!(gateset->object->next->next->contents = malloc(sizeof(uint32_t)))) {
00610 cops_freemsg(gateset);
00611 free(gateset);
00612 return NULL;
00613 }
00614 *((uint32_t *) gateset->object->next->next->contents) = htonl(0x00010001);
00615
00616
00617 if (!(gateset->object->next->next->next = malloc(sizeof(struct pktcobj)))) {
00618 cops_freemsg(gateset);
00619 free(gateset);
00620 return NULL;
00621 }
00622 gateset->object->next->next->next->length = COPS_OBJECT_HEADER_SIZE + ((cmd != GATE_INFO && cmd != GATE_DEL) ? GATE_SET_OBJ_SIZE : GATE_INFO_OBJ_SIZE) + ((cmd == GATE_SET_HAVE_GATEID) ? GATEID_OBJ_SIZE : 0);
00623 gateset->object->next->next->next->cnum = 6;
00624 gateset->object->next->next->next->ctype = 4;
00625 gateset->object->next->next->next->contents = malloc(((cmd != GATE_INFO && cmd != GATE_DEL) ? GATE_SET_OBJ_SIZE : GATE_INFO_OBJ_SIZE) + ((cmd == GATE_SET_HAVE_GATEID) ? GATEID_OBJ_SIZE : 0));
00626 if (!gateset->object->next->next->next->contents) {
00627 cops_freemsg(gateset);
00628 free(gateset);
00629 return NULL;
00630 }
00631 gateset->object->next->next->next->next = NULL;
00632
00633 gateset->length = COPS_HEADER_SIZE + gateset->object->length + gateset->object->next->length + gateset->object->next->next->length + gateset->object->next->next->next->length;
00634
00635 if ((cmd == GATE_INFO || cmd == GATE_SET_HAVE_GATEID || cmd == GATE_DEL) && gate) {
00636 ast_debug(1, "Construct gate with gateid: 0x%x\n", gate->gateid);
00637 cops_construct_gate(cmd, gateset->object->next->next->next->contents, trid, mta, actcount, bitrate, psize, ssip, ssport, gate->gateid, cmts);
00638 } else {
00639 ast_debug(1, "Construct new gate\n");
00640 cops_construct_gate(cmd, gateset->object->next->next->next->contents, trid, mta, actcount, bitrate, psize, ssip, ssport, 0, cmts);
00641 }
00642 if (pktccopsdebug) {
00643 ast_debug(3, "send cmd\n");
00644 }
00645 cops_sendmsg(cmts->sfd, gateset);
00646 cops_freemsg(gateset);
00647 free(gateset);
00648 return gate;
00649 }
00650
00651 static int cops_connect(char *host, char *port)
00652 {
00653 int s, sfd = -1, flags;
00654 struct addrinfo hints;
00655 struct addrinfo *rp;
00656 struct addrinfo *result;
00657 #ifdef HAVE_SO_NOSIGPIPE
00658 int trueval = 1;
00659 #endif
00660
00661 memset(&hints, 0, sizeof(struct addrinfo));
00662
00663 hints.ai_family = AF_UNSPEC;
00664 hints.ai_socktype = SOCK_STREAM;
00665 hints.ai_flags = 0;
00666 hints.ai_protocol = 0;
00667
00668 s = getaddrinfo(host, port, &hints, &result);
00669 if (s != 0) {
00670 ast_log(LOG_WARNING, "COPS: getaddrinfo: %s\n", gai_strerror(s));
00671 return -1;
00672 }
00673
00674 for (rp = result; rp != NULL; rp = rp->ai_next) {
00675 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
00676 if (sfd == -1) {
00677 ast_log(LOG_WARNING, "Failed socket\n");
00678 }
00679 flags = fcntl(sfd, F_GETFL);
00680 fcntl(sfd, F_SETFL, flags | O_NONBLOCK);
00681 #ifdef HAVE_SO_NOSIGPIPE
00682 setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, &trueval, sizeof(trueval));
00683 #endif
00684 connect(sfd, rp->ai_addr, rp->ai_addrlen);
00685 if (sfd == -1) {
00686 ast_log(LOG_WARNING, "Failed connect\n");
00687 }
00688 }
00689 freeaddrinfo(result);
00690
00691 ast_debug(3, "Connecting to cmts: %s:%s\n", host, port);
00692 return(sfd);
00693 }
00694
00695 #define PKTCCOPS_DESTROY_CURRENT_GATE \
00696 AST_LIST_REMOVE_CURRENT(list); \
00697 if (gate->gate_remove) { \
00698 gate->gate_remove(gate); \
00699 } \
00700 ast_free(gate);
00701
00702 static void *do_pktccops(void *data)
00703 {
00704 int res, nfds, len;
00705 struct copsmsg *recmsg, *sendmsg;
00706 struct copsmsg recmsgb, sendmsgb;
00707 struct pollfd *pfds = NULL, *tmp;
00708 struct pktcobj *pobject;
00709 struct cops_cmts *cmts;
00710 struct cops_gate *gate;
00711 char *sobjp;
00712 uint16_t snst, sobjlen, scommand, recvtrid, actcount, reason, subreason;
00713 uint32_t gateid, subscrid, pktcerror;
00714 time_t last_exec = 0;
00715
00716 recmsg = &recmsgb;
00717 sendmsg = &sendmsgb;
00718
00719 ast_debug(3, "COPS: thread started\n");
00720
00721 for (;;) {
00722 ast_free(pfds);
00723 pfds = NULL;
00724 nfds = 0;
00725 AST_LIST_LOCK(&cmts_list);
00726 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
00727 if (last_exec != time(NULL)) {
00728 if (cmts->state == 2 && cmts->katimer + cmts->keepalive < time(NULL)) {
00729 ast_log(LOG_WARNING, "KA timer (%is) expired cmts: %s\n", cmts->keepalive, cmts->name);
00730 cmts->state = 0;
00731 cmts->katimer = -1;
00732 close(cmts->sfd);
00733 cmts->sfd = -1;
00734 }
00735 }
00736 if (cmts->sfd > 0) {
00737 if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
00738 continue;
00739 }
00740 pfds = tmp;
00741 pfds[nfds].fd = cmts->sfd;
00742 pfds[nfds].events = POLLIN;
00743 pfds[nfds].revents = 0;
00744 nfds++;
00745 } else {
00746 cmts->sfd = cops_connect(cmts->host, cmts->port);
00747 if (cmts->sfd > 0) {
00748 cmts->state = 1;
00749 if (cmts->sfd > 0) {
00750 if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
00751 continue;
00752 }
00753 pfds = tmp;
00754 pfds[nfds].fd = cmts->sfd;
00755 pfds[nfds].events = POLLIN;
00756 pfds[nfds].revents = 0;
00757 nfds++;
00758 }
00759 }
00760 }
00761 }
00762 AST_LIST_UNLOCK(&cmts_list);
00763
00764 if (last_exec != time(NULL)) {
00765 last_exec = time(NULL);
00766 AST_LIST_LOCK(&gate_list);
00767 AST_LIST_TRAVERSE_SAFE_BEGIN(&gate_list, gate, list) {
00768 if (gate) {
00769 if (gate->deltimer && gate->deltimer < time(NULL)) {
00770 gate->deltimer = time(NULL) + 5;
00771 gate->trid = cops_trid++;
00772 cops_gate_cmd(GATE_DEL, gate->cmts, gate->trid, 0, 0, 0, 0, 0, 0, gate);
00773 ast_debug(3, "COPS: requested Gate-Del: CMTS: %s gateid: 0x%x\n", (gate->cmts) ? gate->cmts->name : "null", gate->gateid);
00774 }
00775 if (time(NULL) - gate->checked > gatetimeout) {
00776 ast_debug(3, "COPS: remove from list GATE, CMTS: %s gateid: 0x%x\n", (gate->cmts) ? gate->cmts->name : "null", gate->gateid);
00777 gate->state = GATE_TIMEOUT;
00778 PKTCCOPS_DESTROY_CURRENT_GATE;
00779 } else if (time(NULL) - gate->checked > gateinfoperiod && (gate->state == GATE_ALLOCATED || gate->state == GATE_OPEN)) {
00780 if (gate->cmts && (!gate->in_transaction || ( gate->in_transaction + 5 ) < time(NULL))) {
00781 gate->trid = cops_trid++;
00782 ast_debug(3, "COPS: Gate-Info send to CMTS: %s gateid: 0x%x\n", gate->cmts->name, gate->gateid);
00783 cops_gate_cmd(GATE_INFO, gate->cmts, gate->trid, gate->mta, 0, 0, 0, 0, 0, gate);
00784 }
00785 }
00786 }
00787 }
00788 AST_LIST_TRAVERSE_SAFE_END;
00789 AST_LIST_UNLOCK(&gate_list);
00790 }
00791
00792 if (pktcreload == 2) {
00793 pktcreload = 0;
00794 }
00795 if ((res = ast_poll(pfds, nfds, 1000))) {
00796 AST_LIST_LOCK(&cmts_list);
00797 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
00798 int idx;
00799 if ((idx = ast_poll_fd_index(pfds, nfds, cmts->sfd)) > -1 && (pfds[idx].revents & POLLIN)) {
00800 len = cops_getmsg(cmts->sfd, recmsg);
00801 if (len > 0) {
00802 ast_debug(3, "COPS: got from %s:\n Header: versflag=0x%.2x opcode=%i clienttype=0x%.4x msglength=%i\n",
00803 cmts->name, recmsg->verflag, recmsg->opcode, recmsg->clienttype, recmsg->length);
00804 if (recmsg->object != NULL) {
00805 pobject = recmsg->object;
00806 while (pobject != NULL) {
00807 ast_debug(3, " OBJECT: length=%i cnum=%i ctype=%i\n", pobject->length, pobject->cnum, pobject->ctype);
00808 if (recmsg->opcode == 1 && pobject->cnum == 1 && pobject->ctype == 1 ) {
00809 cmts->handle = ntohl(*((uint32_t *) pobject->contents));
00810 ast_debug(3, " REQ client handle: %i\n", cmts->handle);
00811 cmts->state = 2;
00812 cmts->katimer = time(NULL);
00813 } else if (pobject->cnum == 9 && pobject->ctype == 1) {
00814 sobjp = pobject->contents;
00815 subscrid = 0;
00816 recvtrid = 0;
00817 scommand = 0;
00818 pktcerror = 0;
00819 actcount = 0;
00820 gateid = 0;
00821 reason = 0;
00822 subreason = 0;
00823 while (sobjp < (pobject->contents + pobject->length - 4)) {
00824 sobjlen = ntohs(*((uint16_t *) sobjp));
00825 snst = ntohs(*((uint16_t *) (sobjp + 2)));
00826 ast_debug(3, " S-Num S-type: 0x%.4x len: %i\n", snst, sobjlen);
00827 if (snst == 0x0101 ) {
00828 recvtrid = ntohs(*((uint16_t *) (sobjp + 4)));
00829 scommand = ntohs(*((uint16_t *) (sobjp + 6)));
00830 ast_debug(3, " Transaction Identifier command: %i trid %i\n", scommand, recvtrid);
00831 } else if (snst == 0x0201) {
00832 subscrid = ntohl(*((uint32_t *) (sobjp + 4)));
00833 ast_debug(3, " Subscriber ID: 0x%.8x\n", subscrid);
00834 } else if (snst == 0x0301) {
00835 gateid = ntohl(*((uint32_t *) (sobjp + 4)));
00836 ast_debug(3, " Gate ID: 0x%x 0x%.8x\n", gateid, gateid);
00837 } else if (snst == 0x0401) {
00838 actcount = ntohs(*((uint16_t *) (sobjp + 6)));
00839 ast_debug(3, " Activity Count: %i\n", actcount);
00840 } else if (snst == 0x0901) {
00841 pktcerror = ntohl(*((uint32_t *) (sobjp + 4)));
00842 ast_debug(3, " PKTC Error: 0x%.8x\n", pktcerror);
00843 } else if (snst == 0x0d01) {
00844 reason = ntohs(*((uint16_t *) (sobjp + 4)));
00845 subreason = ntohs(*((uint16_t *) (sobjp + 6)));
00846 ast_debug(3, " Reason: %u Subreason: %u\n", reason, subreason);
00847 }
00848 sobjp += sobjlen;
00849 if (!sobjlen)
00850 break;
00851 }
00852 if (scommand == PKTCCOPS_SCOMMAND_GATE_CLOSE || scommand == PKTCCOPS_SCOMMAND_GATE_OPEN) {
00853 AST_LIST_LOCK(&gate_list);
00854 AST_LIST_TRAVERSE_SAFE_BEGIN(&gate_list, gate, list) {
00855 if (gate->cmts == cmts && gate->gateid == gateid) {
00856 if (scommand == PKTCCOPS_SCOMMAND_GATE_CLOSE && gate->state != GATE_CLOSED && gate->state != GATE_CLOSED_ERR ) {
00857 ast_debug(3, "COPS Gate Close Gate ID: 0x%x TrId: %i CMTS: %s\n", gateid, recvtrid, cmts->name);
00858 if (subreason) {
00859 gate->state = GATE_CLOSED_ERR;
00860 PKTCCOPS_DESTROY_CURRENT_GATE;
00861 } else {
00862 gate->state = GATE_CLOSED;
00863 PKTCCOPS_DESTROY_CURRENT_GATE;
00864 }
00865 break;
00866 } else if (scommand == PKTCCOPS_SCOMMAND_GATE_OPEN && gate->state == GATE_ALLOCATED) {
00867 ast_debug(3, "COPS Gate Open Gate ID: 0x%x TrId: %i CMTS: %s\n", gateid, recvtrid, cmts->name);
00868 gate->state = GATE_OPEN;
00869 if (gate->gate_open) {
00870 ast_debug(3, "Calling GATE-OPEN callback function\n");
00871 gate->gate_open(gate);
00872 gate->gate_open = NULL;
00873 }
00874 break;
00875 }
00876 }
00877 }
00878 AST_LIST_TRAVERSE_SAFE_END;
00879 AST_LIST_UNLOCK(&gate_list);
00880 } else if (scommand == PKTCCOPS_SCOMMAND_GATE_SET_ACK || scommand == PKTCCOPS_SCOMMAND_GATE_SET_ERR || scommand == PKTCCOPS_SCOMMAND_GATE_INFO_ACK || scommand == PKTCCOPS_SCOMMAND_GATE_INFO_ERR || scommand == PKTCCOPS_SCOMMAND_GATE_DELETE_ACK) {
00881 AST_LIST_LOCK(&gate_list);
00882 AST_LIST_TRAVERSE_SAFE_BEGIN(&gate_list, gate, list) {
00883 if (gate->cmts == cmts && gate->trid == recvtrid) {
00884 gate->gateid = gateid;
00885 gate->checked = time(NULL);
00886 if (scommand == PKTCCOPS_SCOMMAND_GATE_SET_ACK) {
00887 ast_debug(3, "COPS Gate Set Ack Gate ID: 0x%x TrId: %i CMTS: %s\n", gateid, recvtrid, cmts->name);
00888 gate->state = GATE_ALLOCATED;
00889 if (gate->got_dq_gi) {
00890 gate->got_dq_gi(gate);
00891 gate->got_dq_gi = NULL;
00892 }
00893 } else if (scommand == PKTCCOPS_SCOMMAND_GATE_SET_ERR) {
00894 ast_debug(3, "COPS Gate Set Error TrId: %i ErrorCode: 0x%.8x CMTS: %s\n ", recvtrid, pktcerror, cmts->name);
00895 gate->state = GATE_ALLOC_FAILED;
00896 if (gate->got_dq_gi) {
00897 gate->got_dq_gi(gate);
00898 gate->got_dq_gi = NULL;
00899 }
00900 PKTCCOPS_DESTROY_CURRENT_GATE;
00901 } else if (scommand == PKTCCOPS_SCOMMAND_GATE_INFO_ACK) {
00902 ast_debug(3, "COPS Gate Info Ack Gate ID: 0x%x TrId: %i CMTS: %s\n", gateid, recvtrid, cmts->name);
00903 } else if (scommand == PKTCCOPS_SCOMMAND_GATE_INFO_ERR) {
00904 ast_debug(3, "COPS Gate Info Error Gate ID: 0x%x TrId: %i CMTS: %s\n", gateid, recvtrid, cmts->name);
00905 gate->state = GATE_ALLOC_FAILED;
00906 PKTCCOPS_DESTROY_CURRENT_GATE;
00907 } else if (scommand == PKTCCOPS_SCOMMAND_GATE_DELETE_ACK) {
00908 ast_debug(3, "COPS Gate Deleted Gate ID: 0x%x TrId: %i CMTS: %s\n", gateid, recvtrid, cmts->name);
00909 gate->state = GATE_DELETED;
00910 PKTCCOPS_DESTROY_CURRENT_GATE;
00911 }
00912 gate->in_transaction = 0;
00913 break;
00914 }
00915 }
00916 AST_LIST_TRAVERSE_SAFE_END;
00917 AST_LIST_UNLOCK(&gate_list);
00918 }
00919 }
00920 pobject = pobject->next;
00921 }
00922 }
00923
00924 if (recmsg->opcode == 6 && recmsg->object && recmsg->object->cnum == 11 && recmsg->object->ctype == 1) {
00925 ast_debug(3, "COPS: Client open %s\n", cmts->name);
00926 sendmsg->msg = NULL;
00927 sendmsg->verflag = 0x10;
00928 sendmsg->opcode = 7;
00929 sendmsg->clienttype = 0x8008;
00930 sendmsg->length = COPS_HEADER_SIZE + COPS_OBJECT_HEADER_SIZE + 4;
00931 sendmsg->object = malloc(sizeof(struct pktcobj));
00932 sendmsg->object->length = 4 + COPS_OBJECT_HEADER_SIZE;
00933 sendmsg->object->cnum = 10;
00934 sendmsg->object->ctype = 1;
00935 sendmsg->object->contents = malloc(sizeof(uint32_t));
00936 *((uint32_t *) sendmsg->object->contents) = htonl(cmts->keepalive & 0x0000ffff);
00937 sendmsg->object->next = NULL;
00938 cops_sendmsg(cmts->sfd, sendmsg);
00939 cops_freemsg(sendmsg);
00940 } else if (recmsg->opcode == 9) {
00941 ast_debug(3, "COPS: Keepalive Request got echoing back %s\n", cmts->name);
00942 cops_sendmsg(cmts->sfd, recmsg);
00943 cmts->state = 2;
00944 cmts->katimer = time(NULL);
00945 }
00946 }
00947 if (len <= 0) {
00948 ast_debug(3, "COPS: lost connection to %s\n", cmts->name);
00949 close(cmts->sfd);
00950 cmts->sfd = -1;
00951 cmts->state = 0;
00952 }
00953 cops_freemsg(recmsg);
00954 }
00955 }
00956 AST_LIST_UNLOCK(&cmts_list);
00957 }
00958 if (pktcreload) {
00959 ast_debug(3, "Reloading pktccops...\n");
00960 AST_LIST_LOCK(&gate_list);
00961 AST_LIST_LOCK(&cmts_list);
00962 pktccops_unregister_ippools();
00963 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
00964 cmts->need_delete = 1;
00965 }
00966 load_pktccops_config();
00967 AST_LIST_TRAVERSE_SAFE_BEGIN(&cmts_list, cmts, list) {
00968 if (cmts && cmts->need_delete) {
00969 AST_LIST_TRAVERSE(&gate_list, gate, list) {
00970 if (gate->cmts == cmts) {
00971 ast_debug(3, "Null gate %s\n", gate->cmts->name);
00972 gate->cmts = NULL;
00973 }
00974 gate->in_transaction = 0;
00975 }
00976 AST_LIST_UNLOCK(&gate_list);
00977 ast_debug(3, "removing cmts: %s\n", cmts->name);
00978 if (cmts->sfd > 0) {
00979 close(cmts->sfd);
00980 }
00981 AST_LIST_REMOVE_CURRENT(list);
00982 free(cmts);
00983 }
00984 }
00985 AST_LIST_TRAVERSE_SAFE_END;
00986 AST_LIST_UNLOCK(&cmts_list);
00987 AST_LIST_UNLOCK(&gate_list);
00988 pktcreload = 2;
00989 }
00990 pthread_testcancel();
00991 }
00992 return NULL;
00993 }
00994
00995 static int restart_pktc_thread(void)
00996 {
00997 if (pktccops_thread == AST_PTHREADT_STOP) {
00998 return 0;
00999 }
01000 if (ast_mutex_lock(&pktccops_lock)) {
01001 ast_log(LOG_WARNING, "Unable to lock pktccops\n");
01002 return -1;
01003 }
01004 if (pktccops_thread == pthread_self()) {
01005 ast_mutex_unlock(&pktccops_lock);
01006 ast_log(LOG_WARNING, "Cannot kill myself\n");
01007 return -1;
01008 }
01009 if (pktccops_thread != AST_PTHREADT_NULL) {
01010
01011 pthread_kill(pktccops_thread, SIGURG);
01012 } else {
01013
01014 if (ast_pthread_create_background(&pktccops_thread, NULL, do_pktccops, NULL) < 0) {
01015 ast_mutex_unlock(&pktccops_lock);
01016 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
01017 return -1;
01018 }
01019 }
01020 ast_mutex_unlock(&pktccops_lock);
01021 return 0;
01022 }
01023
01024 static int load_pktccops_config(void)
01025 {
01026 static char *cfg = "res_pktccops.conf";
01027 struct ast_config *config;
01028 struct ast_variable *v;
01029 struct cops_cmts *cmts;
01030 struct cops_ippool *new_ippool;
01031 const char *host, *cat, *port;
01032 int sfd, update;
01033 int res = 0;
01034 uint16_t t1_temp, t7_temp, t8_temp;
01035 uint32_t keepalive_temp;
01036 unsigned int a,b,c,d,e,f,g,h;
01037 struct ast_flags config_flags = {0};
01038
01039 if (!(config = ast_config_load(cfg, config_flags))) {
01040 ast_log(LOG_WARNING, "Unable to load config file res_pktccops.conf\n");
01041 return -1;
01042 }
01043 for (cat = ast_category_browse(config, NULL); cat; cat = ast_category_browse(config, cat)) {
01044 if (!strcmp(cat, "general")) {
01045 for (v = ast_variable_browse(config, cat); v; v = v->next) {
01046 if (!strcasecmp(v->name, "t1")) {
01047 t1 = atoi(v->value);
01048 } else if (!strcasecmp(v->name, "t7")) {
01049 t7 = atoi(v->value);
01050 } else if (!strcasecmp(v->name, "t8")) {
01051 t8 = atoi(v->value);
01052 } else if (!strcasecmp(v->name, "keepalive")) {
01053 keepalive = atoi(v->value);
01054 } else if (!strcasecmp(v->name, "gateinfoperiod")) {
01055 gateinfoperiod = atoi(v->value);
01056 } else if (!strcasecmp(v->name, "gatetimeout")) {
01057 gatetimeout = atoi(v->value);
01058 } else {
01059 ast_log(LOG_WARNING, "Unkown option %s in general section of res_ptkccops.conf\n", v->name);
01060 }
01061 }
01062 } else {
01063
01064 host = NULL;
01065 port = NULL;
01066 sfd = 0;
01067 t1_temp = t1;
01068 t7_temp = t7;
01069 t8_temp = t8;
01070 keepalive_temp = keepalive;
01071
01072 for (v = ast_variable_browse(config, cat); v; v = v->next) {
01073 if (!strcasecmp(v->name, "host")) {
01074 host = v->value;
01075 } else if (!strcasecmp(v->name, "port")) {
01076 port = v->value;
01077 } else if (!strcasecmp(v->name, "t1")) {
01078 t1_temp = atoi(v->value);
01079 } else if (!strcasecmp(v->name, "t7")) {
01080 t7_temp = atoi(v->value);
01081 } else if (!strcasecmp(v->name, "t8")) {
01082 t8_temp = atoi(v->value);
01083 } else if (!strcasecmp(v->name, "keepalive")) {
01084 keepalive_temp = atoi(v->value);
01085 } else if (!strcasecmp(v->name, "pool")) {
01086
01087 } else {
01088 ast_log(LOG_WARNING, "Unkown option %s in res_ptkccops.conf\n", v->name);
01089 }
01090 }
01091
01092 update = 0;
01093 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01094 if (!strcmp(cmts->name, cat)) {
01095 update = 1;
01096 break;
01097 }
01098
01099 }
01100 if (!update) {
01101 cmts = ast_calloc(1, sizeof(*cmts));
01102 if (!cmts) {
01103 res = -1;
01104 break;
01105 }
01106 AST_LIST_INSERT_HEAD(&cmts_list, cmts, list);
01107 }
01108 if (cat) {
01109 ast_copy_string(cmts->name, cat, sizeof(cmts->name));
01110 }
01111 if (host) {
01112 ast_copy_string(cmts->host, host, sizeof(cmts->host));
01113 }
01114 if (port) {
01115 ast_copy_string(cmts->port, port, sizeof(cmts->port));
01116 } else {
01117 ast_copy_string(cmts->port, DEFAULT_COPS_PORT, sizeof(cmts->port));
01118 }
01119
01120 cmts->t1 = t1_temp;
01121 cmts->t7 = t7_temp;
01122 cmts->t8 = t8_temp;
01123 cmts->keepalive = keepalive_temp;
01124 if (!update) {
01125 cmts->state = 0;
01126 cmts->sfd = -1;
01127 }
01128 cmts->need_delete = 0;
01129 for (v = ast_variable_browse(config, cat); v; v = v->next) {
01130
01131 if (!strcasecmp(v->name, "pool")) {
01132 if (sscanf(v->value, "%3u.%3u.%3u.%3u %3u.%3u.%3u.%3u", &a, &b, &c, &d, &e, &f, &g, &h) == 8) {
01133 new_ippool = ast_calloc(1, sizeof(*new_ippool));
01134 if (!new_ippool) {
01135 res = -1;
01136 break;
01137 }
01138 new_ippool->start = a << 24 | b << 16 | c << 8 | d;
01139 new_ippool->stop = e << 24 | f << 16 | g << 8 | h;
01140 new_ippool->cmts = cmts;
01141 pktccops_add_ippool(new_ippool);
01142 } else {
01143 ast_log(LOG_WARNING, "Invalid ip pool format in res_pktccops.conf\n");
01144 }
01145 }
01146 }
01147 }
01148 }
01149 ast_config_destroy(config);
01150 return res;
01151 }
01152
01153 static char *pktccops_show_cmtses(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01154 {
01155 struct cops_cmts *cmts;
01156 char statedesc[16];
01157 int katimer;
01158
01159 switch(cmd) {
01160 case CLI_INIT:
01161 e->command = "pktccops show cmtses";
01162 e->usage =
01163 "Usage: pktccops show cmtses\n"
01164 " List PacketCable COPS CMTSes.\n";
01165
01166 return NULL;
01167 case CLI_GENERATE:
01168 return NULL;
01169 }
01170
01171 ast_cli(a->fd, "%-16s %-24s %-12s %7s\n", "Name ", "Host ", "Status ", "KA timer ");
01172 ast_cli(a->fd, "%-16s %-24s %-12s %7s\n", "------------", "--------------------", "----------", "-----------");
01173 AST_LIST_LOCK(&cmts_list);
01174 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01175 katimer = -1;
01176 if (cmts->state == 2) {
01177 ast_copy_string(statedesc, "Connected", sizeof(statedesc));
01178 katimer = (int) (time(NULL) - cmts->katimer);
01179 } else if (cmts->state == 1) {
01180 ast_copy_string(statedesc, "Connecting", sizeof(statedesc));
01181 } else {
01182 ast_copy_string(statedesc, "N/A", sizeof(statedesc));
01183 }
01184 ast_cli(a->fd, "%-16s %-15s:%-8s %-12s %-7d\n", cmts->name, cmts->host, cmts->port, statedesc, katimer);
01185 }
01186 AST_LIST_UNLOCK(&cmts_list);
01187 return CLI_SUCCESS;
01188 }
01189
01190 static char *pktccops_show_gates(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01191 {
01192 struct cops_gate *gate;
01193 char state_desc[16];
01194
01195 switch(cmd) {
01196 case CLI_INIT:
01197 e->command = "pktccops show gates";
01198 e->usage =
01199 "Usage: pktccops show gates\n"
01200 " List PacketCable COPS GATEs.\n";
01201
01202 return NULL;
01203 case CLI_GENERATE:
01204 return NULL;
01205 }
01206
01207 ast_cli(a->fd, "%-16s %-12s %-12s %-10s %-10s %-10s\n" ,"CMTS", "Gate-Id","MTA", "Status", "AllocTime", "CheckTime");
01208 ast_cli(a->fd, "%-16s %-12s %-12s %-10s %-10s %-10s\n" ,"--------------" ,"----------", "----------", "--------", "--------", "--------\n");
01209 AST_LIST_LOCK(&cmts_list);
01210 AST_LIST_LOCK(&gate_list);
01211 AST_LIST_TRAVERSE(&gate_list, gate, list) {
01212 if (gate->state == GATE_ALLOC_FAILED) {
01213 ast_copy_string(state_desc, "Failed", sizeof(state_desc));
01214 } else if (gate->state == GATE_ALLOC_PROGRESS) {
01215 ast_copy_string(state_desc, "In Progress", sizeof(state_desc));
01216 } else if (gate->state == GATE_ALLOCATED) {
01217 ast_copy_string(state_desc, "Allocated", sizeof(state_desc));
01218 } else if (gate->state == GATE_CLOSED) {
01219 ast_copy_string(state_desc, "Closed", sizeof(state_desc));
01220 } else if (gate->state == GATE_CLOSED_ERR) {
01221 ast_copy_string(state_desc, "ClosedErr", sizeof(state_desc));
01222 } else if (gate->state == GATE_OPEN) {
01223 ast_copy_string(state_desc, "Open", sizeof(state_desc));
01224 } else if (gate->state == GATE_DELETED) {
01225 ast_copy_string(state_desc, "Deleted", sizeof(state_desc));
01226 } else {
01227 ast_copy_string(state_desc, "N/A", sizeof(state_desc));
01228 }
01229
01230 ast_cli(a->fd, "%-16s 0x%.8x 0x%08x %-10s %10i %10i %u\n", (gate->cmts) ? gate->cmts->name : "null" , gate->gateid, gate->mta,
01231 state_desc, (int) (time(NULL) - gate->allocated), (gate->checked) ? (int) (time(NULL) - gate->checked) : 0, (unsigned int) gate->in_transaction);
01232 }
01233 AST_LIST_UNLOCK(&cmts_list);
01234 AST_LIST_UNLOCK(&gate_list);
01235 return CLI_SUCCESS;
01236 }
01237
01238 static char *pktccops_show_pools(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01239 {
01240 struct cops_ippool *ippool;
01241 char start[32];
01242 char stop[32];
01243
01244 switch(cmd) {
01245 case CLI_INIT:
01246 e->command = "pktccops show pools";
01247 e->usage =
01248 "Usage: pktccops show pools\n"
01249 " List PacketCable COPS ip pools of MTAs.\n";
01250
01251 return NULL;
01252 case CLI_GENERATE:
01253 return NULL;
01254 }
01255
01256 ast_cli(a->fd, "%-16s %-18s %-7s\n", "Start ", "Stop ", "CMTS ");
01257 ast_cli(a->fd, "%-16s %-18s %-7s\n", "----------", "----------", "--------");
01258 AST_LIST_LOCK(&ippool_list);
01259 AST_LIST_TRAVERSE(&ippool_list, ippool, list) {
01260 snprintf(start, sizeof(start), "%3u.%3u.%3u.%3u", ippool->start >> 24, (ippool->start >> 16) & 0x000000ff, (ippool->start >> 8) & 0x000000ff, ippool->start & 0x000000ff);
01261
01262 snprintf(stop, sizeof(stop), "%3u.%3u.%3u.%3u", ippool->stop >> 24, (ippool->stop >> 16) & 0x000000ff, (ippool->stop >> 8) & 0x000000ff, ippool->stop & 0x000000ff);
01263 ast_cli(a->fd, "%-16s %-18s %-16s\n", start, stop, ippool->cmts->name);
01264 }
01265 AST_LIST_UNLOCK(&ippool_list);
01266 return CLI_SUCCESS;
01267 }
01268
01269 static char *pktccops_gatedel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01270 {
01271 int found = 0;
01272 int trid;
01273 uint32_t gateid;
01274 struct cops_gate *gate;
01275 struct cops_cmts *cmts;
01276
01277 switch (cmd) {
01278 case CLI_INIT:
01279 e->command = "pktccops gatedel";
01280 e->usage =
01281 "Usage: pktccops gatedel <cmts> <gateid>\n"
01282 " Send Gate-Del to cmts.\n";
01283 return NULL;
01284 case CLI_GENERATE:
01285 return NULL;
01286 }
01287
01288 if (a->argc < 4)
01289 return CLI_SHOWUSAGE;
01290
01291 AST_LIST_LOCK(&cmts_list);
01292 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01293 if (!strcmp(cmts->name, a->argv[2])) {
01294 ast_cli(a->fd, "Found cmts: %s\n", cmts->name);
01295 found = 1;
01296 break;
01297 }
01298 }
01299 AST_LIST_UNLOCK(&cmts_list);
01300
01301 if (!found)
01302 return CLI_SHOWUSAGE;
01303
01304 trid = cops_trid++;
01305 if (!sscanf(a->argv[3], "%x", &gateid)) {
01306 ast_cli(a->fd, "bad gate specification (%s)\n", a->argv[3]);
01307 return CLI_SHOWUSAGE;
01308 }
01309
01310 found = 0;
01311 AST_LIST_LOCK(&gate_list);
01312 AST_LIST_TRAVERSE(&gate_list, gate, list) {
01313 if (gate->gateid == gateid && gate->cmts == cmts) {
01314 found = 1;
01315 break;
01316 }
01317 }
01318
01319 if (!found) {
01320 ast_cli(a->fd, "gate not found: %s\n", a->argv[3]);
01321 return CLI_SHOWUSAGE;
01322 }
01323
01324 AST_LIST_UNLOCK(&gate_list);
01325 cops_gate_cmd(GATE_DEL, cmts, trid, 0, 0, 0, 0, 0, 0, gate);
01326 return CLI_SUCCESS;
01327 }
01328
01329 static char *pktccops_gateset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01330 {
01331 int foundcmts = 0;
01332 int trid;
01333 unsigned int an,bn,cn,dn;
01334 uint32_t mta, ssip;
01335 struct cops_cmts *cmts;
01336 struct cops_gate *gate;
01337
01338 switch (cmd) {
01339 case CLI_INIT:
01340 e->command = "pktccops gateset";
01341 e->usage =
01342 "Usage: pktccops gateset <cmts> <mta> <acctcount> <bitrate> <packet size> <switch ip> <switch port>\n"
01343 " Send Gate-Set to cmts.\n";
01344 return NULL;
01345 case CLI_GENERATE:
01346 return NULL;
01347 }
01348
01349 if (a->argc < 9)
01350 return CLI_SHOWUSAGE;
01351
01352 if (!strncmp(a->argv[2], "null", sizeof(a->argv[2]))) {
01353 cmts = NULL;
01354 } else {
01355 AST_LIST_LOCK(&cmts_list);
01356 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01357 if (!strcmp(cmts->name, a->argv[2])) {
01358 ast_cli(a->fd, "Found cmts: %s\n", cmts->name);
01359 foundcmts = 1;
01360 break;
01361 }
01362 }
01363 AST_LIST_UNLOCK(&cmts_list);
01364 if (!foundcmts) {
01365 ast_cli(a->fd, "CMTS not found: %s\n", a->argv[2]);
01366 return CLI_SHOWUSAGE;
01367 }
01368 }
01369
01370 trid = cops_trid++;
01371 if (sscanf(a->argv[3], "%3u.%3u.%3u.%3u", &an, &bn, &cn, &dn) != 4) {
01372 ast_cli(a->fd, "MTA specification (%s) does not look like an ipaddr\n", a->argv[3]);
01373 return CLI_SHOWUSAGE;
01374 }
01375 mta = an << 24 | bn << 16 | cn << 8 | dn;
01376
01377 if (sscanf(a->argv[7], "%3u.%3u.%3u.%3u", &an, &bn, &cn, &dn) != 4) {
01378 ast_cli(a->fd, "SSIP specification (%s) does not look like an ipaddr\n", a->argv[7]);
01379 return CLI_SHOWUSAGE;
01380 }
01381 ssip = an << 24 | bn << 16 | cn << 8 | dn;
01382
01383 gate = cops_gate_cmd(GATE_SET, cmts, trid, mta, atoi(a->argv[4]), atof(a->argv[5]), atoi(a->argv[6]), ssip, atoi(a->argv[8]), NULL);
01384 return CLI_SUCCESS;
01385 }
01386
01387 static char *pktccops_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01388 {
01389 switch (cmd) {
01390 case CLI_INIT:
01391 e->command = "pktccops set debug {on|off}";
01392 e->usage =
01393 "Usage: pktccops set debug {on|off}\n"
01394 " Turn on/off debuging\n";
01395 return NULL;
01396 case CLI_GENERATE:
01397 return NULL;
01398 }
01399
01400 if (a->argc != e->args)
01401 return CLI_SHOWUSAGE;
01402 if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
01403 pktccopsdebug = 1;
01404 ast_cli(a->fd, "PktcCOPS Debugging Enabled\n");
01405 } else if (!strncasecmp(a->argv[e->args - 1], "off", 2)) {
01406 pktccopsdebug = 0;
01407 ast_cli(a->fd, "PktcCOPS Debugging Disabled\n");
01408 } else {
01409 return CLI_SHOWUSAGE;
01410 }
01411 return CLI_SUCCESS;
01412
01413 }
01414
01415 static struct ast_cli_entry cli_pktccops[] = {
01416 AST_CLI_DEFINE(pktccops_show_cmtses, "List PacketCable COPS CMTSes"),
01417 AST_CLI_DEFINE(pktccops_show_gates, "List PacketCable COPS GATEs"),
01418 AST_CLI_DEFINE(pktccops_show_pools, "List PacketCable MTA pools"),
01419 AST_CLI_DEFINE(pktccops_gateset, "Send Gate-Set to cmts"),
01420 AST_CLI_DEFINE(pktccops_gatedel, "Send Gate-Det to cmts"),
01421 AST_CLI_DEFINE(pktccops_debug, "Enable/Disable COPS debugging")
01422 };
01423
01424 static int pktccops_add_ippool(struct cops_ippool *ippool)
01425 {
01426 if (ippool) {
01427 AST_LIST_LOCK(&ippool_list);
01428 AST_LIST_INSERT_HEAD(&ippool_list, ippool, list);
01429 AST_LIST_UNLOCK(&ippool_list);
01430 return 0;
01431 } else {
01432 ast_log(LOG_WARNING, "Attempted to register NULL ippool?\n");
01433 return -1;
01434 }
01435 }
01436
01437 static void pktccops_unregister_cmtses(void)
01438 {
01439 struct cops_cmts *cmts;
01440 struct cops_gate *gate;
01441 AST_LIST_LOCK(&cmts_list);
01442 while ((cmts = AST_LIST_REMOVE_HEAD(&cmts_list, list))) {
01443 if (cmts->sfd > 0) {
01444 close(cmts->sfd);
01445 }
01446 free(cmts);
01447 }
01448 AST_LIST_UNLOCK(&cmts_list);
01449
01450 AST_LIST_LOCK(&gate_list);
01451 while ((gate = AST_LIST_REMOVE_HEAD(&gate_list, list))) {
01452 free(gate);
01453 }
01454 AST_LIST_UNLOCK(&gate_list);
01455 }
01456
01457 static void pktccops_unregister_ippools(void)
01458 {
01459 struct cops_ippool *ippool;
01460 AST_LIST_LOCK(&ippool_list);
01461 while ((ippool = AST_LIST_REMOVE_HEAD(&ippool_list, list))) {
01462 free(ippool);
01463 }
01464 AST_LIST_UNLOCK(&ippool_list);
01465 }
01466
01467 static int load_module(void)
01468 {
01469 int res;
01470 AST_LIST_LOCK(&cmts_list);
01471 res = load_pktccops_config();
01472 AST_LIST_UNLOCK(&cmts_list);
01473 if (res == -1) {
01474 return AST_MODULE_LOAD_DECLINE;
01475 }
01476 ast_cli_register_multiple(cli_pktccops, sizeof(cli_pktccops) / sizeof(struct ast_cli_entry));
01477 restart_pktc_thread();
01478 return 0;
01479 }
01480
01481 static int unload_module(void)
01482 {
01483 if (!ast_mutex_lock(&pktccops_lock)) {
01484 if ((pktccops_thread != AST_PTHREADT_NULL) && (pktccops_thread != AST_PTHREADT_STOP)) {
01485 pthread_cancel(pktccops_thread);
01486 pthread_kill(pktccops_thread, SIGURG);
01487 pthread_join(pktccops_thread, NULL);
01488 }
01489 pktccops_thread = AST_PTHREADT_STOP;
01490 ast_mutex_unlock(&pktccops_lock);
01491 } else {
01492 ast_log(LOG_ERROR, "Unable to lock the pktccops_thread\n");
01493 return -1;
01494 }
01495
01496 ast_cli_unregister_multiple(cli_pktccops, sizeof(cli_pktccops) / sizeof(struct ast_cli_entry));
01497 pktccops_unregister_cmtses();
01498 pktccops_unregister_ippools();
01499 pktccops_thread = AST_PTHREADT_NULL;
01500 return 0;
01501 }
01502
01503 static int reload_module(void)
01504 {
01505
01506 if (pktcreload) {
01507 ast_log(LOG_NOTICE, "Previous reload in progress, please wait!\n");
01508 return -1;
01509 }
01510 pktcreload = 1;
01511 return 0;
01512 }
01513
01514 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PktcCOPS manager for MGCP",
01515 .load = load_module,
01516 .unload = unload_module,
01517 .reload = reload_module,
01518 );
01519