Coverage Report

Created: 2025-07-12 06:14

/src/opensips/receive.c
Line
Count
Source (jump to first uncovered line)
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
64
65
#ifdef DEBUG_DMALLOC
66
#include <mem/dmalloc.h>
67
#endif
68
69
static unsigned int msg_no=0;
70
/* address preset vars */
71
str * const default_global_address=&STR_NULL;
72
str * const default_global_port=&STR_NULL;
73
str * const default_via_address=&STR_NULL;
74
str * const default_via_port=&STR_NULL;
75
76
77
unsigned int get_next_msg_no(void)
78
0
{
79
0
  return ++msg_no;
80
0
}
81
82
83
#define prepare_context( _ctx, _err ) \
84
0
  do { \
85
0
    if (_ctx==NULL) { \
86
0
      _ctx = context_alloc(CONTEXT_GLOBAL);\
87
0
      if (_ctx==NULL) { \
88
0
        LM_ERR("failed to allocated new context, skipping\n"); \
89
0
        goto _err; \
90
0
      } \
91
0
    } \
92
0
    memset( _ctx, 0, context_size(CONTEXT_GLOBAL)); \
93
0
  }while(0)
94
95
96
/*! \note WARNING: buf must be 0 terminated (buf[len]=0) or some things might
97
 * break (e.g.: modules/textops)
98
 */
99
int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info,
100
    context_p existing_context, unsigned int msg_flags)
101
0
{
102
0
  #define reset_global_context() \
103
0
    do {\
104
0
      if (!current_processing_ctx) { \
105
0
        ctx = NULL; \
106
0
      } else { \
107
0
        context_destroy(CONTEXT_GLOBAL, ctx); \
108
0
        set_global_context(NULL); \
109
0
      } \
110
0
    } while (0)
111
0
  static context_p ctx = NULL;
112
113
0
  struct sip_msg* msg;
114
0
  struct timeval start;
115
0
  int rc, old_route_type;
116
0
  char *tmp;
117
0
  str in_buff;
118
119
0
  in_buff.len = len;
120
0
  in_buff.s = buf;
121
122
0
  if (existing_context) {
123
0
    context_free(ctx);
124
0
    ctx = existing_context;
125
0
  }
126
127
  /* the raw processing callbacks can change the buffer,
128
  further use in_buff.s and at the end try to free in_buff.s
129
  if changed by callbacks */
130
0
  if (run_pre_raw_processing_cb(PRE_RAW_PROCESSING,&in_buff,NULL)<0) {
131
0
    LM_ERR("error in running pre raw callbacks, dropping\n");
132
0
    goto error;
133
0
  }
134
  /* update the length for further processing */
135
0
  len = in_buff.len;
136
137
0
  msg=pkg_malloc(sizeof(struct sip_msg));
138
0
  if (msg==0) {
139
0
    LM_ERR("no pkg mem left for sip_msg\n");
140
0
    goto error;
141
0
  }
142
0
  msg_no++;
143
  /* number of vias parsed -- good for diagnostic info in replies */
144
0
  via_cnt=0;
145
146
0
  memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
147
  /* fill in msg */
148
0
  msg->buf=in_buff.s;
149
0
  msg->len=len;
150
0
  msg->rcv=*rcv_info;
151
0
  msg->id=msg_no;
152
0
  msg->msg_flags=msg_flags;
153
0
  msg->ruri_q = Q_UNSPECIFIED;
154
155
0
  if (parse_msg_opt(in_buff.s,len, msg, 0)!=0){
156
0
    tmp=ip_addr2a(&(rcv_info->src_ip));
157
0
    LM_ERR("Unable to parse msg received from [%s:%d]\n",
158
0
      tmp, rcv_info->src_port);
159
    /* if a REQUEST msg was detected (first line was successfully parsed)
160
       we should trigger the error route */
161
0
    if ( msg->first_line.type==SIP_REQUEST && sroutes->error.a!=NULL ) {
162
0
      if (existing_context == NULL)
163
0
        prepare_context( ctx, parse_error );
164
0
      set_global_context(ctx);
165
0
      run_error_route(msg, 1);
166
0
      reset_global_context();
167
0
    }
168
0
    goto parse_error;
169
0
  }
170
0
  LM_DBG("After parse_msg...\n");
171
172
0
  start_expire_timer(start,execmsgthreshold);
173
  /* jumpt to parse_error_reset (not to parse_error) while
174
   * start_expire_timer() is still on */
175
176
  /* ... clear branches from previous message */
177
0
  clear_dset();
178
179
0
  if (msg->first_line.type==SIP_REQUEST) {
180
0
    update_stat( rcv_reqs, 1);
181
    /* sanity checks */
182
0
    if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
183
      /* no via, send back error ? */
184
0
      LM_ERR("no via found in request\n");
185
0
      update_stat( err_reqs, 1);
186
0
      goto parse_error_reset;
187
0
    }
188
    /* check if necessary to add receive?->moved to forward_req */
189
190
    /* should we reuse this connection for the opposite direction? */
191
0
    if (is_tcp_based_proto(rcv_info->proto)
192
0
        && tcpconn_add_alias(msg, rcv_info->proto_reserved1,
193
0
                           msg->via1->port, rcv_info->proto) != 0) {
194
0
      LM_WARN("tcp alias failed\n");
195
      /* continue */
196
0
    }
197
198
0
    LM_DBG("preparing to run routing scripts...\n");
199
    /* set request route type --bogdan*/
200
0
    set_route_type( REQUEST_ROUTE );
201
202
    /* prepare and set a new processing context for this request only if
203
     * no context was set from the upper layers */
204
0
    if (existing_context == NULL)
205
0
      prepare_context( ctx, parse_error_reset );
206
0
    set_global_context(ctx);
207
208
    /* execute pre-script callbacks, if any;
209
     * if some of the callbacks said not to continue with
210
     * script processing, don't do so;
211
     * if we are here basic sanity checks are already done
212
     * (like presence of at least one via), so you can count
213
     * on via1 being parsed in a pre-script callback --andrei
214
     */
215
0
    rc = exec_pre_req_cb(msg);
216
0
    if (rc == SCB_DROP_MSG) {
217
0
      update_stat( drp_reqs, 1);
218
0
      goto end; /* drop the message */
219
0
    }
220
221
    /* exec the routing script */
222
0
    if (rc & SCB_RUN_TOP_ROUTE)
223
      /* run the main request route and skip post_script callbacks
224
       * if the TOBE_CONTINUE flag is returned */
225
0
      if ( run_top_route(sroutes->request[DEFAULT_RT], msg) &
226
0
      ACT_FL_TBCONT )
227
0
        goto end;
228
229
    /* execute post request-script callbacks */
230
0
    if (rc & SCB_RUN_POST_CBS)
231
0
      exec_post_req_cb(msg);
232
233
0
  } else if (msg->first_line.type==SIP_REPLY) {
234
0
    update_stat( rcv_rpls, 1);
235
    /* sanity checks */
236
0
    if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
237
      /* no via, send back error ? */
238
0
      LM_ERR("no via found in reply\n");
239
0
      update_stat( err_rpls, 1);
240
0
      goto parse_error_reset;
241
0
    }
242
243
    /* set reply route type --bogdan*/
244
0
    set_route_type( ONREPLY_ROUTE );
245
246
    /* prepare and set a new processing context for this reply only if
247
     * no context was set from the upper layers */
248
0
    if (existing_context == NULL)
249
0
      prepare_context( ctx, parse_error_reset );
250
0
    set_global_context(ctx);
251
252
    /* execute pre-script callbacks, if any ;
253
     * if some of the callbacks said not to continue with
254
     * script processing, don't do so ;
255
     * if we are here, basic sanity checks are already done
256
     * (like presence of at least one via), so you can count
257
     * on via1 being parsed in a pre-script callback --andrei
258
     */
259
0
    rc = exec_pre_rpl_cb(msg);
260
0
    if (rc == SCB_DROP_MSG) {
261
0
      update_stat( drp_rpls, 1);
262
0
      goto end; /* drop the reply */
263
0
    }
264
265
0
    swap_route_type(old_route_type, ONREPLY_ROUTE);
266
    /* exec the onreply routing script */
267
0
    if (rc & SCB_RUN_TOP_ROUTE && sroutes->onreply[DEFAULT_RT].a &&
268
0
        (run_top_route(sroutes->onreply[DEFAULT_RT],msg) & ACT_FL_DROP)
269
0
        && msg->REPLY_STATUS < 200) {
270
0
      set_route_type(old_route_type);
271
272
0
      LM_DBG("dropping provisional reply %d\n", msg->REPLY_STATUS);
273
0
      update_stat( drp_rpls, 1);
274
0
      goto end; /* drop the message */
275
0
    } else {
276
0
      set_route_type(old_route_type);
277
      /* send the msg */
278
0
      forward_reply(msg);
279
      /* TODO - TX reply stat */
280
0
    }
281
282
    /* execute post reply-script callbacks */
283
0
    if (rc & SCB_RUN_POST_CBS)
284
0
      exec_post_rpl_cb(msg);
285
0
  }
286
287
0
end:
288
0
  reset_global_context();
289
290
0
  __stop_expire_timer( start, execmsgthreshold, "msg processing",
291
0
    msg->buf, msg->len, 0, slow_msgs);
292
0
  reset_longest_action_list(execmsgthreshold);
293
294
  /* free possible loaded avps -bogdan */
295
0
  reset_avps();
296
0
  LM_DBG("cleaning up\n");
297
0
  free_sip_msg(msg);
298
0
  pkg_free(msg);
299
0
  if (in_buff.s != buf)
300
0
    pkg_free(in_buff.s);
301
0
  return 0;
302
0
parse_error_reset:
303
0
  reset_longest_action_list(execmsgthreshold);
304
0
parse_error:
305
0
  exec_parse_err_cb(msg);
306
0
  free_sip_msg(msg);
307
0
  pkg_free(msg);
308
0
error:
309
0
  if (in_buff.s != buf)
310
0
    pkg_free(in_buff.s);
311
0
  return -1;
312
0
}
313