blob: dc110c885472268706ee7439419beec4a6671ff4 [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
dburgess82c46ff2011-10-07 02:40:51 +000044bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
45{
46 assert(address);
47 assert(hostAndPort);
48 char *copy = strdup(hostAndPort);
49 char *colon = strchr(copy,':');
50 if (!colon) return false;
51 *colon = '\0';
52 char *host = copy;
53 unsigned port = strtol(colon+1,NULL,10);
54 bool retVal = resolveAddress(address,host,port);
55 free(copy);
56 return retVal;
57}
58
59bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
60{
61 assert(address);
62 assert(host);
dburgess82c46ff2011-10-07 02:40:51 +000063 // FIXME -- Need to ignore leading/trailing spaces in hostname.
kurtis.heimerl0775c802012-12-17 11:22:04 +000064 struct hostent *hp;
65 int h_errno_local;
66#ifdef HAVE_GETHOSTBYNAME2_R
67 struct hostent hostData;
68 char tmpBuffer[2048];
69
70 // There are different flavors of gethostbyname_r(), but
71 // latest Linux use the following form:
72 if (gethostbyname2_r(host, AF_INET, &hostData, tmpBuffer, sizeof(tmpBuffer), &hp, &h_errno_local)!=0) {
73 CERR("WARNING -- gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local));
dburgess82c46ff2011-10-07 02:40:51 +000074 return false;
75 }
kurtis.heimerl0775c802012-12-17 11:22:04 +000076#else
77 static Mutex sGethostbynameMutex;
78 // gethostbyname() is NOT thread-safe, so we should use a mutex here.
79 // Ideally it should be a global mutex for all non thread-safe socket
80 // operations and it should protect access to variables such as
81 // global h_errno.
82 sGethostbynameMutex.lock();
83 hp = gethostbyname(host);
84 h_errno_local = h_errno;
85 sGethostbynameMutex.unlock();
86#endif
87 if (hp==NULL) {
88 CERR("WARNING -- gethostbyname() failed for " << host << ", " << hstrerror(h_errno_local));
89 return false;
90 }
91 if (hp->h_addrtype != AF_INET) {
92 CERR("WARNING -- gethostbyname() resolved " << host << " to something other then AF_INET");
93 return false;
94 }
95 address->sin_family = hp->h_addrtype;
96 assert(sizeof(address->sin_addr) == hp->h_length);
97 memcpy(&(address->sin_addr), hp->h_addr_list[0], hp->h_length);
dburgess82c46ff2011-10-07 02:40:51 +000098 address->sin_port = htons(port);
99 return true;
100}
101
102
103
104DatagramSocket::DatagramSocket()
105{
kurtis.heimerl0775c802012-12-17 11:22:04 +0000106 memset(mDestination, 0, sizeof(mDestination));
dburgess82c46ff2011-10-07 02:40:51 +0000107}
108
109
110
111
112
113void DatagramSocket::nonblocking()
114{
115 fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
116}
117
118void DatagramSocket::blocking()
119{
120 fcntl(mSocketFD,F_SETFL,0);
121}
122
123void DatagramSocket::close()
124{
125 ::close(mSocketFD);
126}
127
128
129DatagramSocket::~DatagramSocket()
130{
131 close();
132}
133
134
135
136
137
138int DatagramSocket::write( const char * message, size_t length )
139{
140 assert(length<=MAX_UDP_LENGTH);
141 int retVal = sendto(mSocketFD, message, length, 0,
142 (struct sockaddr *)mDestination, addressSize());
143 if (retVal == -1 ) perror("DatagramSocket::write() failed");
144 return retVal;
145}
146
147int DatagramSocket::writeBack( const char * message, size_t length )
148{
149 assert(length<=MAX_UDP_LENGTH);
150 int retVal = sendto(mSocketFD, message, length, 0,
151 (struct sockaddr *)mSource, addressSize());
152 if (retVal == -1 ) perror("DatagramSocket::write() failed");
153 return retVal;
154}
155
156
157
158int DatagramSocket::write( const char * message)
159{
160 size_t length=strlen(message)+1;
161 return write(message,length);
162}
163
164int DatagramSocket::writeBack( const char * message)
165{
166 size_t length=strlen(message)+1;
167 return writeBack(message,length);
168}
169
170
171
172int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
173{
174 assert(length<=MAX_UDP_LENGTH);
175 int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
176 if (retVal == -1 ) perror("DatagramSocket::send() failed");
177 return retVal;
178}
179
180int DatagramSocket::send(const struct sockaddr* dest, const char * message)
181{
182 size_t length=strlen(message)+1;
183 return send(dest,message,length);
184}
185
186
187
188
189
190int DatagramSocket::read(char* buffer)
191{
192 socklen_t temp_len = sizeof(mSource);
193 int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0,
194 (struct sockaddr*)&mSource,&temp_len);
195 if ((length==-1) && (errno!=EAGAIN)) {
196 perror("DatagramSocket::read() failed");
197 throw SocketError();
198 }
199 return length;
200}
201
202
203int DatagramSocket::read(char* buffer, unsigned timeout)
204{
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;
kurtis.heimerla7fee632012-11-23 08:36:18 +0000217 if (FD_ISSET(mSocketFD,&fds)) return read(buffer);
218 return -1;
dburgess82c46ff2011-10-07 02:40:51 +0000219}
220
221
222
223
224
225
226UDPSocket::UDPSocket(unsigned short wSrcPort)
227 :DatagramSocket()
228{
229 open(wSrcPort);
230}
231
232
233UDPSocket::UDPSocket(unsigned short wSrcPort,
234 const char * wDestIP, unsigned short wDestPort )
235 :DatagramSocket()
236{
237 open(wSrcPort);
238 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
249void UDPSocket::open(unsigned short localPort)
250{
251 // create
252 mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
253 if (mSocketFD<0) {
254 perror("socket() failed");
255 throw SocketError();
256 }
257
258 // bind
259 struct sockaddr_in address;
260 size_t length = sizeof(address);
261 bzero(&address,length);
262 address.sin_family = AF_INET;
263 address.sin_addr.s_addr = INADDR_ANY;
264 address.sin_port = htons(localPort);
265 if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
266 perror("bind() failed");
267 throw SocketError();
268 }
269}
270
271
272
273unsigned short UDPSocket::port() const
274{
275 struct sockaddr_in name;
276 socklen_t nameSize = sizeof(name);
277 int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
278 if (retVal==-1) throw SocketError();
279 return ntohs(name.sin_port);
280}
281
282
283
284
285
286UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
287 :DatagramSocket()
288{
289 if (localPath!=NULL) open(localPath);
290 if (remotePath!=NULL) destination(remotePath);
291}
292
293
294
295void UDDSocket::open(const char* localPath)
296{
297 // create
298 mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
299 if (mSocketFD<0) {
300 perror("socket() failed");
301 throw SocketError();
302 }
303
304 // bind
305 struct sockaddr_un address;
306 size_t length = sizeof(address);
307 bzero(&address,length);
308 address.sun_family = AF_UNIX;
309 strcpy(address.sun_path,localPath);
310 unlink(localPath);
311 if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
312 perror("bind() failed");
313 throw SocketError();
314 }
315}
316
317
318
319void UDDSocket::destination(const char* remotePath)
320{
321 struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
322 strcpy(unAddr->sun_path,remotePath);
323}
324
325
326
327
328// vim:ts=4:sw=4