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