Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / siproxd / src / sock.c
1 /*
2     Copyright (C) 2002-2005  Thomas Ries <tries@gmx.net>
3
4     This file is part of Siproxd.
5     
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.
10     
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.
15     
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 
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29
30 #include <sys/time.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <osipparser2/osip_parser.h>
37
38 #include "siproxd.h"
39 #include "log.h"
40
41 static char const ident[]="$Id: sock.c,v 1.29 2005/01/08 10:05:13 hb9xar Exp $";
42
43
44 /* configuration storage */
45 extern struct siproxd_config configuration;
46
47 /* socket used for sending SIP datagrams */
48 int sip_udp_socket=0;
49
50
51 /*
52  * binds to SIP UDP socket for listening to incoming packets
53  *
54  * RETURNS
55  *      STS_SUCCESS on success
56  *      STS_FAILURE on error
57  */
58 int sipsock_listen (void) {
59    struct in_addr ipaddr;
60
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*/
64
65    INFO("bound to port %i", configuration.sip_listen_port);
66    DEBUGC(DBCLASS_NET,"bound socket %i",sip_udp_socket);
67    return STS_SUCCESS;
68 }
69
70 /*
71  * Wait for incoming SIP message. After a 2 sec timeout
72  * this function returns with sts=0
73  *
74  * RETURNS >0 if data received, =0 if nothing received /T/O), -1 on error
75  */
76 int sipsock_wait(void) {
77    int sts;
78    fd_set fdset;
79    struct timeval timeout;
80
81    timeout.tv_sec=2;
82    timeout.tv_usec=0;
83
84    FD_ZERO(&fdset);
85    FD_SET (sip_udp_socket, &fdset);
86    sts=select (sip_udp_socket+1, &fdset, NULL, NULL, &timeout);
87
88    /* WARN on failures */
89    if (sts<0) {
90       /* WARN on failure, except if it is an "interrupted system call"
91          as it will result by SIGINT, SIGTERM */
92       if (errno != 4) {
93          WARN("select() returned error [%i:%s]",errno, strerror(errno));
94       } else {
95          DEBUGC(DBCLASS_NET,"select() returned error [%i:%s]",
96                 errno, strerror(errno));
97       }
98    }
99  
100    return sts;
101 }
102
103 /*
104  * read a message from SIP listen socket (UDP datagram)
105  *
106  * RETURNS number of bytes read
107  *         from is modified to return the sockaddr_in of the sender
108  */
109 int sipsock_read(void *buf, size_t bufsize,
110                  struct sockaddr_in *from, int *protocol) {
111    int count;
112    socklen_t fromlen;
113
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);
118
119    if (count<0) {
120       WARN("recvfrom() returned error [%s]",strerror(errno));
121       *protocol = PROTO_UNKN;
122    }
123
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);
127
128    return count;
129 }
130
131
132 /*
133  * sends an UDP datagram to the specified destination
134  *
135  * RETURNS
136  *      STS_SUCCESS on success
137  *      STS_FAILURE on error
138  */
139 int sipsock_send(struct in_addr addr, int port, int protocol,
140                  char *buffer, int size) {
141    struct sockaddr_in dst_addr;
142    int sts;
143
144    /* first time: allocate a socket for sending */
145    if (sip_udp_socket == 0) {
146       ERROR("SIP socket not allocated");
147       return STS_FAILURE;
148    }
149
150    if (buffer == NULL) {
151       ERROR("sipsock_send got NULL buffer");
152       return STS_FAILURE;
153    }
154
155    if (protocol != PROTO_UDP) {
156       ERROR("sipsock_send: only UDP supported by now");
157       return STS_FAILURE;
158    }
159
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);
163
164    DEBUGC(DBCLASS_NET,"send UDP packet to %s: %i", utils_inet_ntoa(addr),port);
165    DUMP_BUFFER(DBCLASS_NETTRAF, buffer, size);
166
167    sts = sendto(sip_udp_socket, buffer, size, 0,
168                 (const struct sockaddr *)&dst_addr,
169                 (socklen_t)sizeof(dst_addr));
170    
171    if (sts == -1) {
172       if (errno != ECONNREFUSED) {
173          ERROR("sendto() [%s:%i size=%i] call failed: %s",
174                utils_inet_ntoa(addr),
175                port, size, strerror(errno));
176          return STS_FAILURE;
177       }
178       DEBUGC(DBCLASS_BABBLE,"sendto() [%s:%i] call failed: %s",
179              utils_inet_ntoa(addr), port, strerror(errno));
180    }
181
182    return STS_SUCCESS;
183 }
184
185
186
187 /*
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
191  *
192  * RETURNS socket number on success, zero on failure
193  */
194 int sockbind(struct in_addr ipaddr, int localport, int errflg) {
195    struct sockaddr_in my_addr;
196    int sts;
197    int sock;
198    int flags;
199
200    memset(&my_addr, 0, sizeof(my_addr));
201
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);
205
206    sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
207    if (sock < 0) {
208       ERROR("socket() call failed: %s",strerror(errno));
209       return 0;
210    }
211
212    sts=bind(sock, (struct sockaddr *)&my_addr, sizeof(my_addr));
213    if (sts != 0) {
214       if (errflg) ERROR("bind failed: %s",strerror(errno));
215       close(sock);
216       return 0;
217    }
218
219    /*
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.
226     *
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.
230     */
231    flags = fcntl(sock, F_GETFL);
232    if (flags < 0) {
233       ERROR("fcntl(F_SETFL) failed: %s",strerror(errno));
234       close(sock);
235       return 0;
236    }
237    if (fcntl(sock, F_SETFL, (long) flags | O_NONBLOCK) < 0) {
238       ERROR("fcntl(F_SETFL) failed: %s",strerror(errno));
239       close(sock);
240       return 0;
241    }
242
243    return sock;
244 }