blob: dd7527c3c31a1c3248b160d4cd10d899a0b50c26 [file] [log] [blame]
dburgess82c46ff2011-10-07 02:40:51 +00001/*
2* Copyright 2008, 2010 Free Software Foundation, Inc.
3*
4*
5* This software is distributed under the terms of the GNU Affero Public License.
6* See the COPYING file in the main directory for details.
7*
8* This use of this software may be subject to additional restrictions.
9* See the LEGAL file in the main directory for details.
10
11 This program is free software: you can redistribute it and/or modify
12 it under the terms of the GNU Affero General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU Affero General Public License for more details.
20
21 You should have received a copy of the GNU Affero General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23
24*/
25
26
27
kurtis.heimerl0775c802012-12-17 11:22:04 +000028#include <config.h>
dburgess82c46ff2011-10-07 02:40:51 +000029#include <unistd.h>
30#include <fcntl.h>
31#include <cstdio>
32#include <sys/select.h>
33
34#include "Threads.h"
35#include "Sockets.h"
36#include <stdio.h>
37#include <unistd.h>
38#include <fcntl.h>
39
40#include <string.h>
41#include <stdlib.h>
42
43
kurtis.heimerl5a872472013-05-31 21:47:25 +000044
45
46
47
dburgess82c46ff2011-10-07 02:40:51 +000048bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
49{
50 assert(address);
51 assert(hostAndPort);
52 char *copy = strdup(hostAndPort);
53 char *colon = strchr(copy,':');
54 if (!colon) return false;
55 *colon = '\0';
56 char *host = copy;
57 unsigned port = strtol(colon+1,NULL,10);
58 bool retVal = resolveAddress(address,host,port);
59 free(copy);
60 return retVal;
61}
62
63bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
64{
65 assert(address);
66 assert(host);
dburgess82c46ff2011-10-07 02:40:51 +000067 // FIXME -- Need to ignore leading/trailing spaces in hostname.
kurtis.heimerl0775c802012-12-17 11:22:04 +000068 struct hostent *hp;
69 int h_errno_local;
70#ifdef HAVE_GETHOSTBYNAME2_R
71 struct hostent hostData;
72 char tmpBuffer[2048];
73
74 // There are different flavors of gethostbyname_r(), but
75 // latest Linux use the following form:
76 if (gethostbyname2_r(host, AF_INET, &hostData, tmpBuffer, sizeof(tmpBuffer), &hp, &h_errno_local)!=0) {
77 CERR("WARNING -- gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local));
dburgess82c46ff2011-10-07 02:40:51 +000078 return false;
79 }
kurtis.heimerl0775c802012-12-17 11:22:04 +000080#else
81 static Mutex sGethostbynameMutex;
82 // gethostbyname() is NOT thread-safe, so we should use a mutex here.
83 // Ideally it should be a global mutex for all non thread-safe socket
84 // operations and it should protect access to variables such as
85 // global h_errno.
86 sGethostbynameMutex.lock();
87 hp = gethostbyname(host);
88 h_errno_local = h_errno;
89 sGethostbynameMutex.unlock();
90#endif
91 if (hp==NULL) {
92 CERR("WARNING -- gethostbyname() failed for " << host << ", " << hstrerror(h_errno_local));
93 return false;
94 }
95 if (hp->h_addrtype != AF_INET) {
96 CERR("WARNING -- gethostbyname() resolved " << host << " to something other then AF_INET");
97 return false;
98 }
99 address->sin_family = hp->h_addrtype;
100 assert(sizeof(address->sin_addr) == hp->h_length);
101 memcpy(&(address->sin_addr), hp->h_addr_list[0], hp->h_length);
dburgess82c46ff2011-10-07 02:40:51 +0000102 address->sin_port = htons(port);
103 return true;
104}
105
106
107
108DatagramSocket::DatagramSocket()
109{
kurtis.heimerl0775c802012-12-17 11:22:04 +0000110 memset(mDestination, 0, sizeof(mDestination));
dburgess82c46ff2011-10-07 02:40:51 +0000111}
112
113
114
115
116
117void DatagramSocket::nonblocking()
118{
119 fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
120}
121
122void DatagramSocket::blocking()
123{
124 fcntl(mSocketFD,F_SETFL,0);
125}
126
127void DatagramSocket::close()
128{
129 ::close(mSocketFD);
130}
131
132
133DatagramSocket::~DatagramSocket()
134{
135 close();
136}
137
138
139
140
141
142int DatagramSocket::write( const char * message, size_t length )
143{
144 assert(length<=MAX_UDP_LENGTH);
145 int retVal = sendto(mSocketFD, message, length, 0,
146 (struct sockaddr *)mDestination, addressSize());
147 if (retVal == -1 ) perror("DatagramSocket::write() failed");
148 return retVal;
149}
150
151int DatagramSocket::writeBack( const char * message, size_t length )
152{
153 assert(length<=MAX_UDP_LENGTH);
154 int retVal = sendto(mSocketFD, message, length, 0,
155 (struct sockaddr *)mSource, addressSize());
156 if (retVal == -1 ) perror("DatagramSocket::write() failed");
157 return retVal;
158}
159
160
161
162int DatagramSocket::write( const char * message)
163{
164 size_t length=strlen(message)+1;
165 return write(message,length);
166}
167
168int DatagramSocket::writeBack( const char * message)
169{
170 size_t length=strlen(message)+1;
171 return writeBack(message,length);
172}
173
174
175
176int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
177{
178 assert(length<=MAX_UDP_LENGTH);
179 int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
180 if (retVal == -1 ) perror("DatagramSocket::send() failed");
181 return retVal;
182}
183
184int DatagramSocket::send(const struct sockaddr* dest, const char * message)
185{
186 size_t length=strlen(message)+1;
187 return send(dest,message,length);
188}
189
190
191
192
193
194int DatagramSocket::read(char* buffer)
195{
196 socklen_t temp_len = sizeof(mSource);
197 int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0,
198 (struct sockaddr*)&mSource,&temp_len);
199 if ((length==-1) && (errno!=EAGAIN)) {
200 perror("DatagramSocket::read() failed");
201 throw SocketError();
202 }
203 return length;
204}
205
206
207int DatagramSocket::read(char* buffer, unsigned timeout)
208{
209 fd_set fds;
kurtis.heimerl0aaabd42012-11-23 08:35:46 +0000210 FD_ZERO(&fds);
kurtis.heimerl9eafbe92012-11-23 08:38:04 +0000211 FD_SET(mSocketFD,&fds);
dburgess82c46ff2011-10-07 02:40:51 +0000212 struct timeval tv;
213 tv.tv_sec = timeout/1000;
214 tv.tv_usec = (timeout%1000)*1000;
215 int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
216 if (sel<0) {
217 perror("DatagramSocket::read() select() failed");
218 throw SocketError();
219 }
220 if (sel==0) return -1;
kurtis.heimerla7fee632012-11-23 08:36:18 +0000221 if (FD_ISSET(mSocketFD,&fds)) return read(buffer);
222 return -1;
dburgess82c46ff2011-10-07 02:40:51 +0000223}
224
225
226
227
228
229
230UDPSocket::UDPSocket(unsigned short wSrcPort)
231 :DatagramSocket()
232{
233 open(wSrcPort);
234}
235
236
237UDPSocket::UDPSocket(unsigned short wSrcPort,
238 const char * wDestIP, unsigned short wDestPort )
239 :DatagramSocket()
240{
241 open(wSrcPort);
242 destination(wDestPort, wDestIP);
243}
244
245
246
247void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
248{
249 resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
250}
251
252
253void UDPSocket::open(unsigned short localPort)
254{
255 // create
256 mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
257 if (mSocketFD<0) {
258 perror("socket() failed");
259 throw SocketError();
260 }
261
kurtis.heimerl5a872472013-05-31 21:47:25 +0000262 // pat added: This lets the socket be reused immediately, which is needed if OpenBTS crashes.
263 int on = 1;
264 setsockopt(mSocketFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
265
266
dburgess82c46ff2011-10-07 02:40:51 +0000267 // bind
268 struct sockaddr_in address;
269 size_t length = sizeof(address);
270 bzero(&address,length);
271 address.sin_family = AF_INET;
272 address.sin_addr.s_addr = INADDR_ANY;
273 address.sin_port = htons(localPort);
274 if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
275 perror("bind() failed");
276 throw SocketError();
277 }
278}
279
280
281
282unsigned short UDPSocket::port() const
283{
284 struct sockaddr_in name;
285 socklen_t nameSize = sizeof(name);
286 int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
287 if (retVal==-1) throw SocketError();
288 return ntohs(name.sin_port);
289}
290
291
292
293
294
295UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
296 :DatagramSocket()
297{
298 if (localPath!=NULL) open(localPath);
299 if (remotePath!=NULL) destination(remotePath);
300}
301
302
303
304void UDDSocket::open(const char* localPath)
305{
306 // create
307 mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
308 if (mSocketFD<0) {
309 perror("socket() failed");
310 throw SocketError();
311 }
312
313 // bind
314 struct sockaddr_un address;
315 size_t length = sizeof(address);
316 bzero(&address,length);
317 address.sun_family = AF_UNIX;
318 strcpy(address.sun_path,localPath);
319 unlink(localPath);
320 if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
321 perror("bind() failed");
322 throw SocketError();
323 }
324}
325
326
327
328void UDDSocket::destination(const char* remotePath)
329{
330 struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
331 strcpy(unAddr->sun_path,remotePath);
332}
333
334
335
336
337// vim:ts=4:sw=4