00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdlib.h>
00023 #include <time.h>
00024 #include <netdb.h>
00025 #include <sys/types.h>
00026 #include <sys/socket.h>
00027 #include <sys/time.h>
00028 #include <netinet/in.h>
00029 #include <netinet/in_systm.h>
00030 #include <netinet/ip.h>
00031 #include <string.h>
00032 #include <unistd.h>
00033 #include <stdio.h>
00034 #include <signal.h>
00035
00036 #include "statistics.h"
00037 #include "seas.h"
00038 #include "../../mem/shm_mem.h"
00039 #include "../../resolve.h"
00040 #include "../../ut.h"
00041 #include "../../dprint.h"
00042 #include "../../locking.h"
00043 #define STATS_PAY 101
00044
00045 struct statstable* seas_stats_table;
00046 int stats_fd;
00047 char use_stats=0;
00048 pid_t pid;
00049
00050 static void sig_handler(int signo)
00051 {
00052 switch(signo){
00053 case SIGTERM:
00054 LM_ERR("stats process caught SIGTERM, shutting down..\n");
00055 close(stats_fd);
00056 destroy_seas_stats_table();
00057 exit(0);
00058 default:
00059 LM_DBG("caught signal %d\n",signo);
00060 }
00061 LM_WARN("statistics process:caught signal (%d)\n",signo);
00062 }
00063
00064 struct statstable* init_seas_stats_table(void)
00065 {
00066
00067 seas_stats_table= (struct statstable*)shm_malloc( sizeof( struct statstable ) );
00068 if (!seas_stats_table) {
00069 LM_ERR("no shmem for stats table (%d bytes)\n",(int)sizeof(struct statstable));
00070 return 0;
00071 }
00072 memset(seas_stats_table, 0, sizeof(struct statstable) );
00073 if(0==(seas_stats_table->mutex=lock_alloc())){
00074 LM_ERR("couldn't alloc mutex (get_lock_t)\n");
00075 shm_free(seas_stats_table);
00076 return 0;
00077 }
00078 lock_init(seas_stats_table->mutex);
00079 return seas_stats_table;
00080 }
00081
00082 inline void destroy_seas_stats_table(void)
00083 {
00084
00085 if(seas_stats_table){
00086 lock_destroy(seas_stats_table->mutex);
00087 shm_free(seas_stats_table);
00088 seas_stats_table=(struct statstable *)0;
00089 }
00090 }
00091
00092
00093
00094
00095
00096 inline void as_relay_stat(struct cell *t)
00097 {
00098 struct statscell *s;
00099 struct totag_elem *to;
00100 if(t==0)
00101 return;
00102 if(t->fwded_totags != 0){
00103 LM_DBG("seas:as_relay_stat() unable to put a payload "
00104 "in fwded_totags because it is being used !!\n");
00105 return;
00106 }
00107 if(!(s=shm_malloc(sizeof(struct statscell)))){
00108 return;
00109 }
00110 if(!(to=shm_malloc(sizeof(struct totag_elem)))){
00111 shm_free(s);
00112 return;
00113 }
00114 memset(s,0,sizeof(struct statscell));
00115 gettimeofday(&(s->u.uas.as_relay),NULL);
00116 s->type=UAS_T;
00117 to->tag.len=0;
00118 to->tag.s=(char *)s;
00119 to->next=0;
00120 to->acked=STATS_PAY;
00121 t->fwded_totags=to;
00122 lock_get(seas_stats_table->mutex);
00123 (seas_stats_table->started_transactions)++;
00124 lock_release(seas_stats_table->mutex);
00125 }
00126
00127
00128
00129
00130
00131
00132
00133
00134 inline void event_stat(struct cell *t)
00135 {
00136 struct statscell *s;
00137 struct totag_elem *to;
00138 if(t==0){
00139
00140
00141 return;
00142 }
00143 if(t->fwded_totags == 0){
00144 LM_DBG("seas:event_stat() unabe to set the event_stat timeval:"
00145 " no payload found at cell!! (fwded_totags=0)\n");
00146 return;
00147 }
00148
00149 to=t->fwded_totags;
00150 while(to){
00151 if(to->acked==STATS_PAY){
00152 s=(struct statscell *)to->tag.s;
00153 gettimeofday(&(s->u.uas.event_sent),NULL);
00154 return;
00155 }else
00156 to=to->next;
00157 }
00158 return;
00159 }
00160
00161
00162 static inline int assignIndex(int i)
00163 {
00164 return (i/100)>14?14:(i/100);
00165 }
00166
00167
00168
00169
00170 inline void action_stat(struct cell *t)
00171 {
00172 unsigned int seas_dispatch,as_delay;
00173 struct timeval *t1,*t2,*t3;
00174 struct statscell *s;
00175 struct totag_elem *to;
00176 if(t==0)
00177 return;
00178 if(t->fwded_totags == 0){
00179 LM_DBG("seas:event_stat() unable to set the event_stat timeval:"
00180 " no payload found at cell!! (fwded_totags=0)\n");
00181 return;
00182 }
00183 to=t->fwded_totags;
00184 while(to){
00185 if(to->acked==STATS_PAY){
00186 s=(struct statscell *)to->tag.s;
00187 gettimeofday(&(s->u.uas.action_recvd),NULL);
00188 break;
00189 }else
00190 to=to->next;
00191 }
00192
00193 if(to==0)
00194 return;
00195 t1=&(s->u.uas.as_relay);
00196 t2=&(s->u.uas.event_sent);
00197 t3=&(s->u.uas.action_recvd);
00198 seas_dispatch = (t2->tv_sec - t1->tv_sec)*1000 + (t2->tv_usec-t1->tv_usec)/1000;
00199 as_delay = (t3->tv_sec - t2->tv_sec)*1000 + (t3->tv_usec-t2->tv_usec)/1000;
00200
00201 lock_get(seas_stats_table->mutex);
00202 {
00203 seas_stats_table->dispatch[assignIndex(seas_dispatch)]++;
00204 seas_stats_table->event[assignIndex(seas_dispatch)]++;
00205 (seas_stats_table->finished_transactions)++;
00206 }
00207 lock_release(seas_stats_table->mutex);
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 int start_stats_server(char *stats_socket)
00221 {
00222 char *p,*port;
00223 unsigned short stats_port;
00224 struct hostent *he;
00225
00226 struct sockaddr_in su;
00227 int optval;
00228
00229 use_stats=0;
00230 port=(char *)0;
00231 he=(struct hostent *)0;
00232 stats_fd=-1;
00233 p=stats_socket;
00234
00235 if(p==0 || *p==0)
00236 return 0;
00237
00238 if(!init_seas_stats_table()){
00239 LM_ERR("unable to init stats table, disabling statistics\n");
00240 return -1;
00241 }
00242 while(*p){
00243 if(*p == ':'){
00244 *p=0;
00245 port=p+1;
00246 break;
00247 }
00248 }
00249 if(!(he=resolvehost(stats_socket,0)))
00250 goto error;
00251 if(port==(char*)0 || *port==0)
00252 stats_port=5088;
00253 else if(!(stats_port=str2s(port,strlen(port),0))){
00254 LM_ERR("invalid port %s\n",port);
00255 goto error;
00256 }
00257 if((stats_fd=socket(he->h_addrtype, SOCK_STREAM, 0))==-1){
00258 LM_ERR("trying to open server socket (%s)\n",strerror(errno));
00259 goto error;
00260 }
00261 optval=1;
00262 if (setsockopt(stats_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(optval))==-1) {
00263 LM_ERR("setsockopt (%s)\n",strerror(errno));
00264 goto error;
00265 }
00266 su.sin_family = he->h_addrtype;
00267 su.sin_port=htons(stats_port);
00268 memcpy(&su.sin_addr,he->h_addr_list[0],4);
00269 if((bind(stats_fd,(struct sockaddr*)&su,sizeof(struct sockaddr_in)))==-1){
00270 LM_ERR( "bind (%s)\n",strerror(errno));
00271 goto error;
00272 }
00273 if(listen(stats_fd, 10)==-1){
00274 LM_ERR( "listen (%s)\n",strerror(errno));
00275 goto error;
00276 }
00277 if(!(pid=fork())){
00278 signal(SIGTERM,sig_handler);
00279 serve_stats(stats_fd);
00280 printf("statistics Server Process exits !!\n");
00281 exit(0);
00282 }else if(pid>0){
00283 close(stats_fd);
00284 }else{
00285 LM_ERR("failed to create stats server process\n");
00286 goto error;
00287 }
00288 use_stats=1;
00289 return 1;
00290 error:
00291 if(stats_fd!=-1)
00292 close(stats_fd);
00293 destroy_seas_stats_table();
00294 return -1;
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 inline int stop_stats_server(void)
00307 {
00308 if(pid)
00309 kill(SIGTERM,pid);
00310 return 0;
00311 }
00312
00313 void serve_stats(int fd)
00314 {
00315 union sockaddr_union su;
00316 int sock,i,retrn;
00317 socklen_t su_len;
00318 char f;
00319
00320 signal(SIGTERM,sig_handler);
00321 signal(SIGHUP,sig_handler);
00322 signal(SIGPIPE,sig_handler);
00323 signal(SIGQUIT,sig_handler);
00324 signal(SIGINT,sig_handler);
00325 signal(SIGCHLD,sig_handler);
00326
00327 while(1){
00328 su_len = sizeof(union sockaddr_union);
00329 sock=-1;
00330 sock=accept(fd, &su.s, &su_len);
00331 if(sock==-1){
00332 if(errno==EINTR){
00333 continue;
00334 }else{
00335 LM_ERR("failed to accept connection: %s\n", strerror(errno));
00336 return ;
00337 }
00338 }
00339 while(0!=(i=read(sock,&f,1))){
00340 if(i==-1){
00341 if(errno==EINTR){
00342 continue;
00343 }else{
00344 LM_ERR("unknown error reading from socket\n");
00345 close(sock);
00346
00347 break;
00348 }
00349 }
00350 retrn=print_stats_info(f,sock);
00351 if(retrn==-1){
00352
00353 LM_ERR("printing statisticss \n");
00354 continue;
00355 }else if(retrn==-2){
00356
00357 LM_ERR("statistics client left\n");
00358 close(sock);
00359 break;
00360 }
00361 }
00362 }
00363 }
00364
00365
00366
00367
00368
00369
00370
00371 inline int print_stats_info(int f,int sock)
00372 {
00373 #define STATS_BUF_SIZE 400
00374 int j,k,writen;
00375 char buf[STATS_BUF_SIZE];
00376
00377 writen=0;
00378 if(0>(k=snprintf(buf,STATS_BUF_SIZE, "Timings: 0-1 1-2 2-3 3-4 4-5 5-6 6-7 7-8 8-9 9-10 10-11 11-12 12-13 13-14 14+\n"))){
00379 goto error;
00380 }else{
00381 if(k>STATS_BUF_SIZE){
00382 j=STATS_BUF_SIZE;
00383 goto send;
00384 }
00385 j=k;
00386 }
00387 lock_get(seas_stats_table->mutex);
00388 if(0>(k=snprintf(&buf[j],STATS_BUF_SIZE-j,"UAS:dispatch: %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d\n",\
00389 seas_stats_table->dispatch[0],seas_stats_table->dispatch[1],seas_stats_table->dispatch[2],seas_stats_table->dispatch[3],seas_stats_table->dispatch[4]\
00390 ,seas_stats_table->dispatch[5],seas_stats_table->dispatch[6],seas_stats_table->dispatch[7],seas_stats_table->dispatch[8],seas_stats_table->dispatch[9],\
00391 seas_stats_table->dispatch[10],seas_stats_table->dispatch[11],seas_stats_table->dispatch[12],seas_stats_table->dispatch[13],seas_stats_table->dispatch[14]))){
00392 goto error;
00393 }else{
00394 if(k>(STATS_BUF_SIZE-j)){
00395 j=STATS_BUF_SIZE;
00396 goto send;
00397 }
00398 j+=k;
00399 }
00400 if(0>(k=snprintf(&buf[j],STATS_BUF_SIZE-j,"UAS:event: %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d %-5d\n",\
00401 seas_stats_table->event[0],seas_stats_table->event[1],seas_stats_table->event[2],seas_stats_table->event[3],seas_stats_table->event[4]\
00402 ,seas_stats_table->event[5],seas_stats_table->event[6],seas_stats_table->event[7],seas_stats_table->event[8],seas_stats_table->event[9],\
00403 seas_stats_table->event[10],seas_stats_table->event[11],seas_stats_table->event[12],seas_stats_table->event[13],seas_stats_table->event[14]))){
00404 goto error;
00405 }else{
00406 if(k>STATS_BUF_SIZE-j){
00407 j=STATS_BUF_SIZE;
00408 goto send;
00409 }
00410 j+=k;
00411 }
00412 if(0>(k=snprintf(&buf[j],STATS_BUF_SIZE-j,"Started Transactions: %d\nTerminated Transactions:%d\nReceived replies:%d\nReceived:%d\n",\
00413 seas_stats_table->started_transactions,seas_stats_table->finished_transactions,seas_stats_table->received_replies,seas_stats_table->received))){
00414 goto error;
00415 }else{
00416 if(k>STATS_BUF_SIZE-j){
00417 j=STATS_BUF_SIZE;
00418 goto send;
00419 }
00420 j+=k;
00421 }
00422 send:
00423 lock_release(seas_stats_table->mutex);
00424 again:
00425 k=write(sock,buf,j);
00426 if(k<0){
00427 switch(errno){
00428 case EINTR:
00429 goto again;
00430 case EPIPE:
00431 return -2;
00432 }
00433 }
00434 writen+=k;
00435 if(writen<j)
00436 goto again;
00437 return writen;
00438 error:
00439 lock_release(seas_stats_table->mutex);
00440 return -1;
00441 }
00442
00443 inline void stats_reply(void)
00444 {
00445 lock_get(seas_stats_table->mutex);
00446 seas_stats_table->received_replies++;
00447 lock_release(seas_stats_table->mutex);
00448 }
00449
00450