blob: 62841ad769b17d22bdecc9dc50a85937204529af [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
28#include <unistd.h>
29#include <fcntl.h>
30#include <cstdio>
31#include <sys/select.h>
32
33#include "Threads.h"
34#include "Sockets.h"
35#include <stdio.h>
36#include <unistd.h>
37#include <fcntl.h>
38
39#include <string.h>
40#include <stdlib.h>
41
42
kurtis.heimerld0093192011-12-24 02:53:10 +000043//mutex for protecting non-thread safe gethostbyname
44static Mutex sgGethostbynameLock;
dburgess82c46ff2011-10-07 02:40:51 +000045
46bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
47{
48 assert(address);
49 assert(hostAndPort);
50 char *copy = strdup(hostAndPort);
51 char *colon = strchr(copy,':');
52 if (!colon) return false;
53 *colon = '\0';
54 char *host = copy;
55 unsigned port = strtol(colon+1,NULL,10);
56 bool retVal = resolveAddress(address,host,port);
57 free(copy);
58 return retVal;
59}
60
61bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
62{
63 assert(address);
64 assert(host);
kurtis.heimerld0093192011-12-24 02:53:10 +000065 //gethostbyname not thread safe
66 ScopedLock lock(sgGethostbynameLock);
dburgess82c46ff2011-10-07 02:40:51 +000067 // FIXME -- Need to ignore leading/trailing spaces in hostname.
68 struct hostent *hp = gethostbyname(host);
69 if (hp==NULL) {
70 CERR("WARNING -- gethostbyname() failed for " << host << ", " << hstrerror(h_errno));
71 return false;
72 }
73 address->sin_family = AF_INET;
74 bcopy(hp->h_addr, &(address->sin_addr), hp->h_length);
75 address->sin_port = htons(port);
76 return true;
77}
78
79
80
81DatagramSocket::DatagramSocket()
82{
83 bzero(mDestination,sizeof(mDestination));
84}
85
86
87
88
89
90void DatagramSocket::nonblocking()
91{
92 fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
93}
94
95void DatagramSocket::blocking()
96{
97 fcntl(mSocketFD,F_SETFL,0);
98}
99
100void DatagramSocket::close()
101{
102 ::close(mSocketFD);
103}
104
105
106DatagramSocket::~DatagramSocket()
107{
108 close();
109}
110
111
112
113
114
115int DatagramSocket::write( const char * message, size_t length )
116{
117 assert(length<=MAX_UDP_LENGTH);
118 int retVal = sendto(mSocketFD, message, length, 0,
119 (struct sockaddr *)mDestination, addressSize());
120 if (retVal == -1 ) perror("DatagramSocket::write() failed");
121 return retVal;
122}
123
124int DatagramSocket::writeBack( const char * message, size_t length )
125{
126 assert(length<=MAX_UDP_LENGTH);
127 int retVal = sendto(mSocketFD, message, length, 0,
128 (struct sockaddr *)mSource, addressSize());
129 if (retVal == -1 ) perror("DatagramSocket::write() failed");
130 return retVal;
131}
132
133
134
135int DatagramSocket::write( const char * message)
136{
137 size_t length=strlen(message)+1;
138 return write(message,length);
139}
140
141int DatagramSocket::writeBack( const char * message)
142{
143 size_t length=strlen(message)+1;
144 return writeBack(message,length);
145}
146
147
148
149int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
150{
151 assert(length<=MAX_UDP_LENGTH);
152 int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
153 if (retVal == -1 ) perror("DatagramSocket::send() failed");
154 return retVal;
155}
156
157int DatagramSocket::send(const struct sockaddr* dest, const char * message)
158{
159 size_t length=strlen(message)+1;
160 return send(dest,message,length);
161}
162
163
164
165
166
167int DatagramSocket::read(char* buffer)
168{
169 socklen_t temp_len = sizeof(mSource);
170 int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0,
171 (struct sockaddr*)&mSource,&temp_len);
172 if ((length==-1) && (errno!=EAGAIN)) {
173 perror("DatagramSocket::read() failed");
174 throw SocketError();
175 }
176 return length;
177}
178
179
180int DatagramSocket::read(char* buffer, unsigned timeout)
181{
182 fd_set fds;
kurtis.heimerl0aaabd42012-11-23 08:35:46 +0000183 FD_ZERO(&fds);
dburgess82c46ff2011-10-07 02:40:51 +0000184 struct timeval tv;
185 tv.tv_sec = timeout/1000;
186 tv.tv_usec = (timeout%1000)*1000;
187 int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
188 if (sel<0) {
189 perror("DatagramSocket::read() select() failed");
190 throw SocketError();
191 }
192 if (sel==0) return -1;
kurtis.heimerla7fee632012-11-23 08:36:18 +0000193 if (FD_ISSET(mSocketFD,&fds)) return read(buffer);
194 return -1;
dburgess82c46ff2011-10-07 02:40:51 +0000195}
196
197
198
199
200
201
202UDPSocket::UDPSocket(unsigned short wSrcPort)
203 :DatagramSocket()
204{
205 open(wSrcPort);
206}
207
208
209UDPSocket::UDPSocket(unsigned short wSrcPort,
210 const char * wDestIP, unsigned short wDestPort )
211 :DatagramSocket()
212{
213 open(wSrcPort);
214 destination(wDestPort, wDestIP);
215}
216
217
218
219void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
220{
221 resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
222}
223
224
225void UDPSocket::open(unsigned short localPort)
226{
227 // create
228 mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
229 if (mSocketFD<0) {
230 perror("socket() failed");
231 throw SocketError();
232 }
233
234 // bind
235 struct sockaddr_in address;
236 size_t length = sizeof(address);
237 bzero(&address,length);
238 address.sin_family = AF_INET;
239 address.sin_addr.s_addr = INADDR_ANY;
240 address.sin_port = htons(localPort);
241 if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
242 perror("bind() failed");
243 throw SocketError();
244 }
245}
246
247
248
249unsigned short UDPSocket::port() const
250{
251 struct sockaddr_in name;
252 socklen_t nameSize = sizeof(name);
253 int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
254 if (retVal==-1) throw SocketError();
255 return ntohs(name.sin_port);
256}
257
258
259
260
261
262UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
263 :DatagramSocket()
264{
265 if (localPath!=NULL) open(localPath);
266 if (remotePath!=NULL) destination(remotePath);
267}
268
269
270
271void UDDSocket::open(const char* localPath)
272{
273 // create
274 mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
275 if (mSocketFD<0) {
276 perror("socket() failed");
277 throw SocketError();
278 }
279
280 // bind
281 struct sockaddr_un address;
282 size_t length = sizeof(address);
283 bzero(&address,length);
284 address.sun_family = AF_UNIX;
285 strcpy(address.sun_path,localPath);
286 unlink(localPath);
287 if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
288 perror("bind() failed");
289 throw SocketError();
290 }
291}
292
293
294
295void UDDSocket::destination(const char* remotePath)
296{
297 struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
298 strcpy(unAddr->sun_path,remotePath);
299}
300
301
302
303
304// vim:ts=4:sw=4