port numbers different now for remote and local ser_0839_errors
authorJiri Kuthan <jiri@iptel.org>
Tue, 20 Nov 2001 06:26:49 +0000 (06:26 +0000)
committerJiri Kuthan <jiri@iptel.org>
Tue, 20 Nov 2001 06:26:49 +0000 (06:26 +0000)
13 files changed:
Makefile
cfg.lex
cfg.y
forward.c
globals.h
main.c
msg_parser.c
msg_parser.h
parser_f.c
parser_f.h
receive.c
stats.h
test/shoot.c [moved from test/shoot.cpp with 78% similarity]

index d205a55..15620ef 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,8 @@ DEFS=-DNOCR -DMACROEATER -DSTATS -DOLD_PARSER -DDNS_IP_HACK #-DNO_DEBUG
 #-DNO_LOG
 
 PROFILE=  # -pg #set this if you want profiling
+#mode=release
+mode=debug
 
 # platform dependent settings
 
@@ -40,8 +42,15 @@ ARCH = $(shell uname -s)
 #common
 CC=gcc
 LD=gcc
-CFLAGS=-O2 -Wcast-align $(PROFILE) -Winline#-Wmissing-prototypes 
-LDFLAGS=-Wl,-O2 -Wl,-E $(PROFILE)
+
+ifeq ( mode, release )
+       CFLAGS=-O2 -Wcast-align $(PROFILE) -Winline#-Wmissing-prototypes 
+       LDFLAGS=-Wl,-O2 -Wl,-E $(PROFILE)
+else
+       CFLAGS=-g
+       LDFLAGS=-g
+endif
+
 LEX=flex
 YACC=bison
 YACC_FLAGS=-d -b cfg
@@ -127,3 +136,5 @@ proper: clean
 
 include $(depends)
 
+dbg: ser
+       gdb -command debug.gdb
diff --git a/cfg.lex b/cfg.lex
index 5fecfb8..c73f395 100644 (file)
--- a/cfg.lex
+++ b/cfg.lex
@@ -81,6 +81,7 @@ LISTEN                listen
 DNS             dns
 REV_DNS         rev_dns
 PORT   port
+STAT   statistics
 MAXBUFFER maxbuffer
 CHILDREN children
 CHECK_VIA      check_via
@@ -154,6 +155,7 @@ EAT_ABLE    [\ \t\b\r]
 <INITIAL>{DNS} { count(); yylval.strval=yytext; return DNS; }
 <INITIAL>{REV_DNS}     { count(); yylval.strval=yytext; return REV_DNS; }
 <INITIAL>{PORT}        { count(); yylval.strval=yytext; return PORT; }
+<INITIAL>{STAT}        { count(); yylval.strval=yytext; return STAT; }
 <INITIAL>{MAXBUFFER}   { count(); yylval.strval=yytext; return MAXBUFFER; }
 <INITIAL>{CHILDREN}    { count(); yylval.strval=yytext; return CHILDREN; }
 <INITIAL>{CHECK_VIA}   { count(); yylval.strval=yytext; return CHECK_VIA; }
diff --git a/cfg.y b/cfg.y
index 89f1bd2..2116d94 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -19,6 +19,7 @@
 #include "dprint.h"
 #include "sr_module.h"
 
+
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
@@ -73,6 +74,7 @@ void* f_tmp;
 %token DNS
 %token REV_DNS
 %token PORT
+%token STAT
 %token CHILDREN
 %token CHECK_VIA
 %token LOADMODULE
@@ -147,6 +149,7 @@ assign_stm: DEBUG EQUAL NUMBER { debug=$3; }
                | REV_DNS EQUAL NUMBER { received_dns|= ($3)?DO_REV_DNS:0; }
                | REV_DNS EQUAL error { yyerror("boolean value expected"); }
                | PORT EQUAL NUMBER   { port_no=$3; }
+               | STAT EQUAL STRING { stat_file=$3; }
                | MAXBUFFER EQUAL NUMBER { maxbuffer=$3; }
                | MAXBUFFER EQUAL error { yyerror("number expected"); }
                | PORT EQUAL error    { yyerror("number expected"); } 
index 7657ac8..b3389a3 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -431,20 +431,20 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 
        p->tx++;
        p->tx_bytes+=new_len;
-#ifdef STATS
-       stats.total_tx++;
-#endif
 
        if (udp_send(new_buf, new_len, (struct sockaddr*) to,
                                sizeof(struct sockaddr_in))==-1){
                        p->errors++;
                        p->ok=0;
+#ifdef STATS
+                       update_fail_on_send;
+#endif
                        goto error;
        } 
 #ifdef STATS
-       else stats.ok_tx_rq++;
+       /* sent requests stats */
+       else update_sent_request( msg->first_line.u.request.method_value );
 #endif
-
        free(new_buf);
        free(to);
        /* received_buf & line_buf will be freed in receiv_msg by free_lump_list*/
@@ -552,17 +552,19 @@ int forward_reply(struct sip_msg* msg)
                to->sin_port = (msg->via2.port)?htons(msg->via2.port):htons(SIP_PORT);
                to->sin_addr.s_addr=*((long*)he->h_addr_list[0]);
 
-#ifdef STATS
-               stats.total_tx++;
-#endif
 #ifdef DNS_IP_HACK
        }
 #endif
        if (udp_send(new_buf,new_len, (struct sockaddr*) to, 
-                                       sizeof(struct sockaddr_in))==-1)
+                                       sizeof(struct sockaddr_in))==-1) 
+       {
+#ifdef STATS
+               update_fail_on_send;
+#endif
                goto error;
+       }
 #ifdef STATS
-       else stats.ok_tx_rs++;
+       else update_sent_response(  msg->first_line.u.reply.statusclass );
 #endif
        
        free(new_buf);
index 21db84f..b5a7758 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -15,6 +15,7 @@
 
 
 extern char * cfg_file;
+extern char *stat_file;
 extern unsigned short port_no;
 extern char port_no_str[];
 extern int port_no_str_len;
diff --git a/main.c b/main.c
index bb711ea..9cf1555 100644 (file)
--- a/main.c
+++ b/main.c
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <sys/time.h>
 
 #include "config.h"
 #include "dprint.h"
@@ -26,8 +30,6 @@
 #include "stats.h"
 #endif
 
-
-
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
@@ -94,8 +96,11 @@ Options:\n\
     -V           Version number\n\
     -h           This help message\n\
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
-                 auto-probing procedure even if  OS allows\n\
-";
+                 auto-probing procedure even if  OS allows\n"
+#ifdef STATS
+"    -s file    File to which statistics is dumped (disabled otherwise)\n"
+#endif
+;
 
 /* print compile-time constants */
 void print_ct_constants()
@@ -127,9 +132,9 @@ char* cfg_file = 0;
 unsigned short port_no = 0; /* port on which we listen */
 char port_no_str[MAX_PORT_LEN];
 int port_no_str_len=0;
-unsigned int maxbuffer = 128*1024; /* maximum buffer size we do not want to exceed
-                                     durig the auto-probing procedure; may be
-                                     re-configured */
+unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do not want to exceed
+                                               durig the auto-probing procedure; may be
+                                               re-configured */
 int children_no = 0;           /* number of children processing requests */
 int debug = 0;
 int dont_fork = 0;
@@ -151,11 +156,6 @@ int process_no = 0;
 /* cfg parsing */
 int cfg_errors=0;
 
-#ifdef STATS
-/* jku: RX/TX statistics -- remember, they are process specific */
-struct stats_s stats;
-#endif
-
 
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
                    (normally it shouldn't  be bigger  than 3) */
@@ -226,6 +226,9 @@ int main_loop()
 
 
        if (dont_fork){
+#ifdef STATS
+               setstats( 0 );
+#endif
                /* only one address */
                if (udp_init(addresses[0],port_no)==-1) goto error;
                /* receive loop */
@@ -241,6 +244,9 @@ int main_loop()
                                }
                                if (pid==0){
                                        /* child */
+#ifdef STATS
+                                       setstats( i );
+#endif
                                        return udp_rcv_loop();
                                }
                        }
@@ -260,6 +266,7 @@ int main_loop()
 
 }
 
+
 /* added by jku; allows for regular exit on a specific signal;
    good for profiling which only works if exited regularly and
    not by default signal handlers
@@ -267,17 +274,25 @@ int main_loop()
 
 static void sig_usr(int signo)
 {
-       DPrint("INT received, program terminates\n");
+       if (signo==SIGINT) {    /* exit gracefuly */
 #ifdef STATS
-       DPrint("ok_rx_rq\t%d\nok_rx_rs\t%d\nok_tx_rq\t%d\nok_tx_rs\t%d\ntotal_rx\t%d\ntotal_tx\t%d\n\n",
-               stats.ok_rx_rq, stats.ok_rx_rs, stats.ok_tx_rq, stats.ok_tx_rs, stats.total_rx, stats.total_tx );
-       DPrint("Thank you for flying ser\n");
+               /* print statistics on exit only for the first process */
+
+               if (stats->process_index==0 && stat_file )
+                       if (dump_all_statistic()==0)
+                               printf("statistic dumped to %s\n", stat_file );
+                       else
+                               printf("statistics dump to %s failed\n", stat_file );
 #endif
-       exit(0);
+               DPrint("INT received, program terminates\n");
+               DPrint("Thank you for flying ser\n");
+               exit(0);
+       } else if (signo==SIGUSR1) { /* statistic */
+               dump_all_statistic();
+       }
 }
        
        
-       
 int main(int argc, char** argv)
 {
 
@@ -286,20 +301,36 @@ int main(int argc, char** argv)
        int c,r;
        char *tmp;
        struct utsname myname;
+       char *options;
 
        /* added by jku: add exit handler */
         if (signal(SIGINT, sig_usr) == SIG_ERR ) {
-               DPrint("ERROR: no signal handler can be installed\n");
+               DPrint("ERROR: no SIGINT signal handler can be installed\n");
+                goto error;
+        }
+#ifdef STATS
+       if (signal(SIGUSR1, sig_usr)  == SIG_ERR ) {
+                DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
                 goto error;
         }
+#endif
 
        /* process command line (get port no, cfg. file path etc) */
        opterr=0;
-       while((c=getopt(argc,argv,"f:p:b:l:n:rRvdDEVh"))!=-1){
+       options=
+#ifdef STATS
+       "s:"
+#endif
+       "f:p:b:l:n:rRvdDEVh";
+       
+       while((c=getopt(argc,argv,options))!=-1){
                switch(c){
                        case 'f':
                                        cfg_file=optarg;
                                        break;
+                       case 's':
+                                       stat_file=optarg;
+                                       break;
                        case 'p':
                                        port_no=strtol(optarg, &tmp, 10);
                                        if (tmp &&(*tmp)){
@@ -448,10 +479,6 @@ int main(int argc, char** argv)
                names_len[r]=strlen(names[r]);
        }
 
-#ifdef STATS
-       /* jku: initialize statistic */
-       memset(&stats,0,sizeof(struct stats_s));
-#endif
        
        /* get ips */
        printf("Listening on ");
@@ -467,6 +494,10 @@ int main(int argc, char** argv)
                                (unsigned short)port_no);
        }
 
+#ifdef STATS
+       if (init_stats(  dont_fork ? 1 : children_no  )==-1) goto error;
+#endif
+
        /* init_daemon? */
        if (!dont_fork){
                if ( daemonize(argv[0]) <0 ) goto error;
index 4353850..4ccff1a 100644 (file)
@@ -34,8 +34,9 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
        char* third;
        char* nl;
        int offset;
-       int l;
+       /* int l; */
        char* end;
+       char s1,s2,s3;
        
        /* grammar:
                request  =  method SP uri SP version CRLF
@@ -46,37 +47,72 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
 
        end=buffer+len;
        /* see if it's a reply (status) */
-       tmp=eat_token(buffer, len);
-       if ((tmp==buffer)||(tmp>=end)){
-               LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
+
+       /* jku  -- parse well-known methods */
+
+       /* drop messages which are so short they are for sure useless;
+           utilize knowledge of minimum size in parsing the first
+          token 
+        */
+       if (len <=16 ) {
+               LOG(L_INFO, "ERROR: parse_first_line: message too short\n");
                goto error1;
        }
-       l=tmp-buffer;
-       if ((SIP_VERSION_LEN==l) &&
-               (memcmp(buffer,SIP_VERSION,l)==0)){
-               
-               fl->type=SIP_REPLY;
-       }else{
+
+       tmp=buffer;
+       /* is it perhaps a reply, ie does it start with "SIP...." ? */
+       if (    (*tmp=='S' || *tmp=='s') && 
+               strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
+               (*(tmp+SIP_VERSION_LEN)==' ')) {
+                       fl->type=SIP_REPLY;
+                       fl->u.reply.version.len=SIP_VERSION_LEN;
+                       tmp=buffer+SIP_VERSION_LEN;
+       } else IFISMETHOD( INVITE, 'I' )
+       else IFISMETHOD( CANCEL, 'C')
+       else IFISMETHOD( ACK, 'A' )
+       else IFISMETHOD( BYE, 'B' )
+       /* if you want to add another method XXX, include METHOD_XXX in
+           H-file (this is the value which you will take later in
+           processing and define XXX_LEN as length of method name;
+          then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
+          latter; everything must be capitals
+       */
+       else {
+               /* neither reply, nor any of known method requests, 
+                  let's believe it is an unknown method request
+               */
+               tmp=eat_token_end(buffer,buffer+len);
+               if ((tmp==buffer)||(tmp>=end)){
+                       LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
+                       goto error1;
+               }
+               if (*tmp!=' ') {
+                       LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
+                       goto error1;
+               }
                fl->type=SIP_REQUEST;
+               fl->u.request.method_value=METHOD_OTHER;
+               fl->u.request.method.len=tmp-buffer;
        }
-       
-       offset=l;
-       second=eat_space(tmp, len-offset);
-       offset+=second-tmp;
-       if ((second==tmp)||(tmp>=end)){
-               goto error;
-       }
-       *tmp=0; /* mark the end of the token */
-       fl->u.request.method.s=buffer;
-       fl->u.request.method.len=l;
+
+
+       /* identifying type of message over now; 
+          tmp points at space after; go ahead */
+
+       fl->u.request.method.s=buffer;  /* store ptr to first token */
+       (*tmp)=0;                       /* mark the 1st token end */
+       second=tmp+1;                   /* jump to second token */
+       offset=second-buffer;
+
+/* EoJku */
        
        /* next element */
-       tmp=eat_token(second, len-offset);
+       tmp=eat_token_end(second, second+len-offset);
        if (tmp>=end){
                goto error;
        }
        offset+=tmp-second;
-       third=eat_space(tmp, len-offset);
+       third=eat_space_end(tmp, tmp+len-offset);
        offset+=third-tmp;
        if ((third==tmp)||(tmp>=end)){
                goto error;
@@ -85,20 +121,41 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
        fl->u.request.uri.s=second;
        fl->u.request.uri.len=tmp-second;
 
+       /* jku: parse status code */
+       if (fl->type==SIP_REPLY) {
+               if (fl->u.request.uri.len!=3) {
+                       LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %s\n",
+                               second );
+                       goto error;
+               }
+               s1=*second; s2=*(second+1);s3=*(second+2);
+               if (s1>='0' && s1<='9' && 
+                   s2>='0' && s2<='9' &&
+                   s3>='0' && s3<='9' ) {
+                       fl->u.reply.statusclass=s1-'0';
+                       fl->u.reply.statuscode=fl->u.reply.statusclass*100+10*(s2-'0')+(s3-'0');
+               } else {
+                       LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
+                               second );
+                       goto error;
+               }
+       }
+       /* EoJku */
+
        /*  last part: for a request it must be the version, for a reply
         *  it can contain almost anything, including spaces, so we don't care
         *  about it*/
        if (fl->type==SIP_REQUEST){
-               tmp=eat_token(third,len-offset);
+               tmp=eat_token_end(third,third+len-offset);
                offset+=tmp-third;
                if ((tmp==third)||(tmp>=end)){
                        goto error;
                }
-               if (! is_empty(tmp, len-offset)){
+               if (! is_empty_end(tmp, tmp+len-offset)){
                        goto error;
                }
        }else{
-               tmp=eat_token2(third,len-offset,'\r'); /* find end of line 
+               tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line 
                                                                                                  ('\n' or '\r') */
                if (tmp>=end){ /* no crlf in packet => invalid */
                        goto error;
@@ -240,22 +297,22 @@ char* get_hdr_field(char *buffer, unsigned int len, struct hdr_field*  hdr_f)
                return tmp;
        }
        
-       tmp=eat_token2(buffer, len, ':');
+       tmp=eat_token2_end(buffer, buffer+len, ':');
        if ((tmp==buffer) || (tmp-buffer==len) ||
-               (is_empty(buffer, tmp-buffer))|| (*tmp!=':')){
+               (is_empty_end(buffer, tmp))|| (*tmp!=':')){
                hdr_f->type=HDR_ERROR;
                goto error;
        }
        *tmp=0;
        /* take care of possible spaces (e.g: "Via  :") */
-       tmp2=eat_token(buffer, tmp-buffer);
+       tmp2=eat_token_end(buffer, tmp);
        /* in the worst case tmp2=buffer+tmp-buffer=tmp */
        *tmp2=0;
        l=tmp2-buffer;
        if (tmp2<tmp){
                tmp2++;
                /* catch things like: "Via foo bar:" */
-               tmp2=eat_space(tmp2, tmp-tmp2);
+               tmp2=eat_space_end(tmp2, tmp);
                if (tmp2!=tmp){
                        hdr_f->type=HDR_ERROR;
                        goto error;
@@ -492,33 +549,33 @@ char* parse_via_body(char* buffer,unsigned int len, struct via_body * vb)
 
        name=version=transport=comment=params=hostport=next_via=host.s=0;
        name_len=version_len=transport_len=comment_len=params_len=host.len=0;
-       name=eat_space(buffer, len);
+       name=eat_space_end(buffer, buffer+len);
        if (name-buffer==len) goto error;
        offset=name-buffer;
        tmp=name;
 
-       version=eat_token2(tmp,len-offset,'/');
+       version=eat_token2_end(tmp,tmp+len-offset,'/');
        if (version+1-buffer>=len) goto error;
        *version=0;
        name_len=version-name;
        version++;
        offset+=version-tmp;
        
-       transport=eat_token2(tmp,len-offset,'/');
+       transport=eat_token2_end(tmp,tmp+len-offset,'/');
        if (transport+1-buffer>=len) goto error;
        *transport=0;
        version_len=transport-version;
        transport++;
        offset+=transport-tmp;
        
-       tmp=eat_token(transport,len-offset);
+       tmp=eat_token_end(transport,transport+len-offset);
        if (tmp+1-buffer>=len) goto error;
        *tmp=0;
        transport_len=tmp-transport;
        tmp++;
        offset+=tmp-transport;
        
-       hostport=eat_space(tmp,len-offset);
+       hostport=eat_space_end(tmp,tmp+len-offset);
        if (hostport+1-buffer>=len) goto error;
        offset+=hostport-tmp;
 
index 53bcab7..fbf85df 100644 (file)
@@ -18,7 +18,21 @@ enum {       HDR_EOH=-1, HDR_ERROR=0, HDR_OTHER,
                HDR_MAXFORWARDS, HDR_ROUTE
        };
 
-
+#define INVITE_LEN     6
+#define ACK_LEN                3
+#define CANCEL_LEN     6
+#define BYE_LEN                3
+enum { METHOD_OTHER, METHOD_INVITE, METHOD_CANCEL, METHOD_ACK, METHOD_BYE };
+
+#define IFISMETHOD(methodname,firstchar)                                  \
+if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \
+        strncasecmp( tmp+1, #methodname +1, methodname##_LEN-1)==0 &&     \
+        *(tmp+methodname##_LEN)==' ') {                                   \
+                fl->type=SIP_REQUEST;                                     \
+                fl->u.request.method.len=methodname##_LEN;                \
+                fl->u.request.method_value=METHOD_##methodname;           \
+                tmp=buffer+methodname##_LEN;                              \
+}
 
 
 #define VIA_PARSE_OK   1
@@ -35,11 +49,13 @@ struct msg_start{
                        str method;
                        str uri;
                        str version;
+                       short method_value;
                }request;
                struct {
                        str version;
                        str status;
                        str reason;
+                       unsigned short statusclass, statuscode;
                }reply;
        }u;
 };
index f5af888..d7170f0 100644 (file)
@@ -41,6 +41,9 @@ char* eat_line(char* buffer, unsigned int len)
 
 /* returns pointer to first non  white char or after the end  of the buffer */
 
+/* MACROEATER no more optional */
+
+/*
 #ifndef MACROEATER
 
 char* eat_space(char* buffer, unsigned int len)
@@ -52,7 +55,7 @@ char* eat_space(char* buffer, unsigned int len)
 }
 
 
-/* returns pointer after the token (first whitespace char or CR/LF) */
+// returns pointer after the token (first whitespace char or CR/LF) 
 char* eat_token(char* buffer, unsigned int len)
 {
        char *p;
@@ -65,7 +68,7 @@ char* eat_token(char* buffer, unsigned int len)
 
 
 
-/* returns pointer after the token (first delim char or CR/LF) */
+// returns pointer after the token (first delim char or CR/LF)
 char* eat_token2(char* buffer, unsigned int len, char delim)
 {
        char *p;
@@ -75,18 +78,8 @@ char* eat_token2(char* buffer, unsigned int len, char delim)
                p++);
        return p;
 }
-
-/* EoMACROEATER */
 #endif
+*/
 
+/* EoMACROEATER */
 
-
-/* returns true if line started  at buffer contains only white space */
-int is_empty(char* buffer, unsigned int len)
-{
-       char *p;
-       
-       p=eat_space(buffer, len);
-       if ((p < buffer+len ) && (*p=='\r' || *p=='\n')) return 1;
-       return 0;
-}
index ee1deeb..3884505 100644 (file)
@@ -6,36 +6,47 @@
 #define parser_f_h
 
 char* eat_line(char* buffer, unsigned int len);
+
+/* macro now
 int is_empty(char* buffer, unsigned int len);
+*/
 
-#ifdef MACROEATER
+/* MACROEATER no more optional */
+/* #ifdef MACROEATER */
 
 /* turn the most frequently called functions into macros */
 
 
-#define eat_space(buffer,len)                                          \
-  ( {   char *p;                                                       \
-        for(p=(buffer);(p<(buffer)+(len))&& (*p==' ' || *p=='\t') ;p++);\
+#define eat_space_end(buffer,pend)                                       \
+  ( {   char *p;                                                       \
+        for(p=(buffer);(p<pend)&& (*p==' ' || *p=='\t') ;p++);         \
         p;                                                              \
   } )
 
-#define eat_token(buffer,len)                                          \
-  ( { char *p;                                                         \
-      for (p=(buffer);(p<(buffer)+(len))&&                             \
+#define eat_token_end(buffer,pend)                                     \
+  ( { char *p       ;                                                  \
+      for (p=(buffer);(p<pend)&&                                       \
                         (*p!=' ')&&(*p!='\t')&&(*p!='\n')&&(*p!='\r'); \
                 p++);                                                  \
       p;                                                               \
   } )
 
-#define eat_token2(buffer,len,delim)                                   \
-  ( { char *p;                                                         \
-      for (p=(buffer);(p<(buffer)+(len))&&                             \
+#define eat_token2_end(buffer,pend,delim)                                      \
+  ( { char *p       ;                                                  \
+      for (p=(buffer);(p<pend)&&                                       \
                         (*p!=(delim))&&(*p!='\n')&&(*p!='\r');         \
                 p++);                                                  \
       p;                                                               \
   } )
 
+#define is_empty_end(buffer, pend )                                    \
+  ( { char *p;                                                         \
+      p=eat_space_end( buffer, pend );                                 \
+      ((p<pend ) && (*p=='\r' || *p=='\n')) ? 1 : 0;                   \
+  } )
+
 
+/*
 #else
 
 
@@ -43,7 +54,8 @@ char* eat_space(char* buffer, unsigned int len);
 char* eat_token(char* buffer, unsigned int len);
 char* eat_token2(char* buffer, unsigned int len, char delim);
 
-/* EoMACROEATER */
 #endif
+*/
+/* EoMACROEATER */
 
 #endif
index 1ce69b2..d957713 100644 (file)
--- a/receive.c
+++ b/receive.c
@@ -24,9 +24,8 @@
 int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
 {
        struct sip_msg msg;
-
 #ifdef STATS
-       stats.total_rx++;       
+       int skipped = 1;
 #endif
 
        memset(&msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
@@ -65,8 +64,8 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
                        goto error;
                }
 #ifdef STATS
-               /* jku -- update statistics  */
-               else stats.ok_rx_rq++;  
+               /* jku -- update request statistics  */
+               else update_received_request(  msg.first_line.u.request.method_value );
 #endif
        }else if (msg.first_line.type==SIP_REPLY){
                DBG("msg= reply\n");
@@ -83,7 +82,7 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
 
 #ifdef STATS
                /* jku -- update statistics  */
-               stats.ok_rx_rs++;       
+               update_received_response(  msg.first_line.u.reply.statusclass );
 #endif
                
                /* send the msg */
@@ -93,11 +92,17 @@ int receive_msg(char* buf, unsigned int len, unsigned long src_ip)
                                                (unsigned short) msg.via2.port);
                }
        }
+#ifdef STATS
+       skipped = 0;
+#endif
 skip:
        if (msg.new_uri.s) { free(msg.new_uri.s); msg.new_uri.len=0; }
        if (msg.add_rm) free_lump_list(msg.add_rm);
        if (msg.repl_add_rm) free_lump_list(msg.repl_add_rm);
        free(msg.orig);
+#ifdef STATS
+       if (skipped) update_received_drops;
+#endif
        return 0;
 error:
        if (msg.new_uri.s) free(msg.new_uri.s);
@@ -105,6 +110,9 @@ error:
        if (msg.repl_add_rm) free_lump_list(msg.repl_add_rm);
        free(msg.orig);
 error1:
+#ifdef STATS
+       update_received_drops;
+#endif
        return -1;
 }
 
diff --git a/stats.h b/stats.h
index 22a49b4..153fe9b 100644 (file)
--- a/stats.h
+++ b/stats.h
 #ifndef stats_h
 #define stats_h
 
+#include <ctype.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/utsname.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+
+
 #ifdef STATS
 
+
 struct stats_s {
 
-       /* total/valid, received/sent, request/response */
-       unsigned long   ok_rx_rq,
-                       ok_rx_rs,
-                       ok_tx_rq,
-                       ok_tx_rs,
-                       total_rx,
-                       total_tx;
+       unsigned int    process_index;
+       pid_t           pid;
+       time_t          start_time;
+
+       unsigned long 
+
+       /* received packets */
+
+       received_requests_inv,          /* received_requests */
+       received_requests_ack,
+       received_requests_cnc,
+       received_requests_bye,
+       received_requests_other,
+
+       received_responses_1,           /* received_requests */
+       received_responses_2,
+       received_responses_3,
+       received_responses_4,
+       received_responses_5,
+       received_responses_6,
+       received_responses_other,
+
+       received_drops,                 /* all messages we received and did not process
+                                          successfully; reasons include SIP sanity checks 
+                                          (missing Vias, neither request nor response, 
+                                          failed parsing), ser errors (malloc, action
+                                          failure)
+                                       */
+
+       /* sent */
+
+       /* sent_requests */
+       sent_requests_inv,
+       sent_requests_ack,
+       sent_requests_cnc,
+       sent_requests_bye,
+       sent_requests_other,
+
+       /* sent responses */
+       sent_responses_1,
+       sent_responses_2,
+       sent_responses_3,
+       sent_responses_4,
+       sent_responses_5,
+       sent_responses_6,
+
+       failed_on_send;                 
+                         
 };
 
 
-extern struct stats_s stats;
+extern struct stats_s *stats;
 
-#endif
+void setstats( int child_index );
+void dump_statistic( FILE *fp, struct stats_s *istats );
+int dump_all_statistic();
+int init_stats( int nr_of_processes );
+
+#define _update_request( method, dir )                 \
+       { if (stat_file!=NULL) switch( method ) {       \
+               case METHOD_INVITE: stats->dir##_requests_inv++; break; \
+               case METHOD_ACK: stats->dir##_requests_ack++; break;            \
+               case METHOD_CANCEL: stats->dir##_requests_cnc++; break; \
+               case METHOD_BYE: stats->dir##_requests_bye++; break;            \
+               case METHOD_OTHER: stats->dir##_requests_other++; break;        \
+               default: LOG(L_ERR, "ERROR: unknown method in rq stats (%s)\n", #dir);  \
+               }       \
+        }
+
+#define update_received_request( method ) _update_request( method, received )
+#define update_sent_request( method ) _update_request( method, sent )
+
+#define         _statusline(class, dir )       case class: stats->dir##_responses_##class++; break;
+/*
+#define                statusline( class )     _statusline( class, received )
+#define                statusline2( class )    _statusline( class, sent )
+*/
 
+#define _update_response( statusclass, dir )           \
+        { if (stat_file!=NULL)                          \
+                switch( statusclass ) {                 \
+                        _statusline(1, dir)                   \
+                        _statusline(2, dir)                   \
+                        _statusline(3, dir)                   \
+                        _statusline(4, dir)                   \
+                        _statusline(5, dir)                   \
+                        _statusline(6, dir)                   \
+                        default: LOG(L_INFO, "ERROR: unusual status code received in stats (%s)\n", #dir);    \
+                }       \
+        }
+
+#define update_received_response( statusclass ) _update_response( statusclass, received )
+#define update_sent_response( statusclass ) _update_response( statusclass, sent )
+
+#define update_received_drops  {  stats->received_drops++; }
+#define update_fail_on_send    {  stats->failed_on_send++; }
+
+
+#endif
 #endif
similarity index 78%
rename from test/shoot.cpp
rename to test/shoot.c
index 49791d8..274b00f 100644 (file)
@@ -8,45 +8,23 @@ bouquets and brickbats to farhan@hotfoon.com
 /* changes by jiri@iptel.org; now messages can be really received;
    status code returned is 2 for some local errors , 0 for success
    and 1 for remote error -- ICMP/timeout; can be used to test if
-   a server is alive; 1xx messages are now ignored
+   a server is alive; 1xx messages are now ignored; windows support
+   dropped
 */
 
-/* currently, compiles only for Solaris; Linux returns
- /usr/include/regexp.h:131: cannot convert `char *' to `unsigned char *' 
-*/
-
-int            regerr;
-
-#define INIT         register char *sp = instring;
-#define GETC()       (*sp++)
-#define PEEKC()      (*sp)
-#define UNGETC(c)    (--sp)
-/*#define RETURN(*c)    return; */
-#define RETURN(c)    return c;
-#define ERROR(c)     regerr
-#include <regexp.h>
-
-
+#include <stdlib.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
 #include <string.h>
 #include <ctype.h>
 #include <time.h>
-#include <sys/types.h>
-#include <stdlib.h>
-/* windows specific headers */
-#ifdef WIN32
-#include <windows.h>
-#include <winsock.h>
-#define close(a) closesocket(a)
-#else
-/* *nix specific networking headers */
-#include <sys/time.h>
 #include <unistd.h>
 #include <netdb.h>
-#include <arpa/inet.h>
 #include <sys/socket.h>
-#include <netinet/in.h>
-#endif
+
+#include <regex.h>
+regex_t* regexp;
 
 #define RESIZE         1024
 
@@ -67,8 +45,8 @@ long getaddress(char *host)
 {
        int i, dotcount=0;
        char *p = host;
-       struct hostent          *pent;
-       /* struct sockaddr_in   addr; */ /* see the note on portabilit at the end of the routine */
+       struct hostentpent;
+       long l, *lp;
 
        /*try understanding if this is a valid ip address
        we are skipping the values of the octets specified here.
@@ -106,11 +84,9 @@ long getaddress(char *host)
                exit(2);
        }
 
-       /* PORTABILITY-ISSUE: replacing a costly memcpy call with a hack, may not work on 
-       some systems.  
-       memcpy(&addr.sin_addr, (pent->h_addr), pent->h_length);
-       return addr.sin_addr.s_addr; */
-       return *((long *)(pent->h_addr));
+       lp = (long *) (pent->h_addr);
+       l = *lp;
+       return l;
 }
 
 
@@ -129,18 +105,20 @@ at 5 seconds (5000 milliseconds).
 we are detecting the final response without a '1' as the first
 letter.
 */
-void shoot(char *buff, long address, int port)
+void shoot(char *buff, long address, int lport, int rport )
 {
        struct sockaddr_in      addr;
        /* jku - b  server structures */
        struct sockaddr_in      sockname;
        int ssock;
+       /*
        char compiledre[ RESIZE ];
+       */
        /* jku - e */
        int retryAfter = 500, i, len, ret;
        int     nretries = 10;
        int     sock;
-       timeval tv;
+       struct timeval  tv;
        fd_set  fd;
        char    reply[1600];
 
@@ -160,26 +138,28 @@ void shoot(char *buff, long address, int port)
 
        sockname.sin_family=AF_INET;
        sockname.sin_addr.s_addr = htonl( INADDR_ANY );
-       sockname.sin_port = htons((short)port);
-       if (bind( ssock, (sockaddr *) &sockname, sizeof(sockname) )==-1) {
+       sockname.sin_port = htons((short)lport);
+       if (bind( ssock, (struct sockaddr *) &sockname, sizeof(sockname) )==-1) {
                perror("no bind");
                exit(2);
        }
 
        /* should capture: SIP/2.0 100 Trying */
-       compile("^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", compiledre, &compiledre[RESIZE], '\0');
+       /* compile("^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", compiledre, &compiledre[RESIZE], '\0'); */
+       regexp=(regex_t*)malloc(sizeof(regex_t));
+       regcomp(regexp, "^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ", REG_EXTENDED|REG_NOSUB|REG_ICASE); 
        
 
        /* jku - e */
 
        addr.sin_addr.s_addr = address;
-       addr.sin_port = htons((short)port);
+       addr.sin_port = htons((short)rport);
        addr.sin_family = AF_INET;
        
        /* we connect as per the RFC 2543 recommendations
        modified from sendto/recvfrom */
 
-       ret = connect(sock, (sockaddr *)&addr, sizeof(addr));
+       ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
        if (ret==-1) {
                perror("no connect");
                exit(2);
@@ -241,7 +221,8 @@ void shoot(char *buff, long address, int port)
                        puts("/* reply */");
                        puts(reply);
                        putchar('\n');
-                       if (step( reply, compiledre )) {
+                       /* if (step( reply, compiledre )) { */
+                       if (regexec((regex_t*)regexp, reply, 0, 0, 0)==0) {
                                puts(" provisional received; still waiting for a final response\n ");
                                continue;
                        } else {
@@ -266,21 +247,12 @@ int main(int argc, char *argv[])
        FILE    *pf;
        char    buff[1600];
        int             length;
-       int             port;
-#ifdef WIN32
-       WSADATA wsadata;
-       int err = WSAStartup(0x0101, &wsadata);
-       if (err != 0)
-       {
-               printf("shoot cannot be used as TCP/IP is not available.\n");
-               exit(0);
-       }
-#endif
+       int     lport=0;
+       int     rport=5060;
 
-
-       if (argc != 3 && argc != 4)
+       if (! (argc >= 3 && argc <= 5))
        {
-               puts("usage: shoot file host [port]");
+               puts("usage: shoot file host [rport] [lport]");
                exit(2);
        }
 
@@ -292,14 +264,21 @@ int main(int argc, char *argv[])
        }
 
        /* take the port as 5060 even if it is incorrectly specified */
-       if (argc == 4)
+       if (argc >= 4)
        {
-               port = atoi(argv[3]);
-               if (!port)
-                       port = 5060;
+               rport = atoi(argv[3]);
+               if (!rport) {
+                       puts("error: non-numerical remote port number");
+                       exit(1);
+               }
+               if (argc==5) {
+                       lport=atoi(argv[4]);
+                       if (!lport) {
+                               puts("error: non-numerical local port number");
+                               exit(1);
+                       }
+               }
        }
-       else
-               port = 5060;
 
        /* file is opened in binary mode so that the cr-lf is preserved */
        pf = fopen(argv[1], "rb");
@@ -317,7 +296,7 @@ int main(int argc, char *argv[])
        fclose(pf);
        buff[length] = 0;
 
-       shoot(buff, address, port);
+       shoot(buff, address, lport, rport );
 
        /* visual studio closes the debug console as soon as the 
        program terminates. this is to hold the window from collapsing