Coverage Report

Created: 2025-08-26 06:38

/src/opensips/parser/parse_sst.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2006 SOMA Networks, Inc. <http://www.somanetworks.com/>
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
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
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19
 *
20
 * History:
21
 * --------
22
 * 2006-02-17 Initial revision (dhsueh@somanetworks.com)
23
 */
24
25
#include "parse_sst.h"
26
27
#include "../error.h"
28
#include "../dprint.h"
29
#include "../errinfo.h"
30
#include "../mem/mem.h"
31
32
33
0
static inline int/*bool*/  is_space( char c ) { return (c == ' ' || c == '\t'); }
34
0
static inline int/*bool*/  is_num( char c ) { return (c >= '0' && c <= '9'); }
35
36
0
static inline unsigned  lower_byte( char b ) { return b | 0x20; }
37
0
static inline unsigned  lower_4bytes( unsigned d ) { return d | 0x20202020; }
38
0
static inline unsigned  lower_3bytes( unsigned d ) { return d |   0x202020; }
39
0
static inline unsigned  read_4bytes( char *val ) {
40
0
  return (*(val + 0) + (*(val + 1) << 8)
41
0
    + (*(val + 2) << 16) + (*(val + 3) << 24));
42
0
}
43
0
static inline unsigned  read_3bytes( char *val ) {
44
0
  return (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16));
45
0
}
46
47
/* compile-time constants if called with constants */
48
#define  MAKE_4BYTES( a, b, c, d ) \
49
0
  ( ((a)&0xFF) | (((b)&0xFF)<<8) | (((c)&0xFF)<<16) | (((d)&0xFF)<<24) )
50
#define  MAKE_3BYTES( a, b, c ) \
51
0
  ( ((a)&0xFF) | (((b)&0xFF)<<8) | (((c)&0xFF)<<16) )
52
53
54
struct session_expires *
55
malloc_session_expires( void )
56
0
{
57
0
  struct session_expires *se = (struct session_expires *)
58
0
    pkg_malloc( sizeof(struct session_expires) );
59
0
  if ( se )
60
0
    memset( se, 0, sizeof(struct session_expires) );
61
0
  return se;
62
0
}
63
64
65
void
66
free_session_expires( struct session_expires *se )
67
0
{
68
0
  if ( se )
69
0
    pkg_free( se );
70
0
}
71
72
73
enum parse_sst_result
74
parse_session_expires_body( struct hdr_field *hf )
75
0
{
76
0
  register char *p = hf->body.s;
77
0
  int pos = 0;
78
0
  int len = hf->body.len;
79
0
  char *q;
80
0
  struct session_expires se = { 0, sst_refresher_unspecified };
81
0
  unsigned tok;
82
83
0
  if ( !p || len <= 0 ) {
84
0
    LM_ERR(" no body for header field\n" );
85
0
    return parse_sst_header_not_found;
86
0
  }
87
88
  /* skip whitespace */
89
0
  for ( ; pos < len && is_space(*p); ++pos, ++p )
90
0
    /*nothing*/;
91
92
  /* collect a number */
93
0
  for ( q = p; pos < len && is_num(*q); ++pos, ++q )
94
0
    se.interval = se.interval*10/*radix*/ + (*q - '0');
95
96
0
  if ( q == p ) /*nothing parsed */ {
97
0
    LM_ERR(" no expiry interval\n" );
98
0
    return parse_sst_no_value;
99
0
  }
100
0
  p = q;
101
102
  /* continue on with params */
103
0
  while ( pos < len ) {
104
105
0
    if ( *p == ';' ) {
106
0
      ++p; ++pos;
107
108
0
      if ( pos + 4 < len ) {
109
0
        switch ( lower_4bytes(read_4bytes(p)) ) {
110
0
          case /*refr*/MAKE_4BYTES('r','e','f','r'):
111
0
            if ( pos + 9 <= len
112
0
               && lower_4bytes(read_4bytes(p+4))
113
0
                == /*eshe*/MAKE_4BYTES('e','s','h','e')
114
0
               && lower_byte(*(p+8)) == 'r'
115
0
               && *(p+9) == '=' ) {
116
0
              tok = lower_3bytes( read_3bytes(p+10) );
117
0
              if ( tok == MAKE_3BYTES('u','a','c') ) {
118
0
                se.refresher = sst_refresher_uac;
119
0
                p += 13; pos += 13;
120
0
              }
121
0
              else if ( tok == MAKE_3BYTES('u','a','s') ) {
122
0
                se.refresher = sst_refresher_uas;
123
0
                p += 13; pos += 13;
124
0
              }
125
0
              else /* unrecognized refresher-param */ {
126
0
                LM_ERR(" unrecognized refresher\n" );
127
0
                return parse_sst_parse_error;
128
0
              }
129
0
            }
130
0
            else /* not "esher=" */ {
131
              /* there are no other se-params
132
                 that start with "refr" */
133
0
              for ( ; pos < len && *p != ';'; ++pos, ++p )
134
0
                /*skip to ';'*/;
135
0
            }
136
0
            break;
137
0
          default:
138
            /* unrecognized se-param */
139
0
            for ( ; pos < len && *p != ';'; ++pos, ++p )
140
0
              /*skip to ';'*/;
141
0
            break;
142
0
        } /*switch*/
143
0
      } /* exist 4 bytes to check */
144
0
      else /* less than 4 bytes left */ {
145
        /* not enough text left for any of the recognized se-params */
146
        /* no other recognized se-param */
147
0
        for ( ; pos < len && *p != ';'; ++pos, ++p ) /*skip to ';'*/;
148
0
      }
149
0
    }
150
0
    else /* not ';' */ {
151
0
      LM_ERR("no semicolon separating se-params\n");
152
0
      return parse_sst_parse_error;
153
0
    } /* if ';' */
154
0
  } /* while */
155
156
0
  hf->parsed = malloc_session_expires();
157
0
  if ( !hf->parsed ) {
158
0
    LM_ERR(" out of pkg memory\n" );
159
0
    return parse_sst_out_of_mem;
160
0
  }
161
0
  *((struct session_expires *)hf->parsed) = se;
162
163
0
  return parse_sst_success;
164
0
}
165
166
167
enum parse_sst_result
168
parse_session_expires( struct sip_msg *msg, struct session_expires *se )
169
0
{
170
0
  enum parse_sst_result result;
171
172
0
  if (msg->session_expires==NULL &&
173
0
  parse_headers(msg,HDR_SESSION_EXPIRES_F,0)!=0 ) {
174
0
    LM_ERR("failed to parse message when looking for Session-Expires \n");
175
0
    return parse_sst_header_not_found;
176
0
  }
177
178
0
  if ( msg->session_expires ) {
179
0
    if ( msg->session_expires->parsed == 0
180
0
       && (result = parse_session_expires_body(msg->session_expires))
181
0
        != parse_sst_success ) {
182
0
      if (result!=parse_sst_out_of_mem) {
183
0
        set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM,
184
0
          "error parsing SE header");
185
0
        set_err_reply(400, "bad headers");
186
0
      }
187
0
      return result;
188
0
    }
189
0
    if ( se ) {
190
0
      *se = *((struct session_expires *)msg->session_expires->parsed);
191
0
    }
192
0
    return parse_sst_success;
193
0
  }
194
0
  else {
195
0
    return parse_sst_header_not_found;
196
0
  }
197
0
}
198
199
200
enum parse_sst_result
201
parse_min_se_body( struct hdr_field *hf )
202
0
{
203
0
  int len = hf->body.len;
204
0
  char *p = hf->body.s;
205
0
  int pos = 0;
206
0
  unsigned int interval = 0;
207
208
  /* skip whitespace */
209
0
  for ( ; pos < len && is_space(*p); ++pos, ++p )
210
0
    /*nothing*/;
211
0
  if ( pos == len )
212
0
    return parse_sst_no_value;
213
  /* collect a number */
214
0
  for ( ; pos < len && is_num(*p); ++pos, ++p )
215
0
    interval = interval*10/*radix*/ + (*p - '0');
216
  /* skip whitespace */
217
0
  for ( ; pos < len && is_space(*p); ++pos, ++p )
218
0
    /*nothing*/;
219
0
  if ( pos != len ) /* shouldn't be any more junk */
220
0
    return parse_sst_parse_error;
221
0
  hf->parsed=(void*)(long)interval;
222
0
  return parse_sst_success;
223
0
}
224
225
226
enum parse_sst_result
227
parse_min_se( struct sip_msg *msg, unsigned int *min_se )
228
0
{
229
0
  enum parse_sst_result result;
230
231
0
  if (msg->min_se==NULL && parse_headers(msg,HDR_MIN_SE_F,0)!=0 ) {
232
0
    LM_ERR("failed to parse message when looking for MIN-SE \n");
233
0
    return parse_sst_header_not_found;
234
0
  }
235
236
0
  if ( msg->min_se ) {
237
0
    if ( msg->min_se->parsed == 0
238
0
       && (result = parse_min_se_body(msg->min_se))
239
0
        != parse_sst_success ) {
240
0
      set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM,
241
0
        "error parsing MINSE header");
242
0
      set_err_reply(400, "bad headers");
243
0
      return result;
244
0
    }
245
0
    if ( min_se ) {
246
0
      *min_se = (unsigned int)(long)msg->min_se->parsed;
247
0
    }
248
0
    return parse_sst_success;
249
0
  }
250
0
  else {
251
0
    return parse_sst_header_not_found;
252
0
  }
253
0
}