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: 284597 $")
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 sfd, 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 sfd = 0;
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 struct cops_gate *gate;
01336
01337 switch (cmd) {
01338 case CLI_INIT:
01339 e->command = "pktccops gateset";
01340 e->usage =
01341 "Usage: pktccops gateset <cmts> <mta> <acctcount> <bitrate> <packet size> <switch ip> <switch port>\n"
01342 " Send Gate-Set to cmts.\n";
01343 return NULL;
01344 case CLI_GENERATE:
01345 return NULL;
01346 }
01347
01348 if (a->argc < 9)
01349 return CLI_SHOWUSAGE;
01350
01351 if (!strncmp(a->argv[2], "null", sizeof(a->argv[2]))) {
01352 cmts = NULL;
01353 } else {
01354 AST_LIST_LOCK(&cmts_list);
01355 AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
01356 if (!strcmp(cmts->name, a->argv[2])) {
01357 ast_cli(a->fd, "Found cmts: %s\n", cmts->name);
01358 foundcmts = 1;
01359 break;
01360 }
01361 }
01362 AST_LIST_UNLOCK(&cmts_list);
01363 if (!foundcmts) {
01364 ast_cli(a->fd, "CMTS not found: %s\n", a->argv[2]);
01365 return CLI_SHOWUSAGE;
01366 }
01367 }
01368
01369 trid = cops_trid++;
01370 if (sscanf(a->argv[3], "%3u.%3u.%3u.%3u", &an, &bn, &cn, &dn) != 4) {
01371 ast_cli(a->fd, "MTA specification (%s) does not look like an ipaddr\n", a->argv[3]);
01372 return CLI_SHOWUSAGE;
01373 }
01374 mta = an << 24 | bn << 16 | cn << 8 | dn;
01375
01376 if (sscanf(a->argv[7], "%3u.%3u.%3u.%3u", &an, &bn, &cn, &dn) != 4) {
01377 ast_cli(a->fd, "SSIP specification (%s) does not look like an ipaddr\n", a->argv[7]);
01378 return CLI_SHOWUSAGE;
01379 }
01380 ssip = an << 24 | bn << 16 | cn << 8 | dn;
01381
01382 gate = cops_gate_cmd(GATE_SET, cmts, trid, mta, atoi(a->argv[4]), atof(a->argv[5]), atoi(a->argv[6]), ssip, atoi(a->argv[8]), NULL);
01383 return CLI_SUCCESS;
01384 }
01385
01386 static char *pktccops_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01387 {
01388 switch (cmd) {
01389 case CLI_INIT:
01390 e->command = "pktccops set debug {on|off}";
01391 e->usage =
01392 "Usage: pktccops set debug {on|off}\n"
01393 " Turn on/off debuging\n";
01394 return NULL;
01395 case CLI_GENERATE:
01396 return NULL;
01397 }
01398
01399 if (a->argc != e->args)
01400 return CLI_SHOWUSAGE;
01401 if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
01402 pktccopsdebug = 1;
01403 ast_cli(a->fd, "PktcCOPS Debugging Enabled\n");
01404 } else if (!strncasecmp(a->argv[e->args - 1], "off", 2)) {
01405 pktccopsdebug = 0;
01406 ast_cli(a->fd, "PktcCOPS Debugging Disabled\n");
01407 } else {
01408 return CLI_SHOWUSAGE;
01409 }
01410 return CLI_SUCCESS;
01411
01412 }
01413
01414 static struct ast_cli_entry cli_pktccops[] = {
01415 AST_CLI_DEFINE(pktccops_show_cmtses, "List PacketCable COPS CMTSes"),
01416 AST_CLI_DEFINE(pktccops_show_gates, "List PacketCable COPS GATEs"),
01417 AST_CLI_DEFINE(pktccops_show_pools, "List PacketCable MTA pools"),
01418 AST_CLI_DEFINE(pktccops_gateset, "Send Gate-Set to cmts"),
01419 AST_CLI_DEFINE(pktccops_gatedel, "Send Gate-Det to cmts"),
01420 AST_CLI_DEFINE(pktccops_debug, "Enable/Disable COPS debugging")
01421 };
01422
01423 static int pktccops_add_ippool(struct cops_ippool *ippool)
01424 {
01425 if (ippool) {
01426 AST_LIST_LOCK(&ippool_list);
01427 AST_LIST_INSERT_HEAD(&ippool_list, ippool, list);
01428 AST_LIST_UNLOCK(&ippool_list);
01429 return 0;
01430 } else {
01431 ast_log(LOG_WARNING, "Attempted to register NULL ippool?\n");
01432 return -1;
01433 }
01434 }
01435
01436 static void pktccops_unregister_cmtses(void)
01437 {
01438 struct cops_cmts *cmts;
01439 struct cops_gate *gate;
01440 AST_LIST_LOCK(&cmts_list);
01441 while ((cmts = AST_LIST_REMOVE_HEAD(&cmts_list, list))) {
01442 if (cmts->sfd > 0) {
01443 close(cmts->sfd);
01444 }
01445 free(cmts);
01446 }
01447 AST_LIST_UNLOCK(&cmts_list);
01448
01449 AST_LIST_LOCK(&gate_list);
01450 while ((gate = AST_LIST_REMOVE_HEAD(&gate_list, list))) {
01451 free(gate);
01452 }
01453 AST_LIST_UNLOCK(&gate_list);
01454 }
01455
01456 static void pktccops_unregister_ippools(void)
01457 {
01458 struct cops_ippool *ippool;
01459 AST_LIST_LOCK(&ippool_list);
01460 while ((ippool = AST_LIST_REMOVE_HEAD(&ippool_list, list))) {
01461 free(ippool);
01462 }
01463 AST_LIST_UNLOCK(&ippool_list);
01464 }
01465
01466 static int load_module(void)
01467 {
01468 int res;
01469 AST_LIST_LOCK(&cmts_list);
01470 res = load_pktccops_config();
01471 AST_LIST_UNLOCK(&cmts_list);
01472 if (res == -1) {
01473 return AST_MODULE_LOAD_DECLINE;
01474 }
01475 ast_cli_register_multiple(cli_pktccops, sizeof(cli_pktccops) / sizeof(struct ast_cli_entry));
01476 restart_pktc_thread();
01477 return 0;
01478 }
01479
01480 static int unload_module(void)
01481 {
01482 if (!ast_mutex_lock(&pktccops_lock)) {
01483 if ((pktccops_thread != AST_PTHREADT_NULL) && (pktccops_thread != AST_PTHREADT_STOP)) {
01484 pthread_cancel(pktccops_thread);
01485 pthread_kill(pktccops_thread, SIGURG);
01486 pthread_join(pktccops_thread, NULL);
01487 }
01488 pktccops_thread = AST_PTHREADT_STOP;
01489 ast_mutex_unlock(&pktccops_lock);
01490 } else {
01491 ast_log(LOG_ERROR, "Unable to lock the pktccops_thread\n");
01492 return -1;
01493 }
01494
01495 ast_cli_unregister_multiple(cli_pktccops, sizeof(cli_pktccops) / sizeof(struct ast_cli_entry));
01496 pktccops_unregister_cmtses();
01497 pktccops_unregister_ippools();
01498 pktccops_thread = AST_PTHREADT_NULL;
01499 return 0;
01500 }
01501
01502 static int reload_module(void)
01503 {
01504
01505 if (pktcreload) {
01506 ast_log(LOG_NOTICE, "Previous reload in progress, please wait!\n");
01507 return -1;
01508 }
01509 pktcreload = 1;
01510 return 0;
01511 }
01512
01513 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PktcCOPS manager for MGCP",
01514 .load = load_module,
01515 .unload = unload_module,
01516 .reload = reload_module,
01517 );
01518