/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 | | |