Start of v1.9.20
[jack2.git] / posix / JackNetUnixSocket.cpp
blob528c95880e5f3a2261cc87158198ee2f6e105499
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>
25 #include <sys/time.h>
27 using namespace std;
29 namespace Jack
31 //utility *********************************************************************************************************
32 int GetHostName(char * name, int size)
34 if (gethostname(name, size) == SOCKET_ERROR) {
35 jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
36 strcpy(name, "default");
37 return SOCKET_ERROR;
39 return 0;
42 //construct/destruct***********************************************************************************************
43 JackNetUnixSocket::JackNetUnixSocket()
45 fSockfd = 0;
46 fPort = 0;
47 fTimeOut = 0;
48 fSendAddr.sin_family = AF_INET;
49 fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
50 memset(&fSendAddr.sin_zero, 0, 8);
51 fRecvAddr.sin_family = AF_INET;
52 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
53 memset(&fRecvAddr.sin_zero, 0, 8);
56 JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
58 fSockfd = 0;
59 fPort = port;
60 fTimeOut = 0;
61 fSendAddr.sin_family = AF_INET;
62 fSendAddr.sin_port = htons(port);
63 inet_aton(ip, &fSendAddr.sin_addr);
64 memset(&fSendAddr.sin_zero, 0, 8);
65 fRecvAddr.sin_family = AF_INET;
66 fRecvAddr.sin_port = htons(port);
67 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
68 memset(&fRecvAddr.sin_zero, 0, 8);
71 JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
73 fSockfd = 0;
74 fTimeOut = 0;
75 fPort = socket.fPort;
76 fSendAddr = socket.fSendAddr;
77 fRecvAddr = socket.fRecvAddr;
80 JackNetUnixSocket::~JackNetUnixSocket()
82 Close();
85 JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
87 if (this != &socket) {
88 fSockfd = 0;
89 fPort = socket.fPort;
90 fSendAddr = socket.fSendAddr;
91 fRecvAddr = socket.fRecvAddr;
93 return *this;
96 //socket***********************************************************************************************************
97 int JackNetUnixSocket::NewSocket()
99 if (fSockfd) {
100 Close();
101 Reset();
103 fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
105 /* Enable address reuse */
106 int res, on = 1;
107 #ifdef __APPLE__
108 if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
109 #else
110 if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
111 #endif
112 StrError(NET_ERROR_CODE);
115 int tos = 0; /* see <netinet/in.h> */
118 DSCP Field Hex/Bin/Dec Layer 2 Prio Traffic Type Acronym WMM Access Category
119 0x38 / 111000 / 56 7 Network Control NC AC_VO
120 0x30 / 110000 / 48 6 Voice VO AC_VO
121 0x28 / 101000 / 40 5 Video VI AC_VI
122 0x20 / 100000 / 32 4 Controlled Load CL AC_VI
123 0x18 / 011000 / 24 3 Excellent Effort EE AC_BE
124 0x10 / 010000 / 16 2 Spare -- AC_BK
125 0x08 / 001000 / 8 1 Background BK AC_BK
126 0x00 / 000000 / 0 0 Best Effort BE AC_BE
129 socklen_t len = sizeof(tos);
131 res = getsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, &len);
133 tos = 46 * 4; // see <netinet/in.h>
134 res = setsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
136 return fSockfd;
139 bool JackNetUnixSocket::IsLocal(char* ip)
141 if (strcmp(ip, "127.0.0.1") == 0) {
142 return true;
145 char host_name[32];
146 gethostname(host_name, sizeof(host_name));
148 struct hostent* host = gethostbyname(host_name);
149 if (host) {
150 for (int i = 0; host->h_addr_list[i] != 0; ++i) {
151 struct in_addr addr;
152 memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
153 if (strcmp(inet_ntoa(addr), ip) == 0) {
154 return true;
157 return false;
158 } else {
159 return false;
163 int JackNetUnixSocket::Bind()
165 return ::bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
168 int JackNetUnixSocket::BindWith(const char* ip)
170 int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
171 if (addr_conv < 0) {
172 return addr_conv;
174 return Bind();
177 int JackNetUnixSocket::BindWith(int port)
179 fRecvAddr.sin_port = htons(port);
180 return Bind();
183 int JackNetUnixSocket::Connect()
185 return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
188 int JackNetUnixSocket::ConnectTo(const char* ip)
190 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
191 if (addr_conv < 0) {
192 return addr_conv;
194 return Connect();
197 void JackNetUnixSocket::Close()
199 if (fSockfd) {
200 close(fSockfd);
202 fSockfd = 0;
205 void JackNetUnixSocket::Reset()
207 fSendAddr.sin_family = AF_INET;
208 fSendAddr.sin_port = htons(fPort);
209 fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
210 memset(&fSendAddr.sin_zero, 0, 8);
211 fRecvAddr.sin_family = AF_INET;
212 fRecvAddr.sin_port = htons(fPort);
213 fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
214 memset(&fRecvAddr.sin_zero, 0, 8);
217 bool JackNetUnixSocket::IsSocket()
219 return(fSockfd) ? true : false;
222 //IP/PORT***********************************************************************************************************
223 void JackNetUnixSocket::SetPort(int port)
225 fPort = port;
226 fSendAddr.sin_port = htons(port);
227 fRecvAddr.sin_port = htons(port);
230 int JackNetUnixSocket::GetPort()
232 return fPort;
235 //address***********************************************************************************************************
236 int JackNetUnixSocket::SetAddress(const char* ip, int port)
238 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
239 if (addr_conv < 0) {
240 return addr_conv;
242 fSendAddr.sin_port = htons(port);
243 return 0;
246 char* JackNetUnixSocket::GetSendIP()
248 return inet_ntoa(fSendAddr.sin_addr);
251 char* JackNetUnixSocket::GetRecvIP()
253 return inet_ntoa(fRecvAddr.sin_addr);
256 //utility************************************************************************************************************
257 int JackNetUnixSocket::GetName(char* name)
259 return gethostname(name, 255);
262 int JackNetUnixSocket::JoinMCastGroup(const char* ip)
264 struct ip_mreq multicast_req;
265 inet_aton(ip, &multicast_req.imr_multiaddr);
266 multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
267 return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
270 //options************************************************************************************************************
271 int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
273 return setsockopt(fSockfd, level, optname, optval, optlen);
276 int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
278 return getsockopt(fSockfd, level, optname, optval, optlen);
281 //timeout************************************************************************************************************
283 #if defined(__sun__) || defined(sun)
284 int JackNetUnixSocket::SetTimeOut(int us)
286 int flags;
287 fTimeOut = us;
289 if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
290 jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
291 return -1;
294 flags |= O_NONBLOCK;
295 if (fcntl(fSockfd, F_SETFL, flags) < 0) {
296 jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
297 return 1;
300 return 0;
303 int JackNetUnixSocket::WaitRead()
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, &fdset, NULL, 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 int JackNetUnixSocket::WaitWrite()
334 if (fTimeOut > 0) {
336 struct timeval tv;
337 fd_set fdset;
338 ssize_t res;
340 tv.tv_sec = fTimeOut / 1000000;
341 tv.tv_usec = fTimeOut % 1000000;
343 FD_ZERO(&fdset);
344 FD_SET(fSockfd, &fdset);
346 do {
347 res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
348 } while (res < 0 && errno == EINTR);
350 if (res < 0) {
351 return res;
352 } else if (res == 0) {
353 errno = ETIMEDOUT;
354 return -1;
358 return 0;
361 #else
362 int JackNetUnixSocket::SetTimeOut(int us)
364 jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
365 struct timeval timeout;
367 //less than 1 sec
368 if (us < 1000000) {
369 timeout.tv_sec = 0;
370 timeout.tv_usec = us;
371 } else {
372 //more than 1 sec
373 float sec = float(us) / 1000000.f;
374 timeout.tv_sec = (int)sec;
375 float usec = (sec - float(timeout.tv_sec)) * 1000000;
376 timeout.tv_usec =(int)usec;
378 return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
380 #endif
382 //local loop**********************************************************************************************************
383 int JackNetUnixSocket::SetLocalLoop()
385 char disable = 0;
386 return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
389 //network operations**************************************************************************************************
390 int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
392 #if defined(__sun__) || defined(sun)
393 if (WaitWrite() < 0) {
394 return -1;
396 #endif
397 int res;
398 if ((res = sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t))) < 0) {
399 jack_error("SendTo fd = %ld err = %s", fSockfd, strerror(errno));
401 return res;
404 int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
406 int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
407 if (addr_conv < 1) {
408 return addr_conv;
410 fSendAddr.sin_port = htons(fPort);
411 #if defined(__sun__) || defined(sun)
412 if (WaitWrite() < 0) {
413 return -1;
415 #endif
416 return SendTo(buffer, nbytes, flags);
419 int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
421 #if defined(__sun__) || defined(sun)
422 if (WaitWrite() < 0) {
423 return -1;
425 #endif
426 int res;
427 if ((res = send(fSockfd, buffer, nbytes, flags)) < 0) {
428 jack_error("Send fd = %ld err = %s", fSockfd, strerror(errno));
430 return res;
433 int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
435 socklen_t addr_len = sizeof(socket_address_t);
436 #if defined(__sun__) || defined(sun)
437 if (WaitRead() < 0) {
438 return -1;
440 #endif
441 int res;
442 if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len)) < 0) {
443 jack_error("RecvFrom fd = %ld err = %s", fSockfd, strerror(errno));
445 return res;
448 int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
450 #if defined(__sun__) || defined(sun)
451 if (WaitRead() < 0) {
452 return -1;
454 #endif
455 int res;
456 if ((res = recv(fSockfd, buffer, nbytes, flags)) < 0) {
457 jack_error("Recv fd = %ld err = %s", fSockfd, strerror(errno));
459 return res;
462 int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
464 socklen_t addr_len = sizeof(socket_address_t);
465 #if defined(__sun__) || defined(sun)
466 if (WaitRead() < 0) {
467 return -1;
469 #endif
470 int res;
471 if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len)) < 0) {
472 jack_log("CatchHost fd = %ld err = %s", fSockfd, strerror(errno));
474 return res;
477 net_error_t JackNetUnixSocket::GetError()
479 switch (errno) {
480 case EAGAIN:
481 case ETIMEDOUT:
482 return NET_NO_DATA;
484 case ECONNABORTED:
485 case ECONNREFUSED:
486 case ECONNRESET:
487 case EINVAL:
488 case EHOSTDOWN:
489 case EHOSTUNREACH:
490 case ENETDOWN:
491 case ENETUNREACH:
492 return NET_CONN_ERROR;
494 default:
495 //return NET_OP_ERROR;
496 return NET_CONN_ERROR;
500 void JackNetUnixSocket::PrintError()
502 switch (errno) {
504 case EAGAIN:
505 jack_error("JackNetUnixSocket : EAGAIN");
506 break;
507 case ETIMEDOUT:
508 jack_error("JackNetUnixSocket : ETIMEDOUT");
509 break;
510 case ECONNABORTED:
511 jack_error("JackNetUnixSocket : ECONNABORTED");
512 break;
513 case ECONNREFUSED:
514 jack_error("JackNetUnixSocket : ECONNREFUSED");
515 break;
516 case ECONNRESET:
517 jack_error("JackNetUnixSocket : ECONNRESET");
518 break;
519 case EINVAL:
520 jack_error("JackNetUnixSocket : EINVAL");
521 break;
522 case EHOSTDOWN:
523 jack_error("JackNetUnixSocket : EHOSTDOWN");
524 break;
525 case EHOSTUNREACH:
526 jack_error("JackNetUnixSocket : EHOSTUNREACH");
527 break;
528 case ENETDOWN:
529 jack_error("JackNetUnixSocket : ENETDOWN");
530 break;
531 case ENETUNREACH:
532 jack_error("JackNetUnixSocket : ENETUNREACH");
533 break;
534 default:
535 jack_error("JackNetUnixSocket : %d", errno);
536 break;