blob: ce8e3d5900d75d78fadd44cc5dc1e04d797d56ad [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
Tom Tsou2c650a62016-04-28 21:55:17 -0700190int DatagramSocket::read(char* buffer, size_t length)
dburgess82c46ff2011-10-07 02:40:51 +0000191{
Tom Tsou2c650a62016-04-28 21:55:17 -0700192 socklen_t addr_len = sizeof(mSource);
193 int rd_length = recvfrom(mSocketFD, (void *) buffer, length, 0,
194 (struct sockaddr*) &mSource, &addr_len);
195
196 if ((rd_length==-1) && (errno!=EAGAIN)) {
dburgess82c46ff2011-10-07 02:40:51 +0000197 perror("DatagramSocket::read() failed");
198 throw SocketError();
199 }
Tom Tsou2c650a62016-04-28 21:55:17 -0700200 return rd_length;
dburgess82c46ff2011-10-07 02:40:51 +0000201}
202
Tom Tsou2c650a62016-04-28 21:55:17 -0700203int DatagramSocket::read(char* buffer, size_t length, unsigned timeout)
dburgess82c46ff2011-10-07 02:40:51 +0000204{
205 fd_set fds;
kurtis.heimerl0aaabd42012-11-23 08:35:46 +0000206 FD_ZERO(&fds);
kurtis.heimerl9eafbe92012-11-23 08:38:04 +0000207 FD_SET(mSocketFD,&fds);
dburgess82c46ff2011-10-07 02:40:51 +0000208 struct timeval tv;
209 tv.tv_sec = timeout/1000;
210 tv.tv_usec = (timeout%1000)*1000;
211 int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
212 if (sel<0) {
213 perror("DatagramSocket::read() select() failed");
214 throw SocketError();
215 }
216 if (sel==0) return -1;
Tom Tsou2c650a62016-04-28 21:55:17 -0700217 if (FD_ISSET(mSocketFD,&fds)) return read(buffer, length);
kurtis.heimerla7fee632012-11-23 08:36:18 +0000218 return -1;
dburgess82c46ff2011-10-07 02:40:51 +0000219}
220
221
222
223
224
225
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200226UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort)
dburgess82c46ff2011-10-07 02:40:51 +0000227 :DatagramSocket()
228{
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200229 open(wSrcPort, wSrcIP);
dburgess82c46ff2011-10-07 02:40:51 +0000230}
231
232
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200233UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort,
234 const char *wDestIP, unsigned short wDestPort)
dburgess82c46ff2011-10-07 02:40:51 +0000235 :DatagramSocket()
236{
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200237 open(wSrcPort, wSrcIP);
dburgess82c46ff2011-10-07 02:40:51 +0000238 destination(wDestPort, wDestIP);
239}
240
241
242
243void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
244{
245 resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
246}
247
248
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200249void UDPSocket::open(unsigned short localPort, const char *wlocalIP)
dburgess82c46ff2011-10-07 02:40:51 +0000250{
251 // create
252 mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
253 if (mSocketFD<0) {
254 perror("socket() failed");
255 throw SocketError();
256 }
257
kurtis.heimerl5a872472013-05-31 21:47:25 +0000258 // pat added: This lets the socket be reused immediately, which is needed if OpenBTS crashes.
259 int on = 1;
260 setsockopt(mSocketFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
261
262
dburgess82c46ff2011-10-07 02:40:51 +0000263 // bind
264 struct sockaddr_in address;
265 size_t length = sizeof(address);
266 bzero(&address,length);
267 address.sin_family = AF_INET;
Pau Espin Pedrol8c800952017-08-16 16:53:23 +0200268 address.sin_addr.s_addr = inet_addr(wlocalIP);
dburgess82c46ff2011-10-07 02:40:51 +0000269 address.sin_port = htons(localPort);
270 if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
271 perror("bind() failed");
272 throw SocketError();
273 }
274}
275
276
277
278unsigned short UDPSocket::port() const
279{
280 struct sockaddr_in name;
281 socklen_t nameSize = sizeof(name);
282 int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
283 if (retVal==-1) throw SocketError();
284 return ntohs(name.sin_port);
285}
286
dburgess82c46ff2011-10-07 02:40:51 +0000287// vim:ts=4:sw=4