Coverage Report

Created: 2025-07-11 06:28

/src/opensips/net/proto_udp/proto_udp.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2015 - OpenSIPS Foundation
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
 *
22
 * History:
23
 * -------
24
 *  2015-02-11  first version (bogdan)
25
 */
26
27
#include <errno.h>
28
#include <unistd.h>
29
#include <netinet/tcp.h>
30
#include <poll.h>
31
#include <fcntl.h>
32
33
#include "../../pt.h"
34
#include "../../timer.h"
35
#include "../../socket_info.h"
36
#include "../../receive.h"
37
#include "../api_proto.h"
38
#include "../api_proto_net.h"
39
#include "../net_udp.h"
40
#include "proto_udp.h"
41
42
43
static int mod_init(void);
44
static int proto_udp_init(struct proto_info *pi);
45
static int proto_udp_init_listener(struct socket_info *si);
46
static int proto_udp_bind_listener(struct socket_info *si);
47
static int proto_udp_send(const struct socket_info* send_sock,
48
    char* buf, unsigned int len, const union sockaddr_union* to,
49
    unsigned int id);
50
51
static int udp_read_req(const struct socket_info *src, int* bytes_read);
52
53
static callback_list* cb_list = NULL;
54
55
static int udp_port = SIP_PORT;
56
57
58
static const cmd_export_t cmds[] = {
59
  {"proto_init", (cmd_function)proto_udp_init, {{0,0,0}}, 0},
60
  {0,0,{{0,0,0}},0}
61
};
62
63
64
static const param_export_t params[] = {
65
  { "udp_port",    INT_PARAM,   &udp_port   },
66
  {0, 0, 0}
67
};
68
69
70
struct module_exports proto_udp_exports = {
71
  PROTO_PREFIX "udp",  /* module name*/
72
  MOD_TYPE_DEFAULT,/* class of this module */
73
  MODULE_VERSION,
74
  DEFAULT_DLFLAGS, /* dlopen flags */
75
  0,               /* load function */
76
  NULL,            /* OpenSIPS module dependencies */
77
  cmds,       /* exported functions */
78
  0,          /* exported async functions */
79
  params,     /* module parameters */
80
  0,          /* exported statistics */
81
  0,          /* exported MI functions */
82
  0,          /* exported pseudo-variables */
83
  0,      /* exported transformations */
84
  0,          /* extra processes */
85
  0,          /* module pre-initialization function */
86
  mod_init,   /* module initialization function */
87
  0,          /* response function */
88
  0,          /* destroy function */
89
  0,          /* per-child init function */
90
  0           /* reload confirm function */
91
};
92
93
94
static int mod_init(void)
95
0
{
96
0
  LM_INFO("initializing UDP-plain protocol\n");
97
0
  return 0;
98
0
}
99
100
101
static int proto_udp_init(struct proto_info *pi)
102
0
{
103
0
  pi->id          = PROTO_UDP;
104
0
  pi->name        = "udp";
105
0
  pi->default_port    = udp_port;
106
107
0
  pi->tran.init_listener  = proto_udp_init_listener;
108
0
  pi->tran.bind_listener  = proto_udp_bind_listener;
109
0
  pi->tran.send     = proto_udp_send;
110
111
0
  pi->net.flags     = PROTO_NET_USE_UDP;
112
0
  pi->net.dgram.read    = udp_read_req;
113
114
0
  return 0;
115
0
}
116
117
118
static int proto_udp_init_listener(struct socket_info *si)
119
0
{
120
  /* we do not do anything particular to UDP plain here, so
121
   * transparently use the generic listener init from net UDP layer */
122
0
  return udp_init_listener(si, O_NONBLOCK);
123
0
}
124
125
static int proto_udp_bind_listener(struct socket_info *si)
126
0
{
127
0
  return udp_bind_listener(si);
128
0
}
129
130
static int udp_read_req(const struct socket_info *si, int* bytes_read)
131
0
{
132
0
  struct receive_info ri;
133
0
  int len;
134
0
  static char buf [BUF_SIZE+1];
135
0
  char *tmp;
136
0
  unsigned int fromlen;
137
0
  callback_list* p;
138
0
  str msg;
139
140
0
  fromlen=sockaddru_len(si->su);
141
  /* coverity[overrun-buffer-arg: FALSE] - union has 28 bytes, CID #200029 */
142
0
  len=recvfrom(si->socket, buf, BUF_SIZE,0,&ri.src_su.s,&fromlen);
143
0
  if (len==-1){
144
0
    if (errno==EAGAIN)
145
0
      return 0;
146
0
    if ((errno==EINTR)||(errno==EWOULDBLOCK)|| (errno==ECONNREFUSED))
147
0
      return -1;
148
0
    LM_ERR("recvfrom:[%d] %s\n", errno, strerror(errno));
149
0
    return -2;
150
0
  }
151
152
0
  if (len<MIN_UDP_PACKET) {
153
0
    LM_DBG("probing packet received len = %d\n", len);
154
0
    return 0;
155
0
  }
156
157
  /* we must 0-term the messages, receive_msg expects it */
158
0
  buf[len]=0; /* no need to save the previous char */
159
160
0
  ri.bind_address = si;
161
0
  ri.dst_port = si->port_no;
162
0
  ri.dst_ip = si->address;
163
0
  ri.proto = si->proto;
164
0
  ri.proto_reserved1 = ri.proto_reserved2 = 0;
165
166
0
  su2ip_addr(&ri.src_ip, &ri.src_su);
167
0
  ri.src_port=su_getport(&ri.src_su);
168
169
0
  msg.s = buf;
170
0
  msg.len = len;
171
172
  /* run callbacks if looks like non-SIP message*/
173
0
  if( !isalpha(msg.s[0]) ){    /* not-SIP related */
174
0
    for(p = cb_list; p; p = p->next){
175
0
      if(p->b == msg.s[1]){
176
0
        if (p->func(bind_address->socket, &ri, &msg, p->param)==0){
177
          /* buffer consumed by callback */
178
0
          break;
179
0
        }
180
0
      }
181
0
    }
182
0
    if (p) return 0;
183
0
  }
184
185
0
  if (ri.src_port==0){
186
0
    tmp=ip_addr2a(&ri.src_ip);
187
0
    LM_INFO("dropping 0 port packet from %s\n", tmp);
188
0
    return 0;
189
0
  }
190
191
  /* receive_msg must free buf too!*/
192
0
  receive_msg( msg.s, msg.len, &ri, NULL, 0);
193
194
0
  return 0;
195
0
}
196
197
198
/**
199
 * Main UDP send function, called from msg_send.
200
 * \see msg_send
201
 * \param source send socket
202
 * \param buf sent data
203
 * \param len data length in bytes
204
 * \param to destination address
205
 * \return -1 on error, the return value from sento on success
206
 */
207
static int proto_udp_send(const struct socket_info* source,
208
    char* buf, unsigned int len, const union sockaddr_union* to,
209
    unsigned int id)
210
0
{
211
0
  int n, tolen;
212
213
0
  tolen=sockaddru_len(*to);
214
0
again:
215
0
  n=sendto(source->socket, buf, len, 0, &to->s, tolen);
216
0
  if (n==-1){
217
0
    if (errno==EINTR || errno==EAGAIN) goto again;
218
0
    LM_ERR("sendto(sock,%p,%d,0,%p,%d): %s(%d) [%s:%hu]\n", buf,len,to,
219
0
        tolen,strerror(errno),errno,inet_ntoa(to->sin.sin_addr),
220
0
        ntohs(to->sin.sin_port));
221
0
    if (errno==EINVAL) {
222
0
      LM_CRIT("invalid sendtoparameters\n"
223
0
      "one possible reason is the server is bound to localhost and\n"
224
0
      "attempts to send to the net\n");
225
0
    }
226
0
  }
227
0
  return n;
228
0
}
229
230
231
int register_udprecv_cb(udp_rcv_cb_f* func, void* param, char a, char b)
232
0
{
233
0
  callback_list* new;
234
235
0
  new = (callback_list*) pkg_malloc(sizeof(callback_list));
236
0
  if(!new){
237
0
    LM_ERR("out of pkg memory\n");
238
0
    return -1;
239
0
  }
240
0
  memset(new, 0, sizeof(callback_list));
241
242
0
  new->func = func;
243
0
  new->param = param;
244
0
  new->a = a;
245
0
  new->b = b;
246
0
  new->next = NULL;
247
248
0
  if(!cb_list){
249
0
    cb_list = new;
250
0
  }else{
251
0
    new->next = cb_list;
252
0
    cb_list = new;
253
0
  }
254
255
0
  return 0;
256
0
}
257
258
259
260