Browse code

Merge branch 'master' of https://github.com/kamailio/kamailio

Arsen Semenov authored on 14/10/2020 10:09:41
Showing 37 changed files
... ...
@@ -104,8 +104,15 @@ by the commit, for example:
104 104
   * `modname`: support for foo rfc extension
105 105
     * `usrloc`: support for gruu rfc extension
106 106
   * `lib`: srutils - critical bug fix for abc case
107
+  * `etc`: kamailio.cfg - added core reply route block
108
+  * `misc`: examples/kemi lua - added debug callback function
107 109
   * `kamctl`: added support for management of module xyz
108 110
 
111
+It is acceptable to use slightly different formats, like `etc/kamailio.cfg: ...`
112
+instead of `etc: kamailio.cfg - ...` or `modules/usrloc: ...` instead of
113
+`usrloc: ...`, the important aspect is to indicate the component where the
114
+changes were done.
115
+
109 116
 At the end of the first line some CI flags can be added. Available at this
110 117
 moment:
111 118
 
... ...
@@ -164,7 +171,7 @@ dialplan: basic safety for concurrent rpc reload
164 171
 
165 172
 #### Commit Message Examples ####
166 173
 
167
-  * change to usrloc module from modules
174
+  * changes to usrloc module from modules
168 175
 
169 176
 ```
170 177
 usrloc: fixed name conflict
... ...
@@ -173,7 +180,7 @@ usrloc: fixed name conflict
173 180
   with the usr_avp.h version
174 181
 ```
175 182
 
176
-  * change to core
183
+  * changes to core
177 184
 
178 185
 ```
179 186
 core: loadpath can now use a list of directories
... ...
@@ -183,6 +190,15 @@ core: loadpath can now use a list of directories
183 190
   First match wins (e.g. for loadmodule "textops" if
184 191
   modules/textops.so or modules/textops/textops.so exists, it will
185 192
   be loaded and the search will stop).
193
+```
194
+
195
+  * changes to `etc/kamailio.cfg` file
196
+
197
+```
198
+etc: kamailio.cfg - set load_backends to 1 for permissions module
199
+
200
+- the config uses only address table
201
+
186 202
 ```
187 203
 
188 204
 #### See Also ####
... ...
@@ -150,12 +150,12 @@ import_file "kamailio-local.cfg"
150 150
 
151 151
 # - flags
152 152
 #   FLT_ - per transaction (message) flags
153
-#	FLB_ - per branch flags
154 153
 #!define FLT_ACC 1
155 154
 #!define FLT_ACCMISSED 2
156 155
 #!define FLT_ACCFAILED 3
157 156
 #!define FLT_NATS 5
158 157
 
158
+#	FLB_ - per branch flags
159 159
 #!define FLB_NATB 6
160 160
 #!define FLB_NATSIPPING 7
161 161
 
... ...
@@ -366,6 +366,7 @@ MEMJOIN		"mem_join"
366 366
 MEMSTATUSMODE		"mem_status_mode"
367 367
 CORELOG		"corelog"|"core_log"
368 368
 SIP_PARSER_LOG "sip_parser_log"
369
+SIP_PARSER_MODE "sip_parser_mode"
369 370
 SIP_WARNING sip_warning
370 371
 SERVER_SIGNATURE server_signature
371 372
 SERVER_HEADER server_header
... ...
@@ -817,6 +818,7 @@ IMPORTFILE      "import_file"
817 818
 <INITIAL>{MEMJOIN}	{ count(); yylval.strval=yytext; return MEMJOIN; }
818 819
 <INITIAL>{MEMSTATUSMODE}	{ count(); yylval.strval=yytext; return MEMSTATUSMODE; }
819 820
 <INITIAL>{SIP_PARSER_LOG}  { count(); yylval.strval=yytext; return SIP_PARSER_LOG; }
821
+<INITIAL>{SIP_PARSER_MODE}  { count(); yylval.strval=yytext; return SIP_PARSER_MODE; }
820 822
 <INITIAL>{CORELOG}	{ count(); yylval.strval=yytext; return CORELOG; }
821 823
 <INITIAL>{SIP_WARNING}	{ count(); yylval.strval=yytext; return SIP_WARNING; }
822 824
 <INITIAL>{USER}		{ count(); yylval.strval=yytext; return USER; }
... ...
@@ -391,6 +391,7 @@ extern char *default_routename;
391 391
 %token MEMJOIN
392 392
 %token MEMSTATUSMODE
393 393
 %token SIP_PARSER_LOG
394
+%token SIP_PARSER_MODE
394 395
 %token CORELOG
395 396
 %token SIP_WARNING
396 397
 %token SERVER_SIGNATURE
... ...
@@ -956,6 +957,8 @@ assign_stm:
956 957
 	| MEMSTATUSMODE EQUAL error { yyerror("int value expected"); }
957 958
 	| SIP_PARSER_LOG EQUAL intno { default_core_cfg.sip_parser_log=$3; }
958 959
 	| SIP_PARSER_LOG EQUAL error { yyerror("int value expected"); }
960
+	| SIP_PARSER_MODE EQUAL intno { ksr_sip_parser_mode=$3; }
961
+	| SIP_PARSER_MODE EQUAL error { yyerror("int value expected"); }
959 962
 	| CORELOG EQUAL intno { default_core_cfg.corelog=$3; }
960 963
 	| CORELOG EQUAL error { yyerror("int value expected"); }
961 964
 	| SIP_WARNING EQUAL NUMBER { sip_warning=$3; }
... ...
@@ -214,6 +214,7 @@ extern int ksr_verbose_startup;
214 214
 extern int ksr_route_locks_size;
215 215
 extern str _ksr_xavp_via_params;
216 216
 extern str _ksr_xavp_via_fields;
217
+extern int ksr_sip_parser_mode;
217 218
 
218 219
 extern char *_sr_uri_host_extra_chars;
219 220
 extern unsigned char *_ksr_hname_extra_chars;
... ...
@@ -66,6 +66,8 @@ int via_cnt;
66 66
 /* global request flags */
67 67
 unsigned int global_req_flags = 0;
68 68
 
69
+int ksr_sip_parser_mode = KSR_SIP_PARSER_MODE_STRICT;
70
+
69 71
 /* returns pointer to next header line, and fill hdr_f ;
70 72
  * if at end of header returns pointer to the last crlf  (always buf)*/
71 73
 char* get_hdr_field(char* const buf, char* const end, struct hdr_field* const hdr)
... ...
@@ -169,9 +171,9 @@ char* get_hdr_field(char* const buf, char* const end, struct hdr_field* const hd
169 171
 			hdr->body.len=tmp-hdr->body.s;
170 172
 			DBG("<%.*s> [%d]; uri=[%.*s]\n", hdr->name.len, ZSW(hdr->name.s),
171 173
 					hdr->body.len, to_b->uri.len, ZSW(to_b->uri.s));
172
-			DBG("to body [%.*s], to tag [%.*s]\n", to_b->body.len,
173
-					ZSW(to_b->body.s), to_b->tag_value.len,
174
-					ZSW(to_b->tag_value.s));
174
+			DBG("to body (%d)[%.*s], to tag (%d)[%.*s]\n", to_b->body.len,
175
+					to_b->body.len, ZSW(to_b->body.s), to_b->tag_value.len,
176
+					to_b->tag_value.len, ZSW(to_b->tag_value.s));
175 177
 			break;
176 178
 		case HDR_CONTENTLENGTH_T:
177 179
 			hdr->body.s=tmp;
... ...
@@ -354,7 +356,14 @@ int parse_headers(struct sip_msg* const msg, const hdr_flags_t flags, const int
354 356
 				msg->parsed_flag|=HDR_T2F(hf->type);
355 357
 				break;
356 358
 			case HDR_CALLID_T:
357
-				if (msg->callid==0) msg->callid=hf;
359
+				if (msg->callid==0) {
360
+					msg->callid=hf;
361
+				} else if(ksr_sip_parser_mode & KSR_SIP_PARSER_MODE_STRICT) {
362
+					LOG(cfg_get(core, core_cfg, sip_parser_log),
363
+							"duplicate Call-ID header field [%.*s]\n",
364
+							(end-tmp>100)?100:(int)(end-tmp), tmp);
365
+					goto  error;
366
+				}
358 367
 				msg->parsed_flag|=HDR_CALLID_F;
359 368
 				break;
360 369
 			case HDR_SIPIFMATCH_T:
... ...
@@ -362,15 +371,34 @@ int parse_headers(struct sip_msg* const msg, const hdr_flags_t flags, const int
362 371
 				msg->parsed_flag|=HDR_SIPIFMATCH_F;
363 372
 				break;
364 373
 			case HDR_TO_T:
365
-				if (msg->to==0) msg->to=hf;
374
+				if (msg->to==0) {
375
+					msg->to=hf;
376
+				} else if(ksr_sip_parser_mode & KSR_SIP_PARSER_MODE_STRICT) {
377
+					LOG(cfg_get(core, core_cfg, sip_parser_log),
378
+							"duplicate To header field [%.*s]\n",
379
+							(end-tmp>100)?100:(int)(end-tmp), tmp);
380
+					goto  error;
381
+				}
366 382
 				msg->parsed_flag|=HDR_TO_F;
367 383
 				break;
368 384
 			case HDR_CSEQ_T:
369
-				if (msg->cseq==0) msg->cseq=hf;
385
+				if (msg->cseq==0) {
386
+					msg->cseq=hf;
387
+				} else if(ksr_sip_parser_mode & KSR_SIP_PARSER_MODE_STRICT) {
388
+					ERR("duplicate CSeq header field [%.*s]\n",
389
+						(end-tmp>100)?100:(int)(end-tmp), tmp);
390
+					goto  error;
391
+				}
370 392
 				msg->parsed_flag|=HDR_CSEQ_F;
371 393
 				break;
372 394
 			case HDR_FROM_T:
373
-				if (msg->from==0) msg->from=hf;
395
+				if (msg->from==0) {
396
+					msg->from=hf;
397
+				} else if(ksr_sip_parser_mode & KSR_SIP_PARSER_MODE_STRICT) {
398
+					ERR("duplicate From header field [%.*s]\n",
399
+						(end-tmp>100)?100:(int)(end-tmp), tmp);
400
+					goto  error;
401
+				}
374 402
 				msg->parsed_flag|=HDR_FROM_F;
375 403
 				break;
376 404
 			case HDR_CONTACT_T:
... ...
@@ -378,7 +406,14 @@ int parse_headers(struct sip_msg* const msg, const hdr_flags_t flags, const int
378 406
 				msg->parsed_flag|=HDR_CONTACT_F;
379 407
 				break;
380 408
 			case HDR_MAXFORWARDS_T:
381
-				if(msg->maxforwards==0) msg->maxforwards=hf;
409
+				if(msg->maxforwards==0) {
410
+					msg->maxforwards=hf;
411
+				} else {
412
+					LOG(cfg_get(core, core_cfg, sip_parser_log),
413
+							"duplicate Max-Forwards header field [%.*s]\n",
414
+							(end-tmp>100)?100:(int)(end-tmp), tmp);
415
+					goto  error;
416
+				}
382 417
 				msg->parsed_flag|=HDR_MAXFORWARDS_F;
383 418
 				break;
384 419
 			case HDR_ROUTE_T:
... ...
@@ -394,7 +429,14 @@ int parse_headers(struct sip_msg* const msg, const hdr_flags_t flags, const int
394 429
 				msg->parsed_flag|=HDR_CONTENTTYPE_F;
395 430
 				break;
396 431
 			case HDR_CONTENTLENGTH_T:
397
-				if (msg->content_length==0) msg->content_length = hf;
432
+				if (msg->content_length==0) {
433
+					msg->content_length = hf;
434
+				} else if(ksr_sip_parser_mode & KSR_SIP_PARSER_MODE_STRICT) {
435
+					LOG(cfg_get(core, core_cfg, sip_parser_log),
436
+							"duplicate Content-Length header field [%.*s]\n",
437
+							(end-tmp>100)?100:(int)(end-tmp), tmp);
438
+					goto  error;
439
+				}
398 440
 				msg->parsed_flag|=HDR_CONTENTLENGTH_F;
399 441
 				break;
400 442
 			case HDR_AUTHORIZATION_T:
... ...
@@ -571,7 +613,10 @@ skip:
571 613
 
572 614
 error:
573 615
 	ser_error=E_BAD_REQ;
574
-	if (hf) pkg_free(hf);
616
+	if (hf) {
617
+		clean_hdr_field(hf);
618
+		pkg_free(hf);
619
+	}
575 620
 	/* restore original flags */
576 621
 	msg->parsed_flag |= orig_flag;
577 622
 	return -1;
... ...
@@ -127,6 +127,10 @@ typedef enum request_method {
127 127
 #define FL_MTU_FB_MASK  (FL_MTU_TCP_FB|FL_MTU_TLS_FB|FL_MTU_SCTP_FB)
128 128
 
129 129
 
130
+/* sip parser mode flags (1<<n) */
131
+#define KSR_SIP_PARSER_MODE_NONE 0
132
+#define KSR_SIP_PARSER_MODE_STRICT 1
133
+
130 134
 #define IFISMETHOD(methodname,firstchar)                                  \
131 135
 if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \
132 136
 		strncasecmp( tmp+1, &#methodname[1], methodname##_LEN-1)==0 &&     \
... ...
@@ -137,28 +141,26 @@ if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \
137 141
 				tmp=buffer+methodname##_LEN;                              \
138 142
 }
139 143
 
140
-#define IS_HTTP(req)                                                \
141
-	((req)->first_line.u.request.version.len >= HTTP_VERSION_LEN && \
142
-	!strncasecmp((req)->first_line.u.request.version.s,             \
143
-		HTTP_VERSION, HTTP_VERSION_LEN))
144
-
145
-#define IS_SIP(req)                                                \
146
-	((req)->first_line.u.request.version.len >= SIP_VERSION_LEN && \
147
-	!strncasecmp((req)->first_line.u.request.version.s,             \
148
-		SIP_VERSION, SIP_VERSION_LEN))
149
-
150
-#define IS_HTTP_REPLY(rpl)                                                \
151
-	(((rpl)->first_line.u.reply.version.len >= HTTP_VERSION_LEN && \
152
-	!strncasecmp((rpl)->first_line.u.reply.version.s,             \
153
-		HTTP_VERSION, HTTP_VERSION_LEN)) ||                         \
154
-	((rpl)->first_line.u.reply.version.len >= HTTP2_VERSION_LEN && \
155
-	!strncasecmp((rpl)->first_line.u.reply.version.s,             \
156
-		HTTP2_VERSION, HTTP2_VERSION_LEN)))
157
-
158
-#define IS_SIP_REPLY(rpl)                                                \
159
-	((rpl)->first_line.u.reply.version.len >= SIP_VERSION_LEN && \
160
-	!strncasecmp((rpl)->first_line.u.reply.version.s,             \
161
-		SIP_VERSION, SIP_VERSION_LEN))
144
+
145
+/* sip request */
146
+#define IS_SIP(req)                                     \
147
+	(((req)->first_line.type == SIP_REQUEST) &&           \
148
+	((req)->first_line.type & FLINE_FLAG_PROTO_SIP))
149
+
150
+/* sip reply */
151
+#define IS_SIP_REPLY(rpl)                               \
152
+	(((rpl)->first_line.type == SIP_REPLY) &&             \
153
+	((rpl)->first_line.type & FLINE_FLAG_PROTO_SIP))
154
+
155
+/* http request */
156
+#define IS_HTTP(req)                                    \
157
+	(((req)->first_line.type == SIP_REQUEST) &&           \
158
+	((req)->first_line.type & FLINE_FLAG_PROTO_HTTP))
159
+
160
+/* http reply */
161
+#define IS_HTTP_REPLY(rpl)                              \
162
+	(((rpl)->first_line.type == SIP_REPLY) &&             \
163
+	((rpl)->first_line.type & FLINE_FLAG_PROTO_HTTP))
162 164
 
163 165
 /*! \brief
164 166
  * Return a URI to which the message should be really sent (not what should
... ...
@@ -1,6 +1,6 @@
1 1
 /*
2
- * sip first line parsing automaton
3
- * 
2
+ * message first line parsing automaton
3
+ *
4 4
  * Copyright (C) 2001-2003 FhG Fokus
5 5
  *
6 6
  * This file is part of Kamailio, a free SIP server.
... ...
@@ -15,8 +15,8 @@
15 15
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 16
  * GNU General Public License for more details.
17 17
  *
18
- * You should have received a copy of the GNU General Public License 
19
- * along with this program; if not, write to the Free Software 
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20 20
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 21
  *
22 22
  */
... ...
@@ -35,25 +35,21 @@
35 35
 #include "../mem/mem.h"
36 36
 #include "../ut.h"
37 37
 
38
-/* flags for first line
39
- * - stored on a short field (16 flags) */
40
-#define FLINE_FLAG_PROTO_SIP	(1<<0)
41
-#define FLINE_FLAG_PROTO_HTTP	(1<<1)
42 38
 
43 39
 int http_reply_parse = 0;
44 40
 
45 41
 /* grammar:
46
-	request  =  method SP uri SP version CRLF
47
-	response =  version SP status  SP reason  CRLF
48
-	(version = "SIP/2.0")
42
+ *  request  =  method SP uri SP version CRLF
43
+ *  response =  version SP status  SP reason  CRLF
44
+ *  (version = "SIP/2.0")
49 45
 */
50 46
 
51 47
 
52 48
 /* parses the first line, returns pointer to  next line  & fills fl;
53
-   also  modifies buffer (to avoid extra copy ops) */
49
+ * also  modifies buffer (to avoid extra copy ops) */
54 50
 char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
55 51
 {
56
-	
52
+
57 53
 	char *tmp;
58 54
 	char* second;
59 55
 	char* third;
... ...
@@ -67,10 +63,9 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
67 63
 
68 64
 	/* grammar:
69 65
 		request  =  method SP uri SP version CRLF
70
-		response =  version SP status  SP reason  CRLF
66
+		response =  version SP status SP reason CRLF
71 67
 		(version = "SIP/2.0")
72 68
 	*/
73
-	
74 69
 
75 70
 	memset(fl, 0, sizeof(struct msg_start));
76 71
 	offset = 0;
... ...
@@ -80,48 +75,45 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
80 75
 	/* jku  -- parse well-known methods */
81 76
 
82 77
 	/* drop messages which are so short they are for sure useless;
83
-           utilize knowledge of minimum size in parsing the first
84
-	   token 
85
-        */
78
+	 * utilize knowledge of minimum size in parsing the first token */
86 79
 	if (len <=16 ) {
87
-		LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len);
80
+		LM_INFO("message too short: %d [%.*s]\n", len, len, buffer);
88 81
 		goto error1;
89 82
 	}
90 83
 	tmp=buffer;
91
-  	/* is it perhaps a reply, ie does it start with "SIP...." ? */
92
-	if ( 	(*tmp=='S' || *tmp=='s') && 
93
-		strncasecmp( tmp+1, &SIP_VERSION[1], SIP_VERSION_LEN-1)==0 &&
94
-		(*(tmp+SIP_VERSION_LEN)==' ')) {
95
-			fl->type=SIP_REPLY;
96
-			fl->flags|=FLINE_FLAG_PROTO_SIP;
97
-			fl->u.reply.version.len=SIP_VERSION_LEN;
98
-			tmp=buffer+SIP_VERSION_LEN;
84
+	/* is it perhaps a reply, ie does it start with "SIP...." ? */
85
+	if ( (*tmp=='S' || *tmp=='s')
86
+			&& strncasecmp( tmp+1, &SIP_VERSION[1], SIP_VERSION_LEN-1)==0
87
+			&& (*(tmp+SIP_VERSION_LEN)==' ')) {
88
+		fl->type=SIP_REPLY;
89
+		fl->flags|=FLINE_FLAG_PROTO_SIP;
90
+		fl->u.reply.version.len=SIP_VERSION_LEN;
91
+		tmp=buffer+SIP_VERSION_LEN;
99 92
 	} else if (http_reply_parse != 0 && (*tmp=='H' || *tmp=='h')) {
100
-			/* 'HTTP/1.' */
101
-			if (strncasecmp( tmp+1, &HTTP_VERSION[1], HTTP_VERSION_LEN-1)==0 &&
102
-			  /* [0|1] */
103
-			  ((*(tmp+HTTP_VERSION_LEN)=='0') || (*(tmp+HTTP_VERSION_LEN)=='1')) &&
104
-			  (*(tmp+HTTP_VERSION_LEN+1)==' ')  ){ 
105
-			    /* ugly hack to be able to route http replies
106
-			    * Note: - the http reply must have a via
107
-			    *       - the message is marked as SIP_REPLY (ugly)
108
-			    */
109
-				  fl->type=SIP_REPLY;
110
-				  fl->flags|=FLINE_FLAG_PROTO_HTTP;
111
-				  fl->u.reply.version.len=HTTP_VERSION_LEN+1 /*include last digit*/;
112
-          tmp=buffer+HTTP_VERSION_LEN+1 /* last digit */;
113
-			/* 'HTTP/2' */
114
-			} else if (strncasecmp( tmp+1, &HTTP2_VERSION[1], HTTP2_VERSION_LEN-1)==0 &&
115
-						(*(tmp+HTTP2_VERSION_LEN)==' ')) {
116
-					fl->type=SIP_REPLY;
117
-					fl->flags|=FLINE_FLAG_PROTO_HTTP;
118
-					fl->u.reply.version.len=HTTP2_VERSION_LEN;
119
-					tmp=buffer+HTTP2_VERSION_LEN;
120
-			}
93
+		/* 'HTTP/1.[0|1]' */
94
+		if (strncasecmp( tmp+1, &HTTP_VERSION[1], HTTP_VERSION_LEN-1)==0 &&
95
+				((*(tmp+HTTP_VERSION_LEN)=='0') || (*(tmp+HTTP_VERSION_LEN)=='1'))
96
+				&& (*(tmp+HTTP_VERSION_LEN+1)==' ')  ){
97
+			/* hack to be able to route http replies
98
+			 * Note: - the http reply must have a via
99
+			 *       - the message is marked as SIP_REPLY (ugly)
100
+			 */
101
+			fl->type=SIP_REPLY;
102
+			fl->flags|=FLINE_FLAG_PROTO_HTTP;
103
+			fl->u.reply.version.len=HTTP_VERSION_LEN+1 /*include last digit*/;
104
+			tmp=buffer+HTTP_VERSION_LEN+1 /* last digit */;
105
+		/* 'HTTP/2' */
106
+		} else if (strncasecmp( tmp+1, &HTTP2_VERSION[1], HTTP2_VERSION_LEN-1)==0
107
+				&& (*(tmp+HTTP2_VERSION_LEN)==' ')) {
108
+			fl->type=SIP_REPLY;
109
+			fl->flags|=(FLINE_FLAG_PROTO_HTTP | FLINE_FLAG_PROTO_HTTP2);
110
+			fl->u.reply.version.len=HTTP2_VERSION_LEN;
111
+			tmp=buffer+HTTP2_VERSION_LEN;
112
+		}
121 113
 	} else IFISMETHOD( INVITE, 'I' )
122 114
 	else IFISMETHOD( CANCEL, 'C')
123 115
 	else IFISMETHOD( ACK, 'A' )
124
-	else IFISMETHOD( BYE, 'B' ) 
116
+	else IFISMETHOD( BYE, 'B' )
125 117
 	else IFISMETHOD( INFO, 'I' )
126 118
 	else IFISMETHOD( REGISTER, 'R')
127 119
 	else IFISMETHOD( SUBSCRIBE, 'S')
... ...
@@ -138,22 +130,21 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
138 130
 	else IFISMETHOD( PUT, 'P')
139 131
 	else IFISMETHOD( DELETE, 'D')
140 132
 	/* if you want to add another method XXX, include METHOD_XXX in
141
-           H-file (this is the value which you will take later in
142
-           processing and define XXX_LEN as length of method name;
143
-	   then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
144
-	   latter; everything must be capitals
133
+	 * H-file (this is the value which you will take later in
134
+	 * processing and define XXX_LEN as length of method name;
135
+	 * then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
136
+	 * latter; everything must be capitals
145 137
 	*/
146 138
 	else {
147
-		/* neither reply, nor any of known method requests, 
148
-		   let's believe it is an unknown method request
149
-        	*/
139
+		/* neither reply, nor any of known method requests,
140
+		 * let's believe it is an unknown method request */
150 141
 		tmp=eat_token_end(buffer,buffer+len);
151 142
 		if ((tmp==buffer)||(tmp>=end)){
152
-			LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
143
+			LM_INFO("empty or bad first line\n");
153 144
 			goto error1;
154 145
 		}
155 146
 		if (*tmp!=' ') {
156
-			LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
147
+			LM_INFO("method not followed by SP\n");
157 148
 			goto error1;
158 149
 		}
159 150
 		fl->type=SIP_REQUEST;
... ...
@@ -162,15 +153,15 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
162 153
 	}
163 154
 
164 155
 
165
-	/* identifying type of message over now; 
166
-	   tmp points at space after; go ahead */
156
+	/* identifying type of message over now;
157
+	 * tmp points at space after; go ahead */
167 158
 
168 159
 	fl->u.request.method.s=buffer;  /* store ptr to first token */
169 160
 	second=tmp+1;			/* jump to second token */
170 161
 	offset=second-buffer;
171 162
 
172
-/* EoJku */
173
-	
163
+	/* EoJku */
164
+
174 165
 	/* next element */
175 166
 	tmp=eat_token_end(second, second+len-offset);
176 167
 	if (tmp>=end){
... ...
@@ -188,18 +179,18 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
188 179
 	/* jku: parse status code */
189 180
 	if (fl->type==SIP_REPLY) {
190 181
 		if (fl->u.request.uri.len!=3) {
191
-			LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %.*s\n",
192
-				fl->u.request.uri.len, ZSW(second) );
182
+			LM_INFO("len(status code)!=3: %.*s\n",
183
+					fl->u.request.uri.len, ZSW(second) );
193 184
 			goto error;
194 185
 		}
195 186
 		s1=*second; s2=*(second+1);s3=*(second+2);
196
-		if (s1>='0' && s1<='9' && 
197
-		    s2>='0' && s2<='9' &&
198
-		    s3>='0' && s3<='9' ) {
187
+		if (s1>='0' && s1<='9'
188
+				&& s2>='0' && s2<='9'
189
+				&& s3>='0' && s3<='9' ) {
199 190
 			fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0');
200 191
 		} else {
201
-			LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %.*s\n",
202
-				fl->u.request.uri.len, ZSW(second) );
192
+			LM_INFO("status code non-numerical: %.*s\n",
193
+					fl->u.request.uri.len, ZSW(second) );
203 194
 			goto error;
204 195
 		}
205 196
 	}
... ...
@@ -218,8 +209,8 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
218 209
 			goto error;
219 210
 		}
220 211
 	}else{
221
-		tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line 
222
-												  ('\n' or '\r') */
212
+		/* find end of line ('\n' or '\r') */
213
+		tmp=eat_token2_end(third,third+len-offset,'\r');
223 214
 		if (tmp>=end){ /* no crlf in packet => invalid */
224 215
 			goto error;
225 216
 		}
... ...
@@ -240,35 +231,45 @@ char* parse_first_line(char* buffer, unsigned int len, struct msg_start* fl)
240 231
 				&& !strncasecmp(fl->u.request.version.s+1,
241 232
 					&SIP_VERSION[1], SIP_VERSION_LEN-1)) {
242 233
 			fl->flags|=FLINE_FLAG_PROTO_SIP;
243
-		} else if(fl->u.request.version.len >= HTTP_VERSION_LEN
234
+		} else if(fl->u.request.version.len >= 4
244 235
 				&& (fl->u.request.version.s[0]=='H'
245
-					|| fl->u.request.version.s[0]=='h')
246
-				&& !strncasecmp(fl->u.request.version.s+1,
247
-					&HTTP_VERSION[1], HTTP_VERSION_LEN-1)) {
248
-			fl->flags|=FLINE_FLAG_PROTO_HTTP;
236
+					|| fl->u.request.version.s[0]=='h')) {
237
+			if(fl->u.request.version.len >= HTTP_VERSION_LEN
238
+					&& !strncasecmp(fl->u.request.version.s+1,
239
+						&HTTP_VERSION[1], HTTP_VERSION_LEN-1)) {
240
+				fl->flags|=FLINE_FLAG_PROTO_HTTP;
241
+			} else if(fl->u.request.version.len >= HTTP2_VERSION_LEN
242
+					&& !strncasecmp(fl->u.request.version.s+1,
243
+						&HTTP2_VERSION[1], HTTP2_VERSION_LEN-1)) {
244
+				fl->flags|=(FLINE_FLAG_PROTO_HTTP | FLINE_FLAG_PROTO_HTTP2);
245
+			}
249 246
 		}
250 247
 	}
251 248
 
249
+	LM_DBG("first line type %d (%s) flags %d\n", (int)fl->type,
250
+		(fl->type==SIP_REPLY)?"reply(status)":"request", (int)fl->flags);
251
+
252 252
 	return nl;
253 253
 
254 254
 error:
255
-	LOG(L_DBG, "parse_first_line: bad %s first line\n",
256
-		(fl->type==SIP_REPLY)?"reply(status)":"request");
255
+	LM_DBG("bad %s first line\n",
256
+			(fl->type==SIP_REPLY)?"reply(status)":"request");
257 257
 
258
-	LOG(L_DBG, "at line 0 char %d: \n", offset );
258
+	LM_DBG("at line 0 char %d: \n", offset );
259 259
 	prn=pkg_malloc( offset );
260 260
 	if (prn) {
261 261
 		for (t=0; t<offset; t++)
262 262
 			if (*(buffer+t)) *(prn+t)=*(buffer+t);
263 263
 			else *(prn+t)=(char)176; /* '�' */
264
-		LOG(L_DBG, "parsed so far: %.*s\n", offset, ZSW(prn) );
264
+		LM_DBG("parsed so far: %.*s\n", offset, ZSW(prn) );
265 265
 		pkg_free( prn );
266 266
 	} else {
267 267
 		PKG_MEM_ERROR;
268 268
 	}
269 269
 error1:
270 270
 	fl->type=SIP_INVALID;
271
-	LOG(cfg_get(core, core_cfg, sip_parser_log), "parse_first_line: bad message (offset: %d)\n", offset);
271
+	LOG(cfg_get(core, core_cfg, sip_parser_log),
272
+			"parse_first_line: bad message (offset: %d)\n", offset);
272 273
 	/* skip  line */
273 274
 	nl=eat_line(buffer,len);
274 275
 	return nl;
... ...
@@ -34,14 +34,24 @@
34 34
 
35 35
 #include "../str.h"
36 36
 
37
+
38
+/* Invalid message */
39
+#define SIP_INVALID 0
40
+#define MSG_INVALID 0
41
+
37 42
 /* Message is request */
38 43
 #define SIP_REQUEST 1
44
+#define MSG_REQUEST 1
39 45
 
40 46
 /* Message is reply */
41 47
 #define SIP_REPLY   2
48
+#define MSG_REPLY   2
42 49
 
43
-/* Invalid message */
44
-#define SIP_INVALID 0
50
+/* flags for first line
51
+ * - stored on a short field (16 flags) */
52
+#define FLINE_FLAG_PROTO_SIP	(1<<0) /* sip 2.0 protocol */
53
+#define FLINE_FLAG_PROTO_HTTP	(1<<1) /* any http protocol */
54
+#define FLINE_FLAG_PROTO_HTTP2	(1<<2) /* additional for http 2 */
45 55
 
46 56
 #define SIP_VERSION "SIP/2.0"
47 57
 #define SIP_VERSION_LEN 7
... ...
@@ -85,7 +95,7 @@ typedef struct msg_start {
85 95
 			str method;			/*!< Method string */
86 96
 			str uri;			/*!< Request URI */
87 97
 			str version;		/*!< SIP version */
88
-			int method_value;
98
+			int method_value;	/*!< Method id value */
89 99
 		} request;
90 100
 		struct {
91 101
 			str version;		/*!< SIP version */
... ...
@@ -27,6 +27,7 @@
27 27
 #include <stdlib.h>
28 28
 #include <string.h>
29 29
 #include <ctype.h>
30
+#include "../ut.h"
30 31
 #include "../mem/mem.h"
31 32
 #include "parse_def.h"
32 33
 #include "parse_identityinfo.h"
... ...
@@ -59,8 +59,6 @@ enum {
59 59
 	II_M_TOKEN
60 60
 };
61 61
 
62
-#define ZSW(_c) ((_c)?(_c):"")
63
-
64 62
 struct identityinfo_body {
65 63
 	int error;  	/* Error code */
66 64
 	str uri;    	/* URI */
... ...
@@ -95,6 +95,7 @@
95 95
 #include "tcp_info.h"
96 96
 #include "tcp_options.h"
97 97
 #include "ut.h"
98
+#include "events.h"
98 99
 #include "cfg/cfg_struct.h"
99 100
 
100 101
 #include <fcntl.h> /* must be included after io_wait.h if SIGIO_RT is used */
... ...
@@ -5135,4 +5136,88 @@ void tcp_get_info(struct tcp_gen_info *ti)
5135 5136
 #endif /* TCP_ASYNC */
5136 5137
 }
5137 5138
 
5139
+
5140
+/* finds an ws/wss tcpconn & sends on it
5141
+ * uses the dst members to, proto (ws/wss) and id and tries to send
5142
+ * returns: number of bytes written (>=0) on success
5143
+ *          <0 on error */
5144
+int wss_send(dest_info_t* dst, const char* buf, unsigned len)
5145
+{
5146
+	int port;
5147
+	struct ip_addr ip;
5148
+	union sockaddr_union* from = NULL;
5149
+	union sockaddr_union local_addr;
5150
+	struct tcp_connection *con = NULL;
5151
+	struct ws_event_info wsev;
5152
+	sr_event_param_t evp = {0};
5153
+	int ret;
5154
+
5155
+	if (unlikely((dst->proto == PROTO_WS
5156
+#ifdef USE_TLS
5157
+					|| dst->proto == PROTO_WSS
5138 5158
 #endif
5159
+				) && sr_event_enabled(SREV_TCP_WS_FRAME_OUT))) {
5160
+		if (unlikely(dst->send_flags.f & SND_F_FORCE_SOCKET
5161
+					&& dst->send_sock)) {
5162
+
5163
+			local_addr = dst->send_sock->su;
5164
+#ifdef SO_REUSEPORT
5165
+			if (cfg_get(tcp, tcp_cfg, reuse_port)) {
5166
+				LM_DBG("sending to: %s, force_socket=%d, send_sock=%p\n",
5167
+						su2a(&dst->to,sizeof(struct sockaddr_in)),
5168
+						(dst->send_flags.f & SND_F_FORCE_SOCKET),
5169
+						dst->send_sock);
5170
+
5171
+				su_setport(&local_addr, dst->send_sock->port_no);
5172
+			}
5173
+			else
5174
+				su_setport(&local_addr, 0); /* any local port will do */
5175
+#else
5176
+			su_setport(&local_addr, 0); /* any local port will do */
5177
+#endif
5178
+			from = &local_addr;
5179
+		}
5180
+
5181
+		port = su_getport(&dst->to);
5182
+		if (likely(port)) {
5183
+			su2ip_addr(&ip, &dst->to);
5184
+			if(tcp_connection_match==TCPCONN_MATCH_STRICT) {
5185
+				con = tcpconn_lookup(dst->id, &ip, port, from,
5186
+						(dst->send_sock)?dst->send_sock->port_no:0, 0);
5187
+			} else {
5188
+				con = tcpconn_get(dst->id, &ip, port, from, 0);
5189
+			}
5190
+		}
5191
+		else if (likely(dst->id))
5192
+			con = tcpconn_get(dst->id, 0, 0, 0, 0);
5193
+		else {
5194
+			LM_CRIT("null_id & to\n");
5195
+			goto error;
5196
+		}
5197
+
5198
+		if (con == NULL) {
5199
+			LM_WARN("TCP/TLS connection for WebSocket could not be found\n");
5200
+			goto error;
5201
+		}
5202
+
5203
+		memset(&wsev, 0, sizeof(ws_event_info_t));
5204
+		wsev.type = SREV_TCP_WS_FRAME_OUT;
5205
+		wsev.buf = (char*)buf;
5206
+		wsev.len = len;
5207
+		wsev.id = con->id;
5208
+		evp.data = (void *)&wsev;
5209
+		ret = sr_event_exec(SREV_TCP_WS_FRAME_OUT, &evp);
5210
+		tcpconn_put(con);
5211
+		goto done;
5212
+	} else {
5213
+		LM_CRIT("used with invalid proto %d\n", dst->proto);
5214
+		goto error;
5215
+	}
5216
+
5217
+done:
5218
+	return ret;
5219
+error:
5220
+	return -1;
5221
+}
5222
+
5223
+#endif /* USE_TCP */
... ...
@@ -13,8 +13,8 @@
13 13
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 14
  * GNU General Public License for more details.
15 15
  *
16
- * You should have received a copy of the GNU General Public License 
17
- * along with this program; if not, write to the Free Software 
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program; if not, write to the Free Software
18 18
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 19
  */
20 20
 
... ...
@@ -33,7 +33,7 @@ int tcp_send(struct dest_info* dst, union sockaddr_union* from,
33 33
 int tcpconn_add_alias(int id, int port, int proto);
34 34
 
35 35
 
36
-
36
+int wss_send(dest_info_t* dst, const char* buf, unsigned len);
37 37
 
38 38
 
39 39
 #endif
... ...
@@ -35,10 +35,11 @@ Daniel-Constantin Mierla
35 35
 
36 36
               4.1. crypto_aes_encrypt(text, key, res)
37 37
               4.2. crypto_aes_decrypt(text, key, res)
38
-              4.3. crypto_netio_in)
39
-              4.4. crypto_netio_out()
40
-              4.5. crypto_netio_encrypt()
41
-              4.6. crypto_netio_decrypt()
38
+              4.3. crypto_hmac_sha256(text, key, res)
39
+              4.4. crypto_netio_in)
40
+              4.5. crypto_netio_out()
41
+              4.6. crypto_netio_encrypt()
42
+              4.7. crypto_netio_decrypt()
42 43
 
43 44
         5. Event Routes
44 45
 
... ...
@@ -53,11 +54,12 @@ Daniel-Constantin Mierla
53 54
    1.5. Set netio_key parameter
54 55
    1.6. crypto_aes_encrypt usage
55 56
    1.7. crypto_aes_decrypt usage
56
-   1.8. crypto_netio_in usage
57
-   1.9. crypto_netio_out usage
58
-   1.10. crypto_netio_encrypt usage
59
-   1.11. crypto_netio_decrypt usage
60
-   1.12. event_route[crypto:netio] usage
57
+   1.8. crypto_hmac_sha256 usage
58
+   1.9. crypto_netio_in usage
59
+   1.10. crypto_netio_out usage
60
+   1.11. crypto_netio_encrypt usage
61
+   1.12. crypto_netio_decrypt usage
62
+   1.13. event_route[crypto:netio] usage
61 63
 
62 64
 Chapter 1. Admin Guide
63 65
 
... ...
@@ -81,10 +83,11 @@ Chapter 1. Admin Guide
81 83
 
82 84
         4.1. crypto_aes_encrypt(text, key, res)
83 85
         4.2. crypto_aes_decrypt(text, key, res)
84
-        4.3. crypto_netio_in)
85
-        4.4. crypto_netio_out()
86
-        4.5. crypto_netio_encrypt()
87
-        4.6. crypto_netio_decrypt()
86
+        4.3. crypto_hmac_sha256(text, key, res)
87
+        4.4. crypto_netio_in)
88
+        4.5. crypto_netio_out()
89
+        4.6. crypto_netio_encrypt()
90
+        4.7. crypto_netio_decrypt()
88 91
 
89 92
    5. Event Routes
90 93
 
... ...
@@ -199,10 +202,11 @@ modparam("crypto", "netio_key", "strong-password-here")
199 202
 
200 203
    4.1. crypto_aes_encrypt(text, key, res)
201 204
    4.2. crypto_aes_decrypt(text, key, res)
202
-   4.3. crypto_netio_in)
203
-   4.4. crypto_netio_out()
204
-   4.5. crypto_netio_encrypt()
205
-   4.6. crypto_netio_decrypt()
205
+   4.3. crypto_hmac_sha256(text, key, res)
206
+   4.4. crypto_netio_in)
207
+   4.5. crypto_netio_out()
208
+   4.6. crypto_netio_encrypt()
209
+   4.7. crypto_netio_decrypt()
206 210
 
207 211
 4.1.  crypto_aes_encrypt(text, key, res)
208 212
 
... ...
@@ -232,14 +236,29 @@ crypto_aes_encrypt("$rb", "my-secret-key", "$var(encrypted)");
232 236
 crypto_aes_decrypt("$var(encrypted)", "my-secret-key", "$var(text)");
233 237
 ...
234 238
 
235
-4.3.  crypto_netio_in)
239
+4.3.  crypto_hmac_sha256(text, key, res)
240
+
241
+   Calculates HMAC (keyed-hash message authentication code) with SHA256 as
242
+   a cryptographic hash function. The result is encoded in base64 url
243
+   encoded format and stored in res. The parameter res must be a
244
+   read-write variable. The parameters text and key can be static strings
245
+   or strings with variables (dynamic strings).
246
+
247
+   This function can be used from ANY_ROUTE.
248
+
249
+   Example 1.8. crypto_hmac_sha256 usage
250
+...
251
+crypto_hmac_sha256("$var(text)", "my-secret-key", "$var(hmac)");
252
+...
253
+
254
+4.4.  crypto_netio_in)
236 255
 
237 256
    Return 1 (true) if it is an incoming net message, or -1 (false)
238 257
    otherwise.
239 258
 
240 259
    This function can be used from EVENT_ROUTE.
241 260
 
242
-   Example 1.8. crypto_netio_in usage
261
+   Example 1.9. crypto_netio_in usage
243 262
 ...
244 263
 event_route[crypto:netio] {
245 264
   if(crypto_netio_in()) {
... ...
@@ -247,14 +266,14 @@ event_route[crypto:netio] {
247 266
   }
248 267
 ...
249 268
 
250
-4.4.  crypto_netio_out()
269
+4.5.  crypto_netio_out()
251 270
 
252 271
    Return 1 (true) if it is an outgoing net message, or -1 (false)
253 272
    otherwise.
254 273
 
255 274
    This function can be used from EVENT_ROUTE.
256 275
 
257
-   Example 1.9. crypto_netio_out usage
276
+   Example 1.10. crypto_netio_out usage
258 277
 ...
259 278
 event_route[crypto:netio] {
260 279
   if(crypto_netio_out()) {
... ...
@@ -262,13 +281,13 @@ event_route[crypto:netio] {
262 281
   }
263 282
 ...
264 283
 
265
-4.5.  crypto_netio_encrypt()
284
+4.6.  crypto_netio_encrypt()
266 285
 
267 286
    Mark the network message for encryption.
268 287
 
269 288
    This function can be used from EVENT_ROUTE.
270 289
 
271
-   Example 1.10. crypto_netio_encrypt usage
290
+   Example 1.11. crypto_netio_encrypt usage
272 291
 ...
273 292
 event_route[crypto:netio] {
274 293
   if(crypto_netio_out()) {
... ...
@@ -276,13 +295,13 @@ event_route[crypto:netio] {
276 295
   }
277 296
 ...
278 297
 
279
-4.6.  crypto_netio_decrypt()
298
+4.7.  crypto_netio_decrypt()
280 299
 
281 300
    Mark the network message for decryption.
282 301
 
283 302
    This function can be used from EVENT_ROUTE.
284 303
 
285
-   Example 1.11. crypto_netio_decrypt usage
304
+   Example 1.12. crypto_netio_decrypt usage
286 305
 ...
287 306
 event_route[crypto:netio] {
288 307
   if(crypto_netio_in()) {
... ...
@@ -296,7 +315,7 @@ event_route[crypto:netio] {
296 315
 
297 316
 5.1.  event_route[crypto:netio]
298 317
 
299
-   Example 1.12. event_route[crypto:netio] usage
318
+   Example 1.13. event_route[crypto:netio] usage
300 319
 ...
301 320
 # ----- crypto params -----
302 321
 modparam("crypto", "register_evcb", 1)
... ...
@@ -38,6 +38,9 @@
38 38
 #include "crypto_evcb.h"
39 39
 #include "api.h"
40 40
 
41
+#include <openssl/hmac.h>
42
+
43
+
41 44
 MODULE_VERSION
42 45
 
43 46
 int crypto_aes_init(unsigned char *key_data, int key_data_len,
... ...
@@ -61,6 +64,9 @@ static int w_crypto_nio_out(sip_msg_t* msg, char* p1, char* p2);
61 64
 static int w_crypto_nio_encrypt(sip_msg_t* msg, char* p1, char* p2);
62 65
 static int w_crypto_nio_decrypt(sip_msg_t* msg, char* p1, char* p2);
63 66
 
67
+static int w_crypto_hmac_sha256(sip_msg_t* msg, char* inb, char* keyb, char* outb);
68
+static int fixup_crypto_hmac(void** param, int param_no);
69
+
64 70
 static char *_crypto_salt_param = "k8hTm4aZ";
65 71
 
66 72
 static int _crypto_register_callid = 0;
... ...
@@ -82,6 +88,8 @@ static cmd_export_t cmds[]={
82 88
 		0, 0, ANY_ROUTE},
83 89
 	{"crypto_netio_decrypt", (cmd_function)w_crypto_nio_decrypt, 0,
84 90
 		0, 0, ANY_ROUTE},
91
+	{"crypto_hmac_sha256", (cmd_function)w_crypto_hmac_sha256, 3,
92
+		fixup_crypto_hmac, 0, ANY_ROUTE},
85 93
 	{"load_crypto",        (cmd_function)load_crypto, 0, 0, 0, 0},
86 94
 	{0, 0, 0, 0, 0, 0}
87 95
 };
... ...
@@ -286,6 +294,110 @@ static int fixup_crypto_aes_encrypt(void** param, int param_no)
286 294
 	return 0;
287 295
 }
288 296
 
297
+/**
298
+ *
299
+ */
300
+static int ki_crypto_hmac_sha256_helper(sip_msg_t* msg, str *ins, str *key,
301
+		pv_spec_t *dst)
302
+{
303
+	pv_value_t val;
304
+	unsigned char digest[EVP_MAX_MD_SIZE];
305
+	unsigned int digest_len;
306
+
307
+	LM_DBG("ins: %.*s, key: %.*s\n", STR_FMT(ins), STR_FMT(key));
308
+
309
+	if (!HMAC(EVP_sha256(), key->s, key->len, (const unsigned char *)ins->s, ins->len, digest, &digest_len)) {
310
+		LM_ERR("HMAC error\n");
311
+		goto error;
312
+	}
313
+
314
+	memset(&val, 0, sizeof(pv_value_t));
315
+	val.rs.s = pv_get_buffer();
316
+	val.rs.len = base64url_enc((unsigned char *)digest, digest_len, (unsigned char *)val.rs.s, pv_get_buffer_size()-1);
317
+	if (val.rs.len < 0) {
318
+		LM_ERR("base64 output of digest value is too large (need %d)\n", -val.rs.len);
319
+		goto error;
320
+	}
321
+
322
+	if (val.rs.len > 1 && val.rs.s[val.rs.len-1] == '=') {
323
+		val.rs.len--;
324
+		if (val.rs.len > 1 && val.rs.s[val.rs.len-1] == '=') {
325
+			val.rs.len--;
326
+		}
327
+	}
328
+	val.rs.s[val.rs.len] = '\0';
329
+
330
+	LM_DBG("base64 digest result: [%.*s]\n", val.rs.len, val.rs.s);
331
+	val.flags = PV_VAL_STR;
332
+	dst->setf(msg, &dst->pvp, (int)EQ_T, &val);
333
+
334
+	return 1;
335
+
336
+error:
337
+	return -1;
338
+}
339
+
340
+/**
341
+ *
342
+ */
343
+static int ki_crypto_hmac_sha256(sip_msg_t* msg, str *ins, str *keys, str *dpv)
344
+{
345
+	pv_spec_t *dst;
346
+
347
+	dst = pv_cache_get(dpv);
348
+
349
+	if(dst==NULL) {
350
+		LM_ERR("failed getting pv: %.*s\n", dpv->len, dpv->s);
351
+		return -1;
352
+	}
353
+
354
+	return ki_crypto_hmac_sha256_helper(msg, ins, keys, dst);
355
+}
356
+
357
+/**
358
+ *
359
+ */
360
+static int w_crypto_hmac_sha256(sip_msg_t* msg, char* inb, char* keyb, char* outb)
361
+{
362
+	str ins;
363
+	str keys;
364
+	pv_spec_t *dst;
365
+
366
+	if (fixup_get_svalue(msg, (gparam_t*)inb, &ins) != 0) {
367
+		LM_ERR("cannot get input value\n");
368
+		return -1;
369
+	}
370
+	if (fixup_get_svalue(msg, (gparam_t*)keyb, &keys) != 0) {
371
+		LM_ERR("cannot get key value\n");
372
+		return -1;
373
+	}
374
+	dst = (pv_spec_t*)outb;
375
+
376
+	return ki_crypto_hmac_sha256_helper(msg, &ins, &keys, dst);
377
+}
378
+
379
+/**
380
+ *
381
+ */
382
+static int fixup_crypto_hmac(void** param, int param_no)
383
+{
384
+	if(param_no==1 || param_no==2) {
385
+		if(fixup_spve_null(param, 1)<0)
386
+			return -1;
387
+		return 0;
388
+	} else if(param_no==3) {
389
+		if (fixup_pvar_null(param, 1) != 0) {
390
+			LM_ERR("failed to fixup result pvar\n");
391
+			return -1;
392
+		}
393
+		if (((pv_spec_t *)(*param))->setf == NULL) {
394
+			LM_ERR("result pvar is not writeble\n");
395
+			return -1;
396
+		}
397
+	}
398
+	return 0;
399
+}
400
+
289 401
 /**
290 402
  *
291 403
  */
... ...
@@ -401,6 +513,7 @@ static int fixup_crypto_aes_decrypt(void** param, int param_no)
401 513
 	return 0;
402 514
 }
403 515
 
516
+
404 517
 /**
405 518
  * testing function
406 519
  */
... ...
@@ -534,4 +647,4 @@ int mod_register(char *path, int *dlflags, void *p1, void *p2)
534 647
 {
535 648
 	sr_kemi_modules_add(sr_kemi_crypto_exports);
536 649
 	return 0;
537
-}
538 650
\ No newline at end of file
651
+}
... ...
@@ -226,6 +226,30 @@ crypto_aes_decrypt("$var(encrypted)", "my-secret-key", "$var(text)");
226 226
 	    </example>
227 227
 	</section>
228 228
 
229
+	<section id="async.f.crypto_hmac_sha256">
230
+		<title>
231
+			<function moreinfo="none">crypto_hmac_sha256(text, key, res)</function>
232
+		</title>
233
+		<para>
234
+			Calculates HMAC (keyed-hash message authentication code) with SHA256
235
+			as a cryptographic hash function. The result is encoded in base64 url
236
+			encoded format and stored in res. The parameter res must be a read-write
237
+			variable. The parameters text and key can be static strings or strings
238
+			with variables (dynamic strings).
239
+		</para>
240
+		<para>
241
+		This function can be used from ANY_ROUTE.
242
+		</para>
243
+		<example>
244
+			<title><function>crypto_hmac_sha256</function> usage</title>
245
+			<programlisting format="linespecific">
246
+...
247
+crypto_hmac_sha256("$var(text)", "my-secret-key", "$var(hmac)");
248
+...
249
+</programlisting>
250
+		</example>
251
+	</section>
252
+	
229 253
 	<section id="async.f.crypto_netio_in">
230 254
 	    <title>
231 255
 		<function moreinfo="none">crypto_netio_in)</function>
... ...
@@ -762,7 +762,8 @@ modparam("dispatcher", "ds_probing_mode", 1)
762 762
 
763 763
 3.26. ds_ping_latency_stats (int)
764 764
 
765
-   Enable latency measurement when pinging nodes
765
+   Enable latency measurement when pinging nodes The estimator can be
766
+   initialized at startup and reload using the attribute latency.
766 767
      * If set to 0, disable latency measurement.
767 768
      * If set to 1, enable latency measurement.
768 769
 
... ...
@@ -776,6 +777,9 @@ DEST: {
776 777
         URI: sip:1.2.3.4
777 778
         FLAGS: AX
778 779
         PRIORITY: 9
780
+        ATTRS: {
781
+                BODY: latency=24
782
+        }
779 783
         LATENCY: {
780 784
                 AVG: 24.250000 # weighted moving average for the last few weeks
781 785
                 STD: 1.035000  # standard deviation of AVG
... ...
@@ -1695,6 +1699,7 @@ kamctl rpc dispatcher.hash 4 bob server.com
1695 1699
        overwrites the general ds_ping_from parameter.
1696 1700
      * 'obproxy' - SIP URI of outbound proxy to be used when sending
1697 1701
        pings. It overwrites the general ds_outbound_proxy parameter.
1702
+     * 'latency' - latency_stats initialization in ms.
1698 1703
 
1699 1704
 6.1.2. File Format
1700 1705
 
... ...
@@ -319,6 +319,11 @@ int ds_set_attrs(ds_dest_t *dest, str *vattrs)
319 319
 		} else if(pit->name.len == 6
320 320
 				  && strncasecmp(pit->name.s, "weight", 6) == 0) {
321 321
 			str2sint(&pit->body, &dest->attrs.weight);
322
+		} else if(pit->name.len == 7
323
+				  && strncasecmp(pit->name.s, "latency", 7) == 0) {
324
+			int initial_latency = 0;
325
+			if (str2sint(&pit->body, &initial_latency) == 0)
326
+				latency_stats_init(&dest->latency_stats, initial_latency, 10000);
322 327
 		} else if(pit->name.len == 7
323 328
 				  && strncasecmp(pit->name.s, "maxload", 7) == 0) {
324 329
 			str2sint(&pit->body, &dest->attrs.maxload);
... ...
@@ -2061,6 +2066,65 @@ int ds_select_dst_limit(sip_msg_t *msg, int set, int alg, uint32_t limit,
2061 2066
 	return ret;
2062 2067
 }
2063 2068
 
2069
+int ds_manage_routes_fill_xavp(unsigned int hash, ds_set_t *idx, ds_select_state_t *rstate)
2070
+{
2071
+	int i;
2072
+
2073
+	LM_DBG("using first entry [%d/%d]\n", rstate->setid, hash);
2074
+	if(ds_add_xavp_record(idx, hash, rstate->setid, rstate->alg,
2075
+				&rstate->lxavp)<0) {
2076
+		LM_ERR("failed to add destination in the xavp (%d/%d)\n",
2077
+				hash, rstate->setid);
2078
+		return -1;
2079
+	}
2080
+	rstate->cnt++;
2081
+
2082
+	/* add to xavp the destinations after the selected one */
2083
+	for(i = hash + 1; i < idx->nr && rstate->cnt < rstate->limit; i++) {
2084
+		if(ds_skip_dst(idx->dlist[i].flags)
2085
+				|| (ds_use_default != 0 && i == (idx->nr - 1))) {
2086
+			continue;
2087
+		}
2088
+		/* max load exceeded per destination */
2089
+		if(rstate->alg == DS_ALG_CALLLOAD
2090
+				&& idx->dlist[i].attrs.maxload != 0
2091
+				&& idx->dlist[i].dload >= idx->dlist[i].attrs.maxload) {
2092
+			continue;
2093
+		}
2094
+		LM_DBG("using entry [%d/%d]\n", rstate->setid, i);
2095
+		if(ds_add_xavp_record(idx, i, rstate->setid, rstate->alg,
2096
+					&rstate->lxavp)<0) {
2097
+			LM_ERR("failed to add destination in the xavp (%d/%d)\n",
2098
+					i, rstate->setid);
2099
+			return -1;
2100
+		}
2101
+		rstate->cnt++;
2102
+	}
2103
+
2104
+	/* add to xavp the destinations before the selected one */
2105
+	for(i = 0; i < hash && rstate->cnt < rstate->limit; i++) {
2106
+		if(ds_skip_dst(idx->dlist[i].flags)
2107
+				|| (ds_use_default != 0 && i == (idx->nr - 1))) {
2108
+			continue;
2109
+		}
2110
+		/* max load exceeded per destination */
2111
+		if(rstate->alg == DS_ALG_CALLLOAD
2112
+				&& idx->dlist[i].attrs.maxload != 0
2113
+				&& idx->dlist[i].dload >= idx->dlist[i].attrs.maxload) {
2114
+			continue;
2115
+		}
2116
+		LM_DBG("using entry [%d/%d]\n", rstate->setid, i);
2117
+		if(ds_add_xavp_record(idx, i, rstate->setid, rstate->alg,
2118
+					&rstate->lxavp)<0) {
2119
+			LM_ERR("failed to add destination in the xavp (%d/%d)\n",
2120
+					i, rstate->setid);
2121
+			return -1;
2122
+		}
2123
+		rstate->cnt++;
2124
+	}
2125
+	return 0;
2126
+}
2127
+
2064 2128
 /**
2065 2129
  *
2066 2130
  */
... ...
@@ -2280,58 +2344,8 @@ int ds_manage_routes(sip_msg_t *msg, ds_select_state_t *rstate)
2280 2344
 		return 1;
2281 2345
 	}
2282 2346
 
2283
-	LM_DBG("using first entry [%d/%d]\n", rstate->setid, hash);
2284
-	if(ds_add_xavp_record(idx, hash, rstate->setid, rstate->alg,
2285
-				&rstate->lxavp)<0) {
2286
-		LM_ERR("failed to add destination in the xavp (%d/%d)\n",
2287
-				hash, rstate->setid);
2347
+	if (ds_manage_routes_fill_xavp(hash, idx, rstate) == -1)
2288 2348
 		return -1;
2289
-	}
2290
-	rstate->cnt++;
2291
-
2292
-	/* add to xavp the destinations after the selected one */
2293
-	for(i = hash + 1; i < idx->nr && rstate->cnt < rstate->limit; i++) {
2294
-		if(ds_skip_dst(idx->dlist[i].flags)
2295
-				|| (ds_use_default != 0 && i == (idx->nr - 1))) {
2296
-			continue;
2297
-		}
2298
-		/* max load exceeded per destination */
2299
-		if(rstate->alg == DS_ALG_CALLLOAD
2300
-				&& idx->dlist[i].attrs.maxload != 0
2301
-				&& idx->dlist[i].dload >= idx->dlist[i].attrs.maxload) {
2302
-			continue;
2303
-		}
2304
-		LM_DBG("using entry [%d/%d]\n", rstate->setid, i);
2305
-		if(ds_add_xavp_record(idx, i, rstate->setid, rstate->alg,
2306
-					&rstate->lxavp)<0) {
2307
-			LM_ERR("failed to add destination in the xavp (%d/%d)\n",
2308
-					i, rstate->setid);
2309
-			return -1;
2310
-		}
2311
-		rstate->cnt++;
2312
-	}
2313
-
2314
-	/* add to xavp the destinations before the selected one */
2315
-	for(i = 0; i < hash && rstate->cnt < rstate->limit; i++) {
2316
-		if(ds_skip_dst(idx->dlist[i].flags)
2317
-				|| (ds_use_default != 0 && i == (idx->nr - 1))) {
2318
-			continue;
2319
-		}
2320
-		/* max load exceeded per destination */
2321
-		if(rstate->alg == DS_ALG_CALLLOAD
2322
-				&& idx->dlist[i].attrs.maxload != 0
2323
-				&& idx->dlist[i].dload >= idx->dlist[i].attrs.maxload) {
2324
-			continue;
2325
-		}
2326
-		LM_DBG("using entry [%d/%d]\n", rstate->setid, i);
2327
-		if(ds_add_xavp_record(idx, i, rstate->setid, rstate->alg,
2328
-					&rstate->lxavp)<0) {
2329
-			LM_ERR("failed to add destination in the xavp (%d/%d)\n",
2330
-					i, rstate->setid);
2331
-			return -1;
2332
-		}
2333
-		rstate->cnt++;
2334
-	}
2335 2349
 
2336 2350
 	/* add default dst to last position in XAVP list */
2337 2351
 	if(ds_use_default != 0 && hash != idx->nr - 1
... ...
@@ -2587,6 +2601,16 @@ int ds_mark_dst(struct sip_msg *msg, int state)
2587 2601
 	return (ret == 0) ? 1 : -1;
2588 2602
 }
2589 2603
 
2604
+void latency_stats_init(ds_latency_stats_t *latency_stats, int latency, int count) {
2605
+	latency_stats->stdev = 0.0f;
2606
+	latency_stats->m2 = 0.0f;
2607
+	latency_stats->max = latency;
2608
+	latency_stats->min = latency;
2609
+	latency_stats->average = latency;
2610
+	latency_stats->estimate = latency;
2611
+	latency_stats->count = count;
2612
+}
2613
+
2590 2614
 static inline void latency_stats_update(ds_latency_stats_t *latency_stats, int latency) {
2591 2615
 	int training_count = 10000;
2592 2616
 
... ...
@@ -2596,18 +2620,14 @@ static inline void latency_stats_update(ds_latency_stats_t *latency_stats, int l
2596 2620
 	} else { /* We adjust the sum of squares used by the oneline algorithm proportionally */
2597 2621
 		latency_stats->m2 -= latency_stats->m2/latency_stats->count;
2598 2622
 	}
2599
-	if (latency_stats->count == 1) {
2600
-		latency_stats->stdev = 0.0f;
2601
-		latency_stats->m2 = 0.0f;
2602
-		latency_stats->max = latency;
2603
-		latency_stats->min = latency;
2604
-		latency_stats->average = latency;
2605
-		latency_stats->estimate = latency;
2606
-	}
2623
+
2624
+	if (latency_stats->count == 1)
2625
+		latency_stats_init(latency_stats, latency, 1);
2607 2626
 	/* stabilize-train the estimator if the average is stable after 10 samples */
2608 2627
 	if (latency_stats->count > 10 && latency_stats->count < training_count
2609 2628
 	        && latency_stats->stdev < 0.5)
2610 2629
 		latency_stats->count = training_count;
2630
+
2611 2631
 	if (latency_stats->min > latency)
2612 2632
 		latency_stats->min = latency;
2613 2633
 	if (latency_stats->max < latency)
... ...
@@ -204,6 +204,8 @@ typedef struct _ds_latency_stats {
204 204
 	uint32_t timeout;
205 205
 } ds_latency_stats_t;
206 206
 
207
+void latency_stats_init(ds_latency_stats_t *latency_stats, int latency, int count);
208
+
207 209
 typedef struct _ds_dest {
208 210
 	str uri;          /*!< address/uri */
209 211
 	int flags;        /*!< flags */
... ...
@@ -709,6 +709,7 @@ modparam("dispatcher", "ds_probing_mode", 1)
709 709
 		<title><varname>ds_ping_latency_stats</varname> (int)</title>
710 710
 		<para>
711 711
 		Enable latency measurement when pinging nodes
712
+		The estimator can be initialized at startup and reload using the attribute latency.
712 713
 		</para>
713 714
 
714 715
 		<itemizedlist>
... ...
@@ -735,6 +736,9 @@ DEST: {
735 736
 	URI: sip:1.2.3.4
736 737
 	FLAGS: AX
737 738
 	PRIORITY: 9
739
+	ATTRS: {
740
+		BODY: latency=24
741
+	}
738 742
 	LATENCY: {
739 743
 		AVG: 24.250000 # weighted moving average for the last few weeks
740 744
 		STD: 1.035000  # standard deviation of AVG
... ...
@@ -2126,6 +2130,9 @@ kamctl rpc dispatcher.hash 4 bob server.com
2126 2130
 							<para>'obproxy' - SIP URI of outbound proxy to be used when sending
2127 2131
 								pings. It overwrites the general ds_outbound_proxy parameter.</para>
2128 2132
 						</listitem>
2133
+						<listitem>
2134
+							<para>'latency' - latency_stats initialization in ms.</para>
2135
+						</listitem>
2129 2136
 					</itemizedlist>
2130 2137
 		</para>
2131 2138
 		</section>
... ...
@@ -31,6 +31,7 @@ Bogdan-Andrei Iancu
31 31
         4. Functions
32 32
 
33 33
               4.1. pike_check_req()
34
+              4.2. pike_check_ip(ipaddr)
34 35
 
35 36
         5. RPC Commands
36 37
 
... ...
@@ -50,6 +51,7 @@ Bogdan-Andrei Iancu
50 51
    1.3. Set remove_latency parameter
51 52
    1.4. Set pike_log_level parameter
52 53
    1.5. pike_check_req usage
54
+   1.6. pike_check_ip usage
53 55
    2.1. Using pike.top
54 56
    3.1. Tree of IP addresses
55 57
 
... ...
@@ -73,6 +75,7 @@ Chapter 1. Admin Guide
73 75
    4. Functions
74 76
 
75 77
         4.1. pike_check_req()
78
+        4.2. pike_check_ip(ipaddr)
76 79
 
77 80
    5. RPC Commands
78 81
 
... ...
@@ -175,6 +178,7 @@ modparam("pike", "pike_log_level", -1)
175 178
 4. Functions
176 179
 
177 180
    4.1. pike_check_req()
181
+   4.2. pike_check_ip(ipaddr)
178 182
 
179 183
 4.1.  pike_check_req()
180 184
 
... ...
@@ -191,13 +195,30 @@ Warning
191 195
      * -2 (false) - IP is detected as a new source of flooding - first
192 196
        time detection
193 197
 
194
-   This function can be used from REQUEST_ROUTE.
198
+   This function can be used from REQUEST_ROUTE|ONREPLY_ROUTE.
195 199
 
196 200
    Example 1.5. pike_check_req usage
197 201
 ...
198 202
 if (!pike_check_req()) { exit; };
199 203
 ...
200 204
 
205
+4.2.  pike_check_ip(ipaddr)
206
+
207
+   Process the IP address parameter and return false if it was exceeding
208
+   the blocking limit. The return codes are the same from
209
+   pike_check_req().
210
+
211
+   The parameter can contain variables.
212
+
213
+   This function can be used from REQUEST_ROUTE|ONREPLY_ROUTE.
214
+
215
+   Example 1.6. pike_check_ip usage
216
+...
217
+if (!pike_check_ip("1.2.3.4")) { exit; };
218
+...
219
+if (!pike_check_ip("$si")) { exit; };
220
+...
221
+
201 222
 5. RPC Commands
202 223
 
203 224
    5.1. pike.top
... ...
@@ -193,7 +193,7 @@ modparam("pike", "pike_log_level", -1)
193 193
 		</itemizedlist>
194 194
 		</para>
195 195
 		<para>
196
-		This function can be used from REQUEST_ROUTE.
196
+		This function can be used from REQUEST_ROUTE|ONREPLY_ROUTE.
197 197
 		</para>
198 198
 		<example>
199 199
 		<title><function>pike_check_req</function> usage</title>
... ...
@@ -204,6 +204,32 @@ if (!pike_check_req()) { exit; };
204 204
 </programlisting>
205 205
 		</example>
206 206
 	</section>
207
+	<section id="pike.f.pike_check_ip">
208
+		<title>
209
+		<function moreinfo="none">pike_check_ip(ipaddr)</function>
210
+		</title>
211
+		<para>
212
+		Process the IP address parameter and return false if it was exceeding
213
+		the blocking limit. The return codes are the same from pike_check_req().
214
+		</para>
215
+		<para>
216
+		The parameter can contain variables.