New JackWinCondVar class.
[jack2.git] / posix / JackNetUnixSocket.cpp
blobf4a1b94225bc67b6f9dc12806c079311e9d80bf5
1 /*
2 Copyright (C) 2008-2011 Romain Moret at Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "JackNetUnixSocket.h"
21 #include "JackError.h"
23 #include <unistd.h>
24 #include <fcntl.h>
26 namespace Jack
28 //utility *********************************************************************************************************
29 int GetHostName(char * name, int size)
31 if (gethostname(name, size) == SOCKET_ERROR) {
32 jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
33 strcpy(name, "default");
34 return SOCKET_ERROR;
36 return 0;
39 //construct/destruct***********************************************************************************************
40 JackNetUnixSocket::JackNetUnixSocket()
42 fSockfd = 0;
43 fPort = 0;
44 fTimeOut = 0;
45 fSendAddr.sin_family = AF_INET;
46 fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
47 memset(&fSendAddr.sin_zero, 0, 8);
48 fRecvAddr.sin_family = AF_INET;
49 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
50 memset(&fRecvAddr.sin_zero, 0, 8);
53 JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
55 fSockfd = 0;
56 fPort = port;
57 fTimeOut = 0;
58 fSendAddr.sin_family = AF_INET;
59 fSendAddr.sin_port = htons(port);
60 inet_aton(ip, &fSendAddr.sin_addr);
61 memset(&fSendAddr.sin_zero, 0, 8);
62 fRecvAddr.sin_family = AF_INET;
63 fRecvAddr.sin_port = htons(port);
64 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
65 memset(&fRecvAddr.sin_zero, 0, 8);
68 JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
70 fSockfd = 0;
71 fTimeOut = 0;
72 fPort = socket.fPort;
73 fSendAddr = socket.fSendAddr;
74 fRecvAddr = socket.fRecvAddr;
77 JackNetUnixSocket::~JackNetUnixSocket()
79 Close();
82 JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
84 if (this != &socket) {
85 fSockfd = 0;
86 fPort = socket.fPort;
87 fSendAddr = socket.fSendAddr;
88 fRecvAddr = socket.fRecvAddr;
90 return *this;
93 //socket***********************************************************************************************************
94 int JackNetUnixSocket::NewSocket()
96 if (fSockfd) {
97 Close();
98 Reset();
100 fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
102 /* Enable address reuse */
103 int res, on = 1;
104 #ifdef __APPLE__
105 if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
106 #else
107 if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
108 #endif
109 StrError(NET_ERROR_CODE);
111 return fSockfd;
114 bool JackNetUnixSocket::IsLocal(char* ip)
116 if (strcmp(ip, "127.0.0.1") == 0) {
117 return true;
120 char host_name[32];
121 gethostname(host_name, sizeof(host_name));
123 struct hostent* host = gethostbyname(host_name);
124 if (host) {
125 for (int i = 0; host->h_addr_list[i] != 0; ++i) {
126 struct in_addr addr;
127 memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
128 if (strcmp(inet_ntoa(addr), ip) == 0) {
129 return true;
132 return false;
133 } else {
134 return false;
138 int JackNetUnixSocket::Bind()
140 return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
143 int JackNetUnixSocket::BindWith(const char* ip)
145 int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
146 if (addr_conv < 0)
147 return addr_conv;
148 return Bind();
151 int JackNetUnixSocket::BindWith(int port)
153 fRecvAddr.sin_port = htons(port);
154 return Bind();
157 int JackNetUnixSocket::Connect()
159 return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
162 int JackNetUnixSocket::ConnectTo(const char* ip)
164 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
165 if (addr_conv < 0)
166 return addr_conv;
167 return Connect();
170 void JackNetUnixSocket::Close()
172 if (fSockfd)
173 close(fSockfd);
174 fSockfd = 0;
177 void JackNetUnixSocket::Reset()
179 fSendAddr.sin_family = AF_INET;
180 fSendAddr.sin_port = htons(fPort);
181 fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
182 memset(&fSendAddr.sin_zero, 0, 8);
183 fRecvAddr.sin_family = AF_INET;
184 fRecvAddr.sin_port = htons(fPort);
185 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
186 memset(&fRecvAddr.sin_zero, 0, 8);
189 bool JackNetUnixSocket::IsSocket()
191 return(fSockfd) ? true : false;
194 //IP/PORT***********************************************************************************************************
195 void JackNetUnixSocket::SetPort(int port)
197 fPort = port;
198 fSendAddr.sin_port = htons(port);
199 fRecvAddr.sin_port = htons(port);
202 int JackNetUnixSocket::GetPort()
204 return fPort;
207 //address***********************************************************************************************************
208 int JackNetUnixSocket::SetAddress(const char* ip, int port)
210 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
211 if (addr_conv < 0)
212 return addr_conv;
213 fSendAddr.sin_port = htons(port);
214 return 0;
217 char* JackNetUnixSocket::GetSendIP()
219 return inet_ntoa(fSendAddr.sin_addr);
222 char* JackNetUnixSocket::GetRecvIP()
224 return inet_ntoa(fRecvAddr.sin_addr);
227 //utility************************************************************************************************************
228 int JackNetUnixSocket::GetName(char* name)
230 return gethostname(name, 255);
233 int JackNetUnixSocket::JoinMCastGroup(const char* ip)
235 struct ip_mreq multicast_req;
236 inet_aton(ip, &multicast_req.imr_multiaddr);
237 multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
238 return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
241 //options************************************************************************************************************
242 int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
244 return setsockopt(fSockfd, level, optname, optval, optlen);
247 int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
249 return getsockopt(fSockfd, level, optname, optval, optlen);
252 //timeout************************************************************************************************************
254 #if defined(__sun__) || defined(sun)
255 int JackNetUnixSocket::SetTimeOut(int us)
257 int flags;
258 fTimeOut = us;
260 if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
261 jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
262 return -1;
265 flags |= O_NONBLOCK;
266 if (fcntl(fSockfd, F_SETFL, flags) < 0) {
267 jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
268 return 1;
271 return 0;
274 int JackNetUnixSocket::WaitRead()
276 if (fTimeOut > 0) {
278 struct timeval tv;
279 fd_set fdset;
280 ssize_t res;
282 tv.tv_sec = fTimeOut / 1000000;
283 tv.tv_usec = fTimeOut % 1000000;
285 FD_ZERO(&fdset);
286 FD_SET(fSockfd, &fdset);
288 do {
289 res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
290 } while(res < 0 && errno == EINTR);
292 if (res < 0) {
293 return res;
294 } else if (res == 0) {
295 errno = ETIMEDOUT;
296 return -1;
300 return 0;
303 int JackNetUnixSocket::WaitWrite()
305 if (fTimeOut > 0) {
307 struct timeval tv;
308 fd_set fdset;
309 ssize_t res;
311 tv.tv_sec = fTimeOut / 1000000;
312 tv.tv_usec = fTimeOut % 1000000;
314 FD_ZERO(&fdset);
315 FD_SET(fSockfd, &fdset);
317 do {
318 res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
319 } while(res < 0 && errno == EINTR);
321 if (res < 0) {
322 return res;
323 } else if (res == 0) {
324 errno = ETIMEDOUT;
325 return -1;
329 return 0;
332 #else
333 int JackNetUnixSocket::SetTimeOut(int us)
335 jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
336 struct timeval timeout;
338 //less than 1sec
339 if (us < 1000000) {
340 timeout.tv_sec = 0;
341 timeout.tv_usec = us;
342 } else {
343 //more than 1sec
344 float sec = float(us) / 1000000.f;
345 timeout.tv_sec = (int)sec;
346 float usec = (sec - float(timeout.tv_sec)) * 1000000;
347 timeout.tv_usec =(int)usec;
349 return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
351 #endif
353 //local loop**********************************************************************************************************
354 int JackNetUnixSocket::SetLocalLoop()
356 char disable = 0;
357 return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
360 //network operations**************************************************************************************************
361 int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
363 #if defined(__sun__) || defined(sun)
364 if (WaitWrite() < 0)
365 return -1;
366 #endif
367 return sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
370 int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
372 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
373 if (addr_conv < 1)
374 return addr_conv;
375 #if defined(__sun__) || defined(sun)
376 if (WaitWrite() < 0)
377 return -1;
378 #endif
379 return SendTo(buffer, nbytes, flags);
382 int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
384 #if defined(__sun__) || defined(sun)
385 if (WaitWrite() < 0)
386 return -1;
387 #endif
388 return send(fSockfd, buffer, nbytes, flags);
391 int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
393 socklen_t addr_len = sizeof(socket_address_t);
394 #if defined(__sun__) || defined(sun)
395 if (WaitRead() < 0)
396 return -1;
397 #endif
398 return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len);
401 int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
403 #if defined(__sun__) || defined(sun)
404 if (WaitRead() < 0)
405 return -1;
406 #endif
407 return recv(fSockfd, buffer, nbytes, flags);
410 int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
412 socklen_t addr_len = sizeof(socket_address_t);
413 #if defined(__sun__) || defined(sun)
414 if (WaitRead() < 0)
415 return -1;
416 #endif
417 return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len);
420 net_error_t JackNetUnixSocket::GetError()
422 switch(errno)
424 case EAGAIN:
425 case ETIMEDOUT:
426 return NET_NO_DATA;
428 case ECONNABORTED:
429 case ECONNREFUSED:
430 case ECONNRESET:
431 case EINVAL:
432 case EHOSTDOWN:
433 case EHOSTUNREACH:
434 case ENETDOWN:
435 case ENETUNREACH:
436 return NET_CONN_ERROR;
438 default:
439 //return NET_OP_ERROR;
440 return NET_CONN_ERROR;