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: 355839 $")
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 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 t1_temp = t1;
01067 t7_temp = t7;
01068 t8_temp = t8;
01069 keepalive_temp = keepalive;
01070
01071 for (v = ast_variable_browse(config, cat); v; v = v->next) {
01072 if (!strcasecmp(v->name, "host")) {
01073 host = v->value;
01074 } else if (!strcasecmp(v->name, "port")) {
01075 port = v->value;
01076 } else if (!strcasecmp(v->name, "t1")) {
01077 t1_temp = atoi(v->value);
01078 } else if (!strcasecmp(v->name, "t7")) {
01079 t7_temp = atoi(v->value);
01080 } else if (!strcasecmp(v->name, "t8")) {
01081 t8_temp = atoi(v->value);
01082 } else if (!strcasecmp(v->name, "keepalive")) {
01083 keepalive_temp = atoi(v->value);
01084 } else if (!strcasecmp(v->name, "pool")) {
01085
01086 } else {
01087 ast_log(LOG_WARNING, "Unkown option %s in res_ptkccops.conf\n", v->name);
01088 }
01089 }
01090
01091 update = 0;
01092 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01093 if (!strcmp(cmts->name, cat)) {
01094 update = 1;
01095 break;
01096 }
01097
01098 }
01099 if (!update) {
01100 cmts = ast_calloc(1, sizeof(*cmts));
01101 if (!cmts) {
01102 res = -1;
01103 break;
01104 }
01105 AST_LIST_INSERT_HEAD(&cmts_list, cmts, list);
01106 }
01107 if (cat) {
01108 ast_copy_string(cmts->name, cat, sizeof(cmts->name));
01109 }
01110 if (host) {
01111 ast_copy_string(cmts->host, host, sizeof(cmts->host));
01112 }
01113 if (port) {
01114 ast_copy_string(cmts->port, port, sizeof(cmts->port));
01115 } else {
01116 ast_copy_string(cmts->port, DEFAULT_COPS_PORT, sizeof(cmts->port));
01117 }
01118
01119 cmts->t1 = t1_temp;
01120 cmts->t7 = t7_temp;
01121 cmts->t8 = t8_temp;
01122 cmts->keepalive = keepalive_temp;
01123 if (!update) {
01124 cmts->state = 0;
01125 cmts->sfd = -1;
01126 }
01127 cmts->need_delete = 0;
01128 for (v = ast_variable_browse(config, cat); v; v = v->next) {
01129
01130 if (!strcasecmp(v->name, "pool")) {
01131 if (sscanf(v->value, "%3u.%3u.%3u.%3u %3u.%3u.%3u.%3u", &a, &b, &c, &d, &e, &f, &g, &h) == 8) {
01132 new_ippool = ast_calloc(1, sizeof(*new_ippool));
01133 if (!new_ippool) {
01134 res = -1;
01135 break;
01136 }
01137 new_ippool->start = a << 24 | b << 16 | c << 8 | d;
01138 new_ippool->stop = e << 24 | f << 16 | g << 8 | h;
01139 new_ippool->cmts = cmts;
01140 pktccops_add_ippool(new_ippool);
01141 } else {
01142 ast_log(LOG_WARNING, "Invalid ip pool format in res_pktccops.conf\n");
01143 }
01144 }
01145 }
01146 }
01147 }
01148 ast_config_destroy(config);
01149 return res;
01150 }
01151
01152 static char *pktccops_show_cmtses(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01153 {
01154 struct cops_cmts *cmts;
01155 char statedesc[16];
01156 int katimer;
01157
01158 switch(cmd) {
01159 case CLI_INIT:
01160 e->command = "pktccops show cmtses";
01161 e->usage =
01162 "Usage: pktccops show cmtses\n"
01163 " List PacketCable COPS CMTSes.\n";
01164
01165 return NULL;
01166 case CLI_GENERATE:
01167 return NULL;
01168 }
01169
01170 ast_cli(a->fd, "%-16s %-24s %-12s %7s\n", "Name ", "Host ", "Status ", "KA timer ");
01171 ast_cli(a->fd, "%-16s %-24s %-12s %7s\n", "------------", "--------------------", "----------", "-----------");
01172 AST_LIST_LOCK(&cmts_list);
01173 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01174 katimer = -1;
01175 if (cmts->state == 2) {
01176 ast_copy_string(statedesc, "Connected", sizeof(statedesc));
01177 katimer = (int) (time(NULL) - cmts->katimer);
01178 } else if (cmts->state == 1) {
01179 ast_copy_string(statedesc, "Connecting", sizeof(statedesc));
01180 } else {
01181 ast_copy_string(statedesc, "N/A", sizeof(statedesc));
01182 }
01183 ast_cli(a->fd, "%-16s %-15s:%-8s %-12s %-7d\n", cmts->name, cmts->host, cmts->port, statedesc, katimer);
01184 }
01185 AST_LIST_UNLOCK(&cmts_list);
01186 return CLI_SUCCESS;
01187 }
01188
01189 static char *pktccops_show_gates(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01190 {
01191 struct cops_gate *gate;
01192 char state_desc[16];
01193
01194 switch(cmd) {
01195 case CLI_INIT:
01196 e->command = "pktccops show gates";
01197 e->usage =
01198 "Usage: pktccops show gates\n"
01199 " List PacketCable COPS GATEs.\n";
01200
01201 return NULL;
01202 case CLI_GENERATE:
01203 return NULL;
01204 }
01205
01206 ast_cli(a->fd, "%-16s %-12s %-12s %-10s %-10s %-10s\n" ,"CMTS", "Gate-Id","MTA", "Status", "AllocTime", "CheckTime");
01207 ast_cli(a->fd, "%-16s %-12s %-12s %-10s %-10s %-10s\n" ,"--------------" ,"----------", "----------", "--------", "--------", "--------\n");
01208 AST_LIST_LOCK(&cmts_list);
01209 AST_LIST_LOCK(&gate_list);
01210 AST_LIST_TRAVERSE(&gate_list, gate, list) {
01211 if (gate->state == GATE_ALLOC_FAILED) {
01212 ast_copy_string(state_desc, "Failed", sizeof(state_desc));
01213 } else if (gate->state == GATE_ALLOC_PROGRESS) {
01214 ast_copy_string(state_desc, "In Progress", sizeof(state_desc));
01215 } else if (gate->state == GATE_ALLOCATED) {
01216 ast_copy_string(state_desc, "Allocated", sizeof(state_desc));
01217 } else if (gate->state == GATE_CLOSED) {
01218 ast_copy_string(state_desc, "Closed", sizeof(state_desc));
01219 } else if (gate->state == GATE_CLOSED_ERR) {
01220 ast_copy_string(state_desc, "ClosedErr", sizeof(state_desc));
01221 } else if (gate->state == GATE_OPEN) {
01222 ast_copy_string(state_desc, "Open", sizeof(state_desc));
01223 } else if (gate->state == GATE_DELETED) {
01224 ast_copy_string(state_desc, "Deleted", sizeof(state_desc));
01225 } else {
01226 ast_copy_string(state_desc, "N/A", sizeof(state_desc));
01227 }
01228
01229 ast_cli(a->fd, "%-16s 0x%.8x 0x%08x %-10s %10i %10i %u\n", (gate->cmts) ? gate->cmts->name : "null" , gate->gateid, gate->mta,
01230 state_desc, (int) (time(NULL) - gate->allocated), (gate->checked) ? (int) (time(NULL) - gate->checked) : 0, (unsigned int) gate->in_transaction);
01231 }
01232 AST_LIST_UNLOCK(&cmts_list);
01233 AST_LIST_UNLOCK(&gate_list);
01234 return CLI_SUCCESS;
01235 }
01236
01237 static char *pktccops_show_pools(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01238 {
01239 struct cops_ippool *ippool;
01240 char start[32];
01241 char stop[32];
01242
01243 switch(cmd) {
01244 case CLI_INIT:
01245 e->command = "pktccops show pools";
01246 e->usage =
01247 "Usage: pktccops show pools\n"
01248 " List PacketCable COPS ip pools of MTAs.\n";
01249
01250 return NULL;
01251 case CLI_GENERATE:
01252 return NULL;
01253 }
01254
01255 ast_cli(a->fd, "%-16s %-18s %-7s\n", "Start ", "Stop ", "CMTS ");
01256 ast_cli(a->fd, "%-16s %-18s %-7s\n", "----------", "----------", "--------");
01257 AST_LIST_LOCK(&ippool_list);
01258 AST_LIST_TRAVERSE(&ippool_list, ippool, list) {
01259 snprintf(start, sizeof(start), "%3u.%3u.%3u.%3u", ippool->start >> 24, (ippool->start >> 16) & 0x000000ff, (ippool->start >> 8) & 0x000000ff, ippool->start & 0x000000ff);
01260
01261 snprintf(stop, sizeof(stop), "%3u.%3u.%3u.%3u", ippool->stop >> 24, (ippool->stop >> 16) & 0x000000ff, (ippool->stop >> 8) & 0x000000ff, ippool->stop & 0x000000ff);
01262 ast_cli(a->fd, "%-16s %-18s %-16s\n", start, stop, ippool->cmts->name);
01263 }
01264 AST_LIST_UNLOCK(&ippool_list);
01265 return CLI_SUCCESS;
01266 }
01267
01268 static char *pktccops_gatedel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01269 {
01270 int found = 0;
01271 int trid;
01272 uint32_t gateid;
01273 struct cops_gate *gate;
01274 struct cops_cmts *cmts;
01275
01276 switch (cmd) {
01277 case CLI_INIT:
01278 e->command = "pktccops gatedel";
01279 e->usage =
01280 "Usage: pktccops gatedel <cmts> <gateid>\n"
01281 " Send Gate-Del to cmts.\n";
01282 return NULL;
01283 case CLI_GENERATE:
01284 return NULL;
01285 }
01286
01287 if (a->argc < 4)
01288 return CLI_SHOWUSAGE;
01289
01290 AST_LIST_LOCK(&cmts_list);
01291 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01292 if (!strcmp(cmts->name, a->argv[2])) {
01293 ast_cli(a->fd, "Found cmts: %s\n", cmts->name);
01294 found = 1;
01295 break;
01296 }
01297 }
01298 AST_LIST_UNLOCK(&cmts_list);
01299
01300 if (!found)
01301 return CLI_SHOWUSAGE;
01302
01303 trid = cops_trid++;
01304 if (!sscanf(a->argv[3], "%x", &gateid)) {
01305 ast_cli(a->fd, "bad gate specification (%s)\n", a->argv[3]);
01306 return CLI_SHOWUSAGE;
01307 }
01308
01309 found = 0;
01310 AST_LIST_LOCK(&gate_list);
01311 AST_LIST_TRAVERSE(&gate_list, gate, list) {
01312 if (gate->gateid == gateid && gate->cmts == cmts) {
01313 found = 1;
01314 break;
01315 }
01316 }
01317
01318 if (!found) {
01319 ast_cli(a->fd, "gate not found: %s\n", a->argv[3]);
01320 return CLI_SHOWUSAGE;
01321 }
01322
01323 AST_LIST_UNLOCK(&gate_list);
01324 cops_gate_cmd(GATE_DEL, cmts, trid, 0, 0, 0, 0, 0, 0, gate);
01325 return CLI_SUCCESS;
01326 }
01327
01328 static char *pktccops_gateset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01329 {
01330 int foundcmts = 0;
01331 int trid;
01332 unsigned int an,bn,cn,dn;
01333 uint32_t mta, ssip;
01334 struct cops_cmts *cmts;
01335
01336 switch (cmd) {
01337 case CLI_INIT:
01338 e->command = "pktccops gateset";
01339 e->usage =
01340 "Usage: pktccops gateset <cmts> <mta> <acctcount> <bitrate> <packet size> <switch ip> <switch port>\n"
01341 " Send Gate-Set to cmts.\n";
01342 return NULL;
01343 case CLI_GENERATE:
01344 return NULL;
01345 }
01346
01347 if (a->argc < 9)
01348 return CLI_SHOWUSAGE;
01349
01350 if (!strncmp(a->argv[2], "null", sizeof(a->argv[2]))) {
01351 cmts = NULL;
01352 } else {
01353 AST_LIST_LOCK(&cmts_list);
01354 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01355 if (!strcmp(cmts->name, a->argv[2])) {
01356 ast_cli(a->fd, "Found cmts: %s\n", cmts->name);
01357 foundcmts = 1;
01358 break;
01359 }
01360 }
01361 AST_LIST_UNLOCK(&cmts_list);
01362 if (!foundcmts) {
01363 ast_cli(a->fd, "CMTS not found: %s\n", a->argv[2]);
01364 return CLI_SHOWUSAGE;
01365 }
01366 }
01367
01368 trid = cops_trid++;
01369 if (sscanf(a->argv[3], "%3u.%3u.%3u.%3u", &an, &bn, &cn, &dn) != 4) {
01370 ast_cli(a->fd, "MTA specification (%s) does not look like an ipaddr\n", a->argv[3]);
01371 return CLI_SHOWUSAGE;
01372 }
01373 mta = an << 24 | bn << 16 | cn << 8 | dn;
01374
01375 if (sscanf(a->argv[7], "%3u.%3u.%3u.%3u", &an, &bn, &cn, &dn) != 4) {
01376 ast_cli(a->fd, "SSIP specification (%s) does not look like an ipaddr\n", a->argv[7]);
01377 return CLI_SHOWUSAGE;
01378 }
01379 ssip = an << 24 | bn << 16 | cn << 8 | dn;
01380
01381 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);
01382 return CLI_SUCCESS;
01383 }
01384
01385 static char *pktccops_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01386 {
01387 switch (cmd) {
01388 case CLI_INIT:
01389 e->command = "pktccops set debug {on|off}";
01390 e->usage =
01391 "Usage: pktccops set debug {on|off}\n"
01392 " Turn on/off debuging\n";
01393 return NULL;
01394 case CLI_GENERATE:
01395 return NULL;
01396 }
01397
01398 if (a->argc != e->args)
01399 return CLI_SHOWUSAGE;
01400 if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
01401 pktccopsdebug = 1;
01402 ast_cli(a->fd, "PktcCOPS Debugging Enabled\n");
01403 } else if (!strncasecmp(a->argv[e->args - 1], "off", 2)) {
01404 pktccopsdebug = 0;
01405 ast_cli(a->fd, "PktcCOPS Debugging Disabled\n");
01406 } else {
01407 return CLI_SHOWUSAGE;
01408 }
01409 return CLI_SUCCESS;
01410
01411 }
01412
01413 static struct ast_cli_entry cli_pktccops[] = {
01414 AST_CLI_DEFINE(pktccops_show_cmtses, "List PacketCable COPS CMTSes"),
01415 AST_CLI_DEFINE(pktccops_show_gates, "List PacketCable COPS GATEs"),
01416 AST_CLI_DEFINE(pktccops_show_pools, "List PacketCable MTA pools"),
01417 AST_CLI_DEFINE(pktccops_gateset, "Send Gate-Set to cmts"),
01418 AST_CLI_DEFINE(pktccops_gatedel, "Send Gate-Det to cmts"),
01419 AST_CLI_DEFINE(pktccops_debug, "Enable/Disable COPS debugging")
01420 };
01421
01422 static int pktccops_add_ippool(struct cops_ippool *ippool)
01423 {
01424 if (ippool) {
01425 AST_LIST_LOCK(&ippool_list);
01426 AST_LIST_INSERT_HEAD(&ippool_list, ippool, list);
01427 AST_LIST_UNLOCK(&ippool_list);
01428 return 0;
01429 } else {
01430 ast_log(LOG_WARNING, "Attempted to register NULL ippool?\n");
01431 return -1;
01432 }
01433 }
01434
01435 static void pktccops_unregister_cmtses(void)
01436 {
01437 struct cops_cmts *cmts;
01438 struct cops_gate *gate;
01439 AST_LIST_LOCK(&cmts_list);
01440 while ((cmts = AST_LIST_REMOVE_HEAD(&cmts_list, list))) {
01441 if (cmts->sfd > 0) {
01442 close(cmts->sfd);
01443 }
01444 free(cmts);
01445 }
01446 AST_LIST_UNLOCK(&cmts_list);
01447
01448 AST_LIST_LOCK(&gate_list);
01449 while ((gate = AST_LIST_REMOVE_HEAD(&gate_list, list))) {
01450 free(gate);
01451 }
01452 AST_LIST_UNLOCK(&gate_list);
01453 }
01454
01455 static void pktccops_unregister_ippools(void)
01456 {
01457 struct cops_ippool *ippool;
01458 AST_LIST_LOCK(&ippool_list);
01459 while ((ippool = AST_LIST_REMOVE_HEAD(&ippool_list, list))) {
01460 free(ippool);
01461 }
01462 AST_LIST_UNLOCK(&ippool_list);
01463 }
01464
01465 static int load_module(void)
01466 {
01467 int res;
01468 AST_LIST_LOCK(&cmts_list);
01469 res = load_pktccops_config();
01470 AST_LIST_UNLOCK(&cmts_list);
01471 if (res == -1) {
01472 return AST_MODULE_LOAD_DECLINE;
01473 }
01474 ast_cli_register_multiple(cli_pktccops, sizeof(cli_pktccops) / sizeof(struct ast_cli_entry));
01475 restart_pktc_thread();
01476 return 0;
01477 }
01478
01479 static int unload_module(void)
01480 {
01481 if (!ast_mutex_lock(&pktccops_lock)) {
01482 if ((pktccops_thread != AST_PTHREADT_NULL) && (pktccops_thread != AST_PTHREADT_STOP)) {
01483 pthread_cancel(pktccops_thread);
01484 pthread_kill(pktccops_thread, SIGURG);
01485 pthread_join(pktccops_thread, NULL);
01486 }
01487 pktccops_thread = AST_PTHREADT_STOP;
01488 ast_mutex_unlock(&pktccops_lock);
01489 } else {
01490 ast_log(LOG_ERROR, "Unable to lock the pktccops_thread\n");
01491 return -1;
01492 }
01493
01494 ast_cli_unregister_multiple(cli_pktccops, sizeof(cli_pktccops) / sizeof(struct ast_cli_entry));
01495 pktccops_unregister_cmtses();
01496 pktccops_unregister_ippools();
01497 pktccops_thread = AST_PTHREADT_NULL;
01498 return 0;
01499 }
01500
01501 static int reload_module(void)
01502 {
01503
01504 if (pktcreload) {
01505 ast_log(LOG_NOTICE, "Previous reload in progress, please wait!\n");
01506 return -1;
01507 }
01508 pktcreload = 1;
01509 return 0;
01510 }
01511
01512 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PktcCOPS manager for MGCP",
01513 .load = load_module,
01514 .unload = unload_module,
01515 .reload = reload_module,
01516 );
01517