2 Copyright (C) 2002-2005 Thomas Ries <tries@gmx.net>
4 This file is part of Siproxd.
6 Siproxd 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.
11 Siproxd 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.
16 You should have received a copy of the GNU General Public License
17 along with Siproxd; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
36 #include <osipparser2/osip_parser.h>
41 static char const ident[]="$Id: sock.c,v 1.29 2005/01/08 10:05:13 hb9xar Exp $";
44 /* configuration storage */
45 extern struct siproxd_config configuration;
47 /* socket used for sending SIP datagrams */
52 * binds to SIP UDP socket for listening to incoming packets
55 * STS_SUCCESS on success
56 * STS_FAILURE on error
58 int sipsock_listen (void) {
59 struct in_addr ipaddr;
61 memset(&ipaddr, 0, sizeof(ipaddr));
62 sip_udp_socket=sockbind(ipaddr, configuration.sip_listen_port, 1);
63 if (sip_udp_socket == 0) return STS_FAILURE; /* failure*/
65 INFO("bound to port %i", configuration.sip_listen_port);
66 DEBUGC(DBCLASS_NET,"bound socket %i",sip_udp_socket);
71 * Wait for incoming SIP message. After a 2 sec timeout
72 * this function returns with sts=0
74 * RETURNS >0 if data received, =0 if nothing received /T/O), -1 on error
76 int sipsock_wait(void) {
79 struct timeval timeout;
85 FD_SET (sip_udp_socket, &fdset);
86 sts=select (sip_udp_socket+1, &fdset, NULL, NULL, &timeout);
88 /* WARN on failures */
90 /* WARN on failure, except if it is an "interrupted system call"
91 as it will result by SIGINT, SIGTERM */
93 WARN("select() returned error [%i:%s]",errno, strerror(errno));
95 DEBUGC(DBCLASS_NET,"select() returned error [%i:%s]",
96 errno, strerror(errno));
104 * read a message from SIP listen socket (UDP datagram)
106 * RETURNS number of bytes read
107 * from is modified to return the sockaddr_in of the sender
109 int sipsock_read(void *buf, size_t bufsize,
110 struct sockaddr_in *from, int *protocol) {
114 fromlen=sizeof(struct sockaddr_in);
115 *protocol = PROTO_UDP; /* up to now, unly UDP */
116 count=recvfrom(sip_udp_socket, buf, bufsize, 0,
117 (struct sockaddr *)from, &fromlen);
120 WARN("recvfrom() returned error [%s]",strerror(errno));
121 *protocol = PROTO_UNKN;
124 DEBUGC(DBCLASS_NET,"received UDP packet from %s, count=%i",
125 utils_inet_ntoa(from->sin_addr), count);
126 DUMP_BUFFER(DBCLASS_NETTRAF, buf, count);
133 * sends an UDP datagram to the specified destination
136 * STS_SUCCESS on success
137 * STS_FAILURE on error
139 int sipsock_send(struct in_addr addr, int port, int protocol,
140 char *buffer, int size) {
141 struct sockaddr_in dst_addr;
144 /* first time: allocate a socket for sending */
145 if (sip_udp_socket == 0) {
146 ERROR("SIP socket not allocated");
150 if (buffer == NULL) {
151 ERROR("sipsock_send got NULL buffer");
155 if (protocol != PROTO_UDP) {
156 ERROR("sipsock_send: only UDP supported by now");
160 dst_addr.sin_family = AF_INET;
161 memcpy(&dst_addr.sin_addr.s_addr, &addr, sizeof(struct in_addr));
162 dst_addr.sin_port= htons(port);
164 DEBUGC(DBCLASS_NET,"send UDP packet to %s: %i", utils_inet_ntoa(addr),port);
165 DUMP_BUFFER(DBCLASS_NETTRAF, buffer, size);
167 sts = sendto(sip_udp_socket, buffer, size, 0,
168 (const struct sockaddr *)&dst_addr,
169 (socklen_t)sizeof(dst_addr));
172 if (errno != ECONNREFUSED) {
173 ERROR("sendto() [%s:%i size=%i] call failed: %s",
174 utils_inet_ntoa(addr),
175 port, size, strerror(errno));
178 DEBUGC(DBCLASS_BABBLE,"sendto() [%s:%i] call failed: %s",
179 utils_inet_ntoa(addr), port, strerror(errno));
188 * generic routine to allocate and bind a socket to a specified
189 * local address and port (UDP)
190 * errflg !=0 log errors, ==0 don't
192 * RETURNS socket number on success, zero on failure
194 int sockbind(struct in_addr ipaddr, int localport, int errflg) {
195 struct sockaddr_in my_addr;
200 memset(&my_addr, 0, sizeof(my_addr));
202 my_addr.sin_family = AF_INET;
203 memcpy(&my_addr.sin_addr.s_addr, &ipaddr, sizeof(struct in_addr));
204 my_addr.sin_port = htons(localport);
206 sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
208 ERROR("socket() call failed: %s",strerror(errno));
212 sts=bind(sock, (struct sockaddr *)&my_addr, sizeof(my_addr));
214 if (errflg) ERROR("bind failed: %s",strerror(errno));
220 * It has been seen on linux 2.2.x systems that for some
221 * reason (bug?) inside the RTP relay, select()
222 * claims that a certain file descriptor has data available to
223 * read, a subsequent call to read() or recv() then does block!!
224 * So lets make the FD's we are going to use non-blocking, so
225 * we will at least survive and not run into a deadlock.
227 * There is a way to (more or less) reproduce this effect:
228 * Make a local UA to local UA call and then very quickly do
229 * HOLD/unHOLD, several times.
231 flags = fcntl(sock, F_GETFL);
233 ERROR("fcntl(F_SETFL) failed: %s",strerror(errno));
237 if (fcntl(sock, F_SETFL, (long) flags | O_NONBLOCK) < 0) {
238 ERROR("fcntl(F_SETFL) failed: %s",strerror(errno));