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 #include <string.h>
00037 #include <stdio.h>
00038
00039 #include "mem/shm_mem.h"
00040 #include "mi/mi.h"
00041 #include "ut.h"
00042 #include "dprint.h"
00043 #include "locking.h"
00044 #include "socket_info.h"
00045 #include "core_stats.h"
00046 #include "statistics.h"
00047
00048 #ifdef STATISTICS
00049
00050 #define MAX_PROC_BUFFER 256
00051
00052 static stats_collector *collector;
00053
00054 static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param);
00055 static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param);
00056
00057 static mi_export_t mi_stat_cmds[] = {
00058 { "get_statistics", mi_get_stats, 0 , 0, 0 },
00059 { "reset_statistics", mi_reset_stats, 0 , 0, 0 },
00060 { 0, 0, 0, 0, 0}
00061 };
00062
00063
00064
00065 #ifdef NO_ATOMIC_OPS
00066 #warning STATISTICS: Architecture with no support for atomic operations. \
00067 Using Locks!!
00068 gen_lock_t *stat_lock = 0;
00069 #endif
00070
00071 #define stat_hash(_s) core_hash( _s, 0, STATS_HASH_SIZE)
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 stat_var *get_stat_var_from_num_code(unsigned int numerical_code, int out_codes)
00085 {
00086 static char msg_code[INT2STR_MAX_LEN+4];
00087 str stat_name;
00088
00089 stat_name.s = int2bstr( (unsigned long)numerical_code, msg_code,
00090 &stat_name.len);
00091 stat_name.s[stat_name.len++] = '_';
00092
00093 if (out_codes) {
00094 stat_name.s[stat_name.len++] = 'o';
00095 stat_name.s[stat_name.len++] = 'u';
00096 stat_name.s[stat_name.len++] = 't';
00097 } else {
00098 stat_name.s[stat_name.len++] = 'i';
00099 stat_name.s[stat_name.len++] = 'n';
00100 }
00101
00102 return get_stat(&stat_name);
00103 }
00104
00105
00106
00107 int init_stats_collector(void)
00108 {
00109
00110 collector = (stats_collector*)shm_malloc(sizeof(stats_collector));
00111 if (collector==0) {
00112 LM_ERR("no more shm mem\n");
00113 goto error;
00114 }
00115 memset( collector, 0 , sizeof(stats_collector));
00116
00117 #ifdef NO_ATOMIC_OPS
00118
00119 stat_lock = lock_alloc();
00120 if (stat_lock==0 || lock_init( stat_lock )==0 ) {
00121 LM_ERR("failed to init the really BIG lock\n");
00122 goto error;
00123 }
00124 #endif
00125
00126
00127 if (register_mi_mod( "statistics", mi_stat_cmds)<0) {
00128 LM_ERR("unable to register MI cmds\n");
00129 goto error;
00130 }
00131
00132
00133 if (register_module_stats( "core", core_stats)!=0 ) {
00134 LM_ERR("failed to register core statistics\n");
00135 goto error;
00136 }
00137
00138 if (register_module_stats( "shmem", shm_stats)!=0 ) {
00139 LM_ERR("failed to register sh_mem statistics\n");
00140 goto error;
00141 }
00142 LM_DBG("statistics manager successfully initialized\n");
00143
00144 return 0;
00145 error:
00146 return -1;
00147 }
00148
00149
00150 void destroy_stats_collector(void)
00151 {
00152 stat_var *stat;
00153 stat_var *tmp_stat;
00154 int i;
00155
00156 #ifdef NO_ATOMIC_OPS
00157
00158 if (stat_lock)
00159 lock_destroy( stat_lock );
00160 #endif
00161
00162 if (collector) {
00163
00164 for( i=0 ; i<STATS_HASH_SIZE ; i++ ) {
00165 for( stat=collector->hstats[i] ; stat ; ) {
00166 tmp_stat = stat;
00167 stat = stat->hnext;
00168 if ((tmp_stat->flags&STAT_IS_FUNC)==0 && tmp_stat->u.val)
00169 shm_free(tmp_stat->u.val);
00170 if ( (tmp_stat->flags&STAT_SHM_NAME) && tmp_stat->name.s)
00171 shm_free(tmp_stat->name.s);
00172 shm_free(tmp_stat);
00173 }
00174 }
00175
00176
00177 if (collector->amodules)
00178 shm_free(collector->amodules);
00179
00180
00181 shm_free(collector);
00182 }
00183
00184 return;
00185 }
00186
00187
00188 static inline module_stats* get_stat_module( str *module)
00189 {
00190 int i;
00191
00192 if ( (module==0) || module->s==0 || module->len==0 )
00193 return 0;
00194
00195 for( i=0 ; i<collector->mod_no ; i++ ) {
00196 if ( (collector->amodules[i].name.len == module->len) &&
00197 (strncasecmp(collector->amodules[i].name.s,module->s,module->len)==0) )
00198 return &collector->amodules[i];
00199 }
00200
00201 return 0;
00202 }
00203
00204
00205 static inline module_stats* add_stat_module( char *module)
00206 {
00207 module_stats *amods;
00208 module_stats *mods;
00209 int len;
00210
00211 if ( (module==0) || ((len = strlen(module))==0 ) )
00212 return 0;
00213
00214 amods = (module_stats*)shm_realloc( collector->amodules,
00215 (collector->mod_no+1)*sizeof(module_stats) );
00216 if (amods==0) {
00217 LM_ERR("no more shm memory\n");
00218 return 0;
00219 }
00220
00221 collector->amodules = amods;
00222 collector->mod_no++;
00223
00224 mods = &amods[collector->mod_no-1];
00225 memset( mods, 0, sizeof(module_stats) );
00226
00227 mods->name.s = module;
00228 mods->name.len = len;
00229
00230 return mods;
00231 }
00232
00233
00234 int register_stat( char *module, char *name, stat_var **pvar, int flags)
00235 {
00236 module_stats* mods;
00237 stat_var *stat;
00238 stat_var *it;
00239 str smodule;
00240 int hash;
00241
00242 if (module==0 || name==0 || pvar==0) {
00243 LM_ERR("invalid parameters module=%p, name=%p, pvar=%p \n",
00244 module, name, pvar);
00245 goto error;
00246 }
00247
00248 stat = (stat_var*)shm_malloc(sizeof(stat_var));
00249 if (stat==0) {
00250 LM_ERR("no more shm memory\n");
00251 goto error;
00252 }
00253 memset( stat, 0, sizeof(stat_var));
00254
00255 if ( (flags&STAT_IS_FUNC)==0 ) {
00256 stat->u.val = (stat_val*)shm_malloc(sizeof(stat_val));
00257 if (stat->u.val==0) {
00258 LM_ERR("no more shm memory\n");
00259 goto error1;
00260 }
00261 #ifdef NO_ATOMIC_OPS
00262 *(stat->u.val) = 0;
00263 #else
00264 atomic_set(stat->u.val,0);
00265 #endif
00266 *pvar = stat;
00267 } else {
00268 stat->u.f = (stat_function)(pvar);
00269 }
00270
00271
00272 smodule.s = module;
00273 smodule.len = strlen(module);
00274 mods = get_stat_module(&smodule);
00275 if (mods==0) {
00276 mods = add_stat_module(module);
00277 if (mods==0) {
00278 LM_ERR("failed to add new module\n");
00279 goto error2;
00280 }
00281 }
00282
00283
00284 stat->mod_idx = collector->mod_no-1;
00285
00286 stat->name.s = name;
00287 stat->name.len = strlen(name);
00288 stat->flags = flags;
00289
00290
00291
00292 hash = stat_hash( &stat->name );
00293
00294
00295 if (collector->hstats[hash]==0) {
00296 collector->hstats[hash] = stat;
00297 } else {
00298 it = collector->hstats[hash];
00299 while(it->hnext)
00300 it = it->hnext;
00301 it->hnext = stat;
00302 }
00303 collector->stats_no++;
00304
00305
00306 if (mods->tail) {
00307 mods->tail->lnext = stat;
00308 } else {
00309 mods->head = stat;
00310 }
00311 mods->tail = stat;
00312 mods->no++;
00313
00314 return 0;
00315 error2:
00316 if ( (flags&STAT_IS_FUNC)==0 ) {
00317 shm_free(*pvar);
00318 *pvar = 0;
00319 }
00320 error1:
00321 shm_free(stat);
00322 error:
00323 *pvar = 0;
00324 return -1;
00325 }
00326
00327
00328
00329 int register_module_stats(char *module, stat_export_t *stats)
00330 {
00331 int ret;
00332
00333 if (module==0 || module[0]==0 || !stats || !stats[0].name)
00334 return 0;
00335
00336 for( ; stats->name ; stats++) {
00337 ret = register_stat( module, stats->name, stats->stat_pointer,
00338 stats->flags);
00339 if (ret!=0) {
00340 LM_CRIT("failed to add statistic\n");
00341 return -1;
00342 }
00343 }
00344
00345 return 0;
00346 }
00347
00348
00349
00350 stat_var* get_stat( str *name )
00351 {
00352 stat_var *stat;
00353 int hash;
00354
00355 if (name==0 || name->s==0 || name->len==0)
00356 return 0;
00357
00358
00359 hash = stat_hash( name );
00360
00361
00362 for( stat=collector->hstats[hash] ; stat ; stat=stat->hnext ) {
00363 if ( (stat->name.len==name->len) &&
00364 (strncasecmp( stat->name.s, name->s, name->len)==0) )
00365 return stat;
00366 }
00367
00368 return 0;
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 int get_socket_list_from_proto(int **ipList, int protocol) {
00405
00406 struct socket_info *si;
00407 struct socket_info** list;
00408
00409 int num_ip_octets = 4;
00410 int numberOfSockets = 0;
00411 int currentRow = 0;
00412
00413
00414
00415 #ifndef USE_TCP
00416 if (protocol == PROTO_TCP)
00417 {
00418 return 0;
00419 }
00420 #endif
00421
00422 #ifndef USE_TLS
00423 if (protocol == PROTO_TLS)
00424 {
00425 return 0;
00426 }
00427 #endif
00428
00429
00430 list=get_sock_info_list(protocol);
00431
00432
00433
00434 for(si=list?*list:0; si; si=si->next){
00435
00436 if (si->address.af == AF_INET) {
00437 numberOfSockets++;
00438 }
00439 }
00440
00441
00442 if (numberOfSockets == 0)
00443 {
00444 return 0;
00445 }
00446
00447 *ipList = pkg_malloc(numberOfSockets * (num_ip_octets + 1) * sizeof(int));
00448
00449
00450
00451 if (*ipList == NULL) {
00452 LM_ERR("no more pkg memory");
00453 return 0;
00454 }
00455
00456
00457
00458 list=get_sock_info_list(protocol);
00459
00460
00461 for(si=list?*list:0; si; si=si->next){
00462
00463
00464 if (si->address.af != AF_INET) {
00465 continue;
00466 }
00467
00468 (*ipList)[currentRow*(num_ip_octets + 1) ] =
00469 si->address.u.addr[0];
00470 (*ipList)[currentRow*(num_ip_octets + 1)+1] =
00471 si->address.u.addr[1];
00472 (*ipList)[currentRow*(num_ip_octets + 1)+2] =
00473 si->address.u.addr[2];
00474 (*ipList)[currentRow*(num_ip_octets + 1)+3] =
00475 si->address.u.addr[3];
00476 (*ipList)[currentRow*(num_ip_octets + 1)+4] =
00477 si->port_no;
00478
00479 currentRow++;
00480 }
00481
00482 return numberOfSockets;
00483 }
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 static int parse_proc_net_line(char *line, int *ipAddress, int *rx_queue)
00496 {
00497 int i;
00498
00499 int ipOctetExtractionMask = 0xFF;
00500
00501 char *currColonLocation;
00502 char *nextNonNumericalChar;
00503 char *currentLocationInLine = line;
00504
00505 int parsedInteger[4];
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522 for (i = 0; i < 4; i++) {
00523
00524 currColonLocation = strchr(currentLocationInLine, ':');
00525
00526
00527 if (currColonLocation == NULL) {
00528 return 0;
00529 }
00530
00531
00532
00533 parsedInteger[i] =
00534 (int) strtol(++currColonLocation, &nextNonNumericalChar,
00535 16);
00536
00537
00538
00539
00540 if (nextNonNumericalChar == currColonLocation) {
00541 return 0;
00542 }
00543
00544
00545
00546
00547 currentLocationInLine = nextNonNumericalChar;
00548
00549 }
00550
00551
00552
00553 for (i = 0; i < NUM_IP_OCTETS; i++) {
00554
00555 ipAddress[i] =
00556 parsedInteger[0] & (ipOctetExtractionMask << i*8);
00557
00558 ipAddress[i] >>= i*8;
00559
00560 }
00561
00562 ipAddress[NUM_IP_OCTETS] = parsedInteger[1];
00563
00564 *rx_queue = parsedInteger[3];
00565
00566 return 1;
00567
00568 }
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 static int match_ip_and_port(int *ipOne, int *ipArray, int sizeOf_ipArray)
00579 {
00580 int curIPAddrIdx;
00581 int curOctetIdx;
00582 int ipArrayIndex;
00583
00584
00585 for (curIPAddrIdx = 0; curIPAddrIdx < sizeOf_ipArray; curIPAddrIdx++) {
00586
00587
00588
00589 for (curOctetIdx = 0; curOctetIdx < NUM_IP_OCTETS + 1; curOctetIdx++) {
00590
00591
00592
00593 ipArrayIndex =
00594 curIPAddrIdx * (NUM_IP_OCTETS + 1) + curOctetIdx;
00595
00596 if (ipOne[curOctetIdx] != ipArray[ipArrayIndex]) {
00597 break;
00598 }
00599 }
00600
00601
00602
00603
00604 if (curOctetIdx == NUM_IP_OCTETS + 1) {
00605 return 1;
00606 }
00607
00608 }
00609
00610 return 0;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 static int get_used_waiting_queue(
00626 int forTCP, int *interfaceList, int listSize)
00627 {
00628 FILE *fp;
00629 char *fileToOpen;
00630
00631 char lineBuffer[MAX_PROC_BUFFER];
00632 int ipAddress[NUM_IP_OCTETS+1];
00633 int rx_queue;
00634
00635 int waitingQueueSize = 0;
00636
00637
00638 if (forTCP) {
00639 fileToOpen = "/proc/net/tcp";
00640 } else {
00641 fileToOpen = "/proc/net/udp";
00642 }
00643
00644 fp = fopen(fileToOpen, "r");
00645
00646 if (fp == NULL) {
00647 LM_ERR("Could not open %s. openserMsgQueu eDepth and its related"
00648 " alarms will not be available.\n", fileToOpen);
00649 return 0;
00650 }
00651
00652
00653
00654
00655 while (fgets(lineBuffer, MAX_PROC_BUFFER, fp)!=NULL) {
00656
00657
00658 if(parse_proc_net_line(lineBuffer, ipAddress, &rx_queue)) {
00659
00660
00661
00662
00663
00664
00665 if (match_ip_and_port(ipAddress, interfaceList, listSize)) {
00666 waitingQueueSize += rx_queue;
00667 }
00668 }
00669 }
00670
00671 fclose(fp);
00672
00673 return waitingQueueSize;
00674 }
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 int get_total_bytes_waiting(void)
00685 {
00686 int bytesWaiting = 0;
00687
00688 int *UDPList = NULL;
00689 int *TCPList = NULL;
00690 int *TLSList = NULL;
00691
00692 int numUDPSockets = 0;
00693 int numTCPSockets = 0;
00694 int numTLSSockets = 0;
00695
00696
00697
00698 numUDPSockets = get_socket_list_from_proto(&UDPList, PROTO_UDP);
00699 numTCPSockets = get_socket_list_from_proto(&TCPList, PROTO_TCP);
00700 numTLSSockets = get_socket_list_from_proto(&TLSList, PROTO_TLS);
00701
00702
00703
00704 bytesWaiting += get_used_waiting_queue(0, UDPList, numUDPSockets);
00705 bytesWaiting += get_used_waiting_queue(1, TCPList, numTCPSockets);
00706 bytesWaiting += get_used_waiting_queue(1, TLSList, numTLSSockets);
00707
00708
00709
00710 if (numUDPSockets > 0)
00711 {
00712 pkg_free(UDPList);
00713 }
00714
00715 if (numTCPSockets > 0)
00716 {
00717 pkg_free(TCPList);
00718 }
00719
00720 if (numTLSSockets > 0)
00721 {
00722 pkg_free(TLSList);
00723 }
00724
00725 return bytesWaiting;
00726 }
00727
00728
00729
00730
00731 inline static int mi_add_stat(struct mi_node *rpl, stat_var *stat)
00732 {
00733 struct mi_node *node;
00734
00735 node = addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu",
00736 collector->amodules[stat->mod_idx].name.len,
00737 collector->amodules[stat->mod_idx].name.s,
00738 stat->name.len, stat->name.s,
00739 get_stat_val(stat) );
00740
00741 if (node==0)
00742 return -1;
00743 return 0;
00744 }
00745
00746 inline static int mi_add_module_stats(struct mi_node *rpl,
00747 module_stats *mods)
00748 {
00749 struct mi_node *node;
00750 stat_var *stat;
00751
00752 for( stat=mods->head ; stat ; stat=stat->lnext) {
00753 node = addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu",
00754 mods->name.len, mods->name.s,
00755 stat->name.len, stat->name.s,
00756 get_stat_val(stat) );
00757 if (node==0)
00758 return -1;
00759 }
00760 return 0;
00761 }
00762
00763
00764 static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param)
00765 {
00766 struct mi_root *rpl_tree;
00767 struct mi_node *rpl;
00768 struct mi_node *arg;
00769 module_stats *mods;
00770 stat_var *stat;
00771 str val;
00772 int i;
00773
00774 if (cmd->node.kids==NULL)
00775 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00776
00777 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00778 if (rpl_tree==0)
00779 return 0;
00780 rpl = &rpl_tree->node;
00781
00782 for( arg=cmd->node.kids ; arg ; arg=arg->next) {
00783 if (arg->value.len==0)
00784 continue;
00785
00786 val = arg->value;
00787
00788 if ( val.len==3 && memcmp(val.s,"all",3)==0) {
00789
00790 for( i=0 ; i<collector->mod_no ;i++ ) {
00791 if (mi_add_module_stats( rpl, &collector->amodules[i] )!=0)
00792 goto error;
00793 }
00794 } else if ( val.len>1 && val.s[val.len-1]==':') {
00795
00796 val.len--;
00797 mods = get_stat_module( &val );
00798 if (mods==0)
00799 continue;
00800 if (mi_add_module_stats( rpl, mods )!=0)
00801 goto error;
00802 } else {
00803
00804 stat = get_stat( &val );
00805 if (stat==0)
00806 continue;
00807 if (mi_add_stat(rpl,stat)!=0)
00808 goto error;
00809 }
00810 }
00811
00812 if (rpl->kids==0) {
00813 free_mi_tree(rpl_tree);
00814 return init_mi_tree( 404, "Statistics Not Found", 20);
00815 }
00816
00817 return rpl_tree;
00818 error:
00819 free_mi_tree(rpl_tree);
00820 return 0;
00821 }
00822
00823
00824
00825 static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param)
00826 {
00827 struct mi_root *rpl_tree;
00828 struct mi_node *arg;
00829 stat_var *stat;
00830 int found;
00831
00832 if (cmd->node.kids==NULL)
00833 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00834
00835 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00836 if (rpl_tree==0)
00837 return 0;
00838 found = 0;
00839
00840 for( arg=cmd->node.kids ; arg ; arg=arg->next) {
00841 if (arg->value.len==0)
00842 continue;
00843
00844 stat = get_stat( &arg->value );
00845 if (stat==0)
00846 continue;
00847
00848 reset_stat( stat );
00849 found = 1;
00850 }
00851
00852 if (!found) {
00853 free_mi_tree(rpl_tree);
00854 return init_mi_tree( 404, "Statistics Not Found", 20);
00855 }
00856
00857 return rpl_tree;
00858 }
00859
00860
00861 #endif
00862