Fixes for alsa device reservation
[jack2.git] / posix / JackNetUnixSocket.cpp
blobe71b81d8f44fdb79c04d7a62f93d5c9567858fc2
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 <unistd.h>
22 #include <fcntl.h>
24 namespace Jack
26 //utility *********************************************************************************************************
27 int GetHostName(char * name, int size)
29 if (gethostname(name, size) == SOCKET_ERROR) {
30 jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
31 strcpy(name, "default");
32 return SOCKET_ERROR;
34 return 0;
37 //construct/destruct***********************************************************************************************
38 JackNetUnixSocket::JackNetUnixSocket()
40 fSockfd = 0;
41 fPort = 0;
42 fTimeOut = 0;
43 fSendAddr.sin_family = AF_INET;
44 fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
45 memset(&fSendAddr.sin_zero, 0, 8);
46 fRecvAddr.sin_family = AF_INET;
47 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
48 memset(&fRecvAddr.sin_zero, 0, 8);
51 JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
53 fSockfd = 0;
54 fPort = port;
55 fTimeOut = 0;
56 fSendAddr.sin_family = AF_INET;
57 fSendAddr.sin_port = htons(port);
58 inet_aton(ip, &fSendAddr.sin_addr);
59 memset(&fSendAddr.sin_zero, 0, 8);
60 fRecvAddr.sin_family = AF_INET;
61 fRecvAddr.sin_port = htons(port);
62 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
63 memset(&fRecvAddr.sin_zero, 0, 8);
66 JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
68 fSockfd = 0;
69 fTimeOut = 0;
70 fPort = socket.fPort;
71 fSendAddr = socket.fSendAddr;
72 fRecvAddr = socket.fRecvAddr;
75 JackNetUnixSocket::~JackNetUnixSocket()
77 Close();
80 JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
82 if (this != &socket) {
83 fSockfd = 0;
84 fPort = socket.fPort;
85 fSendAddr = socket.fSendAddr;
86 fRecvAddr = socket.fRecvAddr;
88 return *this;
91 //socket***********************************************************************************************************
92 int JackNetUnixSocket::NewSocket()
94 if (fSockfd) {
95 Close();
96 Reset();
98 fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
100 /* Enable address reuse */
101 int res, on = 1;
102 #ifdef __APPLE__
103 if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
104 #else
105 if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
106 #endif
107 StrError(NET_ERROR_CODE);
109 return fSockfd;
112 bool JackNetUnixSocket::IsLocal(char* ip)
114 if (strcmp(ip, "127.0.0.1") == 0) {
115 return true;
118 char host_name[32];
119 gethostname(host_name, sizeof(host_name));
121 struct hostent* host = gethostbyname(host_name);
122 if (host) {
123 for (int i = 0; host->h_addr_list[i] != 0; ++i) {
124 struct in_addr addr;
125 memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
126 if (strcmp(inet_ntoa(addr), ip) == 0) {
127 return true;
130 return false;
131 } else {
132 return false;
136 int JackNetUnixSocket::Bind()
138 return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
141 int JackNetUnixSocket::BindWith(const char* ip)
143 int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
144 if (addr_conv < 0)
145 return addr_conv;
146 return Bind();
149 int JackNetUnixSocket::BindWith(int port)
151 fRecvAddr.sin_port = htons(port);
152 return Bind();
155 int JackNetUnixSocket::Connect()
157 return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
160 int JackNetUnixSocket::ConnectTo(const char* ip)
162 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
163 if (addr_conv < 0)
164 return addr_conv;
165 return Connect();
168 void JackNetUnixSocket::Close()
170 if (fSockfd)
171 close(fSockfd);
172 fSockfd = 0;
175 void JackNetUnixSocket::Reset()
177 fSendAddr.sin_family = AF_INET;
178 fSendAddr.sin_port = htons(fPort);
179 fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
180 memset(&fSendAddr.sin_zero, 0, 8);
181 fRecvAddr.sin_family = AF_INET;
182 fRecvAddr.sin_port = htons(fPort);
183 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
184 memset(&fRecvAddr.sin_zero, 0, 8);
187 bool JackNetUnixSocket::IsSocket()
189 return(fSockfd) ? true : false;
192 //IP/PORT***********************************************************************************************************
193 void JackNetUnixSocket::SetPort(int port)
195 fPort = port;
196 fSendAddr.sin_port = htons(port);
197 fRecvAddr.sin_port = htons(port);
200 int JackNetUnixSocket::GetPort()
202 return fPort;
205 //address***********************************************************************************************************
206 int JackNetUnixSocket::SetAddress(const char* ip, int port)
208 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
209 if (addr_conv < 0)
210 return addr_conv;
211 fSendAddr.sin_port = htons(port);
212 return 0;
215 char* JackNetUnixSocket::GetSendIP()
217 return inet_ntoa(fSendAddr.sin_addr);
220 char* JackNetUnixSocket::GetRecvIP()
222 return inet_ntoa(fRecvAddr.sin_addr);
225 //utility************************************************************************************************************
226 int JackNetUnixSocket::GetName(char* name)
228 return gethostname(name, 255);
231 int JackNetUnixSocket::JoinMCastGroup(const char* ip)
233 struct ip_mreq multicast_req;
234 inet_aton(ip, &multicast_req.imr_multiaddr);
235 multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
236 return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
239 //options************************************************************************************************************
240 int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
242 return setsockopt(fSockfd, level, optname, optval, optlen);
245 int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
247 return getsockopt(fSockfd, level, optname, optval, optlen);
250 //timeout************************************************************************************************************
252 #if defined(__sun__) || defined(sun)
253 int JackNetUnixSocket::SetTimeOut(int us)
255 int flags;
256 fTimeOut = us;
258 if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
259 jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
260 return -1;
263 flags |= O_NONBLOCK;
264 if (fcntl(fSockfd, F_SETFL, flags) < 0) {
265 jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
266 return 1;
269 return 0;
272 int JackNetUnixSocket::WaitRead()
274 if (fTimeOut > 0) {
276 struct timeval tv;
277 fd_set fdset;
278 ssize_t res;
280 tv.tv_sec = fTimeOut / 1000000;
281 tv.tv_usec = fTimeOut % 1000000;
283 FD_ZERO(&fdset);
284 FD_SET(fSockfd, &fdset);
286 do {
287 res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
288 } while(res < 0 && errno == EINTR);
290 if (res < 0) {
291 return res;
292 } else if (res == 0) {
293 errno = ETIMEDOUT;
294 return -1;
298 return 0;
301 int JackNetUnixSocket::WaitWrite()
303 if (fTimeOut > 0) {
305 struct timeval tv;
306 fd_set fdset;
307 ssize_t res;
309 tv.tv_sec = fTimeOut / 1000000;
310 tv.tv_usec = fTimeOut % 1000000;
312 FD_ZERO(&fdset);
313 FD_SET(fSockfd, &fdset);
315 do {
316 res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
317 } while(res < 0 && errno == EINTR);
319 if (res < 0) {
320 return res;
321 } else if (res == 0) {
322 errno = ETIMEDOUT;
323 return -1;
327 return 0;
330 #else
331 int JackNetUnixSocket::SetTimeOut(int us)
333 jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
335 //negative timeout, or exceding 10s, return
336 if ((us < 0) ||(us > 10000000))
337 return SOCKET_ERROR;
338 struct timeval timeout;
340 //less than 1sec
341 if (us < 1000000) {
342 timeout.tv_sec = 0;
343 timeout.tv_usec = us;
344 } else {
345 //more than 1sec
346 float sec = static_cast<float>(us) / 1000000.f;
347 timeout.tv_sec =(int) sec;
348 float usec = (sec - static_cast<float>(timeout.tv_sec)) * 1000000;
349 timeout.tv_usec =(int) usec;
351 return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
353 #endif
355 //local loop**********************************************************************************************************
356 int JackNetUnixSocket::SetLocalLoop()
358 char disable = 0;
359 return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
362 //network operations**************************************************************************************************
363 int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
365 #if defined(__sun__) || defined(sun)
366 if (WaitWrite() < 0)
367 return -1;
368 #endif
369 return sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
372 int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
374 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
375 if (addr_conv < 1)
376 return addr_conv;
377 #if defined(__sun__) || defined(sun)
378 if (WaitWrite() < 0)
379 return -1;
380 #endif
381 return SendTo(buffer, nbytes, flags);
384 int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
386 #if defined(__sun__) || defined(sun)
387 if (WaitWrite() < 0)
388 return -1;
389 #endif
390 return send(fSockfd, buffer, nbytes, flags);
393 int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
395 socklen_t addr_len = sizeof(socket_address_t);
396 #if defined(__sun__) || defined(sun)
397 if (WaitRead() < 0)
398 return -1;
399 #endif
400 return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len);
403 int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
405 #if defined(__sun__) || defined(sun)
406 if (WaitRead() < 0)
407 return -1;
408 #endif
409 return recv(fSockfd, buffer, nbytes, flags);
412 int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
414 socklen_t addr_len = sizeof(socket_address_t);
415 #if defined(__sun__) || defined(sun)
416 if (WaitRead() < 0)
417 return -1;
418 #endif
419 return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len);
422 net_error_t JackNetUnixSocket::GetError()
424 switch(errno)
426 case EAGAIN:
427 case ETIMEDOUT:
428 return NET_NO_DATA;
430 case ECONNABORTED:
431 case ECONNREFUSED:
432 case ECONNRESET:
433 case EINVAL:
434 case EHOSTDOWN:
435 case EHOSTUNREACH:
436 case ENETDOWN:
437 case ENETUNREACH:
438 return NET_CONN_ERROR;
440 default:
441 //return NET_OP_ERROR;
442 return NET_CONN_ERROR;