Coverage Report

Created: 2026-08-31 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/receive.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2010-2014 OpenSIPS Solutions
3
 * Copyright (C) 2001-2003 FhG Fokus
4
 *
5
 * This file is part of opensips, a free SIP server.
6
 *
7
 * opensips is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version
11
 *
12
 * opensips is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
20
 *
21
 * History:
22
 * ---------
23
 * 2003-02-28 scratchpad compatibility abandoned (jiri)
24
 * 2003-01-29 transport-independent message zero-termination in
25
 *            receive_msg (jiri)
26
 * 2003-02-07 undoed jiri's zero term. changes (they break tcp) (andrei)
27
 * 2003-02-10 moved zero-term in the calling functions (udp_receive &
28
 *            tcp_read_req)
29
 * 2003-08-13 fixed exec_pre_cb returning 0 (backported from stable) (andrei)
30
 * 2004-02-06 added user preferences support - destroy_avps() (bogdan)
31
 * 2004-04-30 exec_pre_cb is called after basic sanity checks (at least one
32
 *            via present & parsed ok)  (andrei)
33
 * 2004-08-23 avp core changed - destroy_avp-> reset_avps (bogdan)
34
 * 2005-07-26 default onreply route added (andrei)
35
 * 2006-12-22 functions for script flags added (bogdan)
36
 */
37
38
/*!
39
 * \file
40
 * \brief Receive message and process routing for it
41
 */
42
43
44
#include <string.h>
45
#include <stdlib.h>
46
#include <sys/time.h>
47
48
#include "receive.h"
49
#include "globals.h"
50
#include "dprint.h"
51
#include "route.h"
52
#include "parser/msg_parser.h"
53
#include "forward.h"
54
#include "action.h"
55
#include "mem/mem.h"
56
#include "ip_addr.h"
57
#include "script_cb.h"
58
#include "dset.h"
59
#include "usr_avp.h"
60
#include "core_stats.h"
61
#include "ut.h"
62
#include "context.h"
63
#include "profiling.h"
64
65
66
#ifdef DEBUG_DMALLOC
67
#include <mem/dmalloc.h>
68
#endif
69
70
static unsigned int msg_no=0;
71
/* address preset vars */
72
str * const default_global_address=&STR_NULL;
73
str * const default_global_port=&STR_NULL;
74
str * const default_via_address=&STR_NULL;
75
str * const default_via_port=&STR_NULL;
76
77
78
unsigned int get_next_msg_no(void)
79
0
{
80
0
  return ++msg_no;
81
0
}
82
83
84
#define prepare_context( _ctx, _err ) \
85
0
  do { \
86
0
    if (_ctx==NULL) { \
87
0
      _ctx = context_alloc(CONTEXT_GLOBAL);\
88
0
      if (_ctx==NULL) { \
89
0
        LM_ERR("failed to allocated new context, skipping\n"); \
90
0
        goto _err; \
91
0
      } \
92
0
    } \
93
0
    memset( _ctx, 0, context_size(CONTEXT_GLOBAL)); \
94
0
  }while(0)
95
96
97
/*! \note WARNING: buf must be 0 terminated (buf[len]=0) or some things might
98
 * break (e.g.: modules/textops)
99
 */
100
int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info,
101
    context_p existing_context, unsigned int msg_flags)
102
0
{
103
0
  #define reset_global_context() \
104
0
    do {\
105
0
      if (!current_processing_ctx) { \
106
0
        ctx = NULL; \
107
0
      } else { \
108
0
        context_destroy(CONTEXT_GLOBAL, ctx); \
109
0
        set_global_context(NULL); \
110
0
      } \
111
0
    } while (0)
112
0
  static context_p ctx = NULL;
113
114
0
  struct sip_msg* msg;
115
0
  struct timeval start;
116
0
  int rc, ret, old_route_type;
117
0
  char *tmp;
118
0
  str in_buff;
119
120
0
  profiling_proc_enter( LEVEL_SIP, "receive_msg", 0 );
121
122
0
  in_buff.len = len;
123
0
  in_buff.s = buf;
124
125
0
  if (existing_context) {
126
0
    context_free(ctx);
127
0
    ctx = existing_context;
128
0
  }
129
130
  /* the raw processing callbacks can change the buffer,
131
  further use in_buff.s and at the end try to free in_buff.s
132
  if changed by callbacks */
133
0
  if (run_pre_raw_processing_cb(PRE_RAW_PROCESSING,&in_buff,NULL)<0) {
134
0
    LM_ERR("error in running pre raw callbacks, dropping\n");
135
0
    goto error;
136
0
  }
137
  /* update the length for further processing */
138
0
  len = in_buff.len;
139
140
0
  msg=pkg_malloc(sizeof(struct sip_msg));
141
0
  if (msg==0) {
142
0
    LM_ERR("no pkg mem left for sip_msg\n");
143
0
    goto error;
144
0
  }
145
0
  msg_no++;
146
  /* number of vias parsed -- good for diagnostic info in replies */
147
0
  via_cnt=0;
148
149
0
  memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
150
  /* fill in msg */
151
0
  msg->buf=in_buff.s;
152
0
  msg->len=len;
153
0
  msg->rcv=*rcv_info;
154
0
  msg->id=msg_no;
155
0
  msg->msg_flags=msg_flags;
156
0
  msg->ruri_q = Q_UNSPECIFIED;
157
158
0
  if (parse_msg_opt(in_buff.s,len, msg, 0)!=0){
159
0
    tmp=ip_addr2a(&(rcv_info->src_ip));
160
0
    LM_ERR("Unable to parse msg received from [%s:%d]\n",
161
0
      tmp, rcv_info->src_port);
162
0
    msg->buf=in_buff.s;
163
0
    msg->len=len;
164
0
    msg->rcv=*rcv_info;
165
0
    msg->id=msg_no;
166
0
    msg->msg_flags=msg_flags;
167
    /* if a REQUEST msg was detected (first line was successfully parsed)
168
       we should trigger the error route */
169
0
    if ( msg->first_line.type==SIP_REQUEST && sroutes->error.a!=NULL ) {
170
0
      if (existing_context == NULL)
171
0
        prepare_context( ctx, parse_error );
172
0
      set_global_context(ctx);
173
0
      run_error_route(msg, 1);
174
0
      reset_global_context();
175
0
    }
176
0
    goto parse_error;
177
0
  }
178
0
  LM_DBG("After parse_msg...\n");
179
180
0
  start_expire_timer(start,execmsgthreshold);
181
  /* jumpt to parse_error_reset (not to parse_error) while
182
   * start_expire_timer() is still on */
183
184
  /* ... clear branches from previous message */
185
0
  clear_dset();
186
187
0
  if (msg->first_line.type==SIP_REQUEST) {
188
0
    update_stat( rcv_reqs, 1);
189
    /* sanity checks */
190
0
    if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
191
      /* no via, send back error ? */
192
0
      LM_ERR("no via found in request\n");
193
0
      update_stat( err_reqs, 1);
194
0
      goto parse_error_reset;
195
0
    }
196
    /* check if necessary to add receive?->moved to forward_req */
197
198
    /* should we reuse this connection for the opposite direction? */
199
0
    if (is_tcp_based_proto(rcv_info->proto)
200
0
        && tcpconn_add_alias(msg, rcv_info->proto_reserved1,
201
0
                           msg->via1->port, rcv_info->proto) != 0) {
202
0
      LM_WARN("tcp alias failed\n");
203
      /* continue */
204
0
    }
205
206
0
    LM_DBG("preparing to run routing scripts...\n");
207
    /* set request route type --bogdan*/
208
0
    set_route_type( REQUEST_ROUTE );
209
210
    /* prepare and set a new processing context for this request only if
211
     * no context was set from the upper layers */
212
0
    if (existing_context == NULL)
213
0
      prepare_context( ctx, parse_error_reset );
214
0
    set_global_context(ctx);
215
216
    /* execute pre-script callbacks, if any;
217
     * if some of the callbacks said not to continue with
218
     * script processing, don't do so;
219
     * if we are here basic sanity checks are already done
220
     * (like presence of at least one via), so you can count
221
     * on via1 being parsed in a pre-script callback --andrei
222
     */
223
0
    profiling_proc_enter( LEVEL_SIP, "request_pre_script", 1 );
224
0
    rc = exec_pre_req_cb(msg);
225
0
    profiling_proc_exit( LEVEL_SIP, "request_pre_script", rc );
226
0
    if (rc == SCB_DROP_MSG) {
227
0
      update_stat( drp_reqs, 1);
228
0
      goto end; /* drop the message */
229
0
    }
230
231
    /* exec the routing script */
232
0
    if (rc & SCB_RUN_TOP_ROUTE) {
233
      /* run the main request route and skip post_script callbacks
234
       * if the TOBE_CONTINUE flag is returned */
235
0
      profiling_proc_enter( LEVEL_SIP, "request_script", 0 );
236
0
      ret = run_top_route(sroutes->request[DEFAULT_RT], msg);
237
0
      profiling_proc_exit( LEVEL_SIP, "request_script", ret );
238
0
      if ( ret & ACT_FL_TBCONT )
239
0
        goto end;
240
0
    }
241
242
    /* execute post request-script callbacks */
243
0
    if (rc & SCB_RUN_POST_CBS)
244
0
      exec_post_req_cb(msg);
245
246
0
  } else if (msg->first_line.type==SIP_REPLY) {
247
0
    update_stat( rcv_rpls, 1);
248
    /* sanity checks */
249
0
    if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
250
      /* no via, send back error ? */
251
0
      LM_ERR("no via found in reply\n");
252
0
      update_stat( err_rpls, 1);
253
0
      goto parse_error_reset;
254
0
    }
255
256
    /* set reply route type --bogdan*/
257
0
    set_route_type( ONREPLY_ROUTE );
258
259
    /* prepare and set a new processing context for this reply only if
260
     * no context was set from the upper layers */
261
0
    if (existing_context == NULL)
262
0
      prepare_context( ctx, parse_error_reset );
263
0
    set_global_context(ctx);
264
265
    /* execute pre-script callbacks, if any ;
266
     * if some of the callbacks said not to continue with
267
     * script processing, don't do so ;
268
     * if we are here, basic sanity checks are already done
269
     * (like presence of at least one via), so you can count
270
     * on via1 being parsed in a pre-script callback --andrei
271
     */
272
0
    rc = exec_pre_rpl_cb(msg);
273
0
    if (rc == SCB_DROP_MSG) {
274
0
      update_stat( drp_rpls, 1);
275
0
      goto end; /* drop the reply */
276
0
    }
277
278
0
    swap_route_type(old_route_type, ONREPLY_ROUTE);
279
    /* exec the onreply routing script */
280
0
    if (rc & SCB_RUN_TOP_ROUTE && sroutes->onreply[DEFAULT_RT].a &&
281
0
        (run_top_route(sroutes->onreply[DEFAULT_RT],msg) & ACT_FL_DROP)
282
0
        && msg->REPLY_STATUS < 200) {
283
0
      set_route_type(old_route_type);
284
285
0
      LM_DBG("dropping provisional reply %d\n", msg->REPLY_STATUS);
286
0
      update_stat( drp_rpls, 1);
287
0
      goto end; /* drop the message */
288
0
    } else {
289
0
      set_route_type(old_route_type);
290
      /* send the msg */
291
0
      profiling_proc_enter( LEVEL_SIP, "reply_forward", 0 );
292
0
      ret = forward_reply(msg);
293
0
      profiling_proc_exit( LEVEL_SIP, "reply_forward", ret );
294
      /* TODO - TX reply stat */
295
0
    }
296
297
    /* execute post reply-script callbacks */
298
0
    if (rc & SCB_RUN_POST_CBS)
299
0
      exec_post_rpl_cb(msg);
300
0
  }
301
302
0
end:
303
0
  reset_global_context();
304
305
0
  __stop_expire_timer( start, execmsgthreshold, "msg processing",
306
0
    msg->buf, msg->len, 0, slow_msgs);
307
0
  reset_longest_action_list(execmsgthreshold);
308
309
  /* free possible loaded avps -bogdan */
310
0
  reset_avps();
311
0
  LM_DBG("cleaning up\n");
312
0
  free_sip_msg(msg);
313
0
  pkg_free(msg);
314
0
  if (in_buff.s != buf)
315
0
    pkg_free(in_buff.s);
316
0
  profiling_proc_exit( LEVEL_SIP, "receive_msg", 0 );
317
0
  return 0;
318
0
parse_error_reset:
319
0
  reset_longest_action_list(execmsgthreshold);
320
0
parse_error:
321
0
  exec_parse_err_cb(msg);
322
0
  free_sip_msg(msg);
323
0
  pkg_free(msg);
324
0
error:
325
0
  if (in_buff.s != buf)
326
0
    pkg_free(in_buff.s);
327
0
  profiling_proc_exit( LEVEL_SIP, "receive_msg", -1 );
328
0
  return -1;
329
0
}
330