Jack2  1.9.13
JackNetUnixSocket.cpp
1 /*
2 Copyright (C) 2008-2011 Romain Moret at Grame
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 #include "JackNetUnixSocket.h"
21 #include "JackError.h"
22 
23 #include <unistd.h>
24 #include <fcntl.h>
25 
26 using namespace std;
27 
28 namespace Jack
29 {
30  //utility *********************************************************************************************************
31  int GetHostName(char * name, int size)
32  {
33  if (gethostname(name, size) == SOCKET_ERROR) {
34  jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
35  strcpy(name, "default");
36  return SOCKET_ERROR;
37  }
38  return 0;
39  }
40 
41  //construct/destruct***********************************************************************************************
42  JackNetUnixSocket::JackNetUnixSocket()
43  {
44  fSockfd = 0;
45  fPort = 0;
46  fTimeOut = 0;
47  fSendAddr.sin_family = AF_INET;
48  fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
49  memset(&fSendAddr.sin_zero, 0, 8);
50  fRecvAddr.sin_family = AF_INET;
51  fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
52  memset(&fRecvAddr.sin_zero, 0, 8);
53  }
54 
55  JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
56  {
57  fSockfd = 0;
58  fPort = port;
59  fTimeOut = 0;
60  fSendAddr.sin_family = AF_INET;
61  fSendAddr.sin_port = htons(port);
62  inet_aton(ip, &fSendAddr.sin_addr);
63  memset(&fSendAddr.sin_zero, 0, 8);
64  fRecvAddr.sin_family = AF_INET;
65  fRecvAddr.sin_port = htons(port);
66  fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
67  memset(&fRecvAddr.sin_zero, 0, 8);
68  }
69 
70  JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
71  {
72  fSockfd = 0;
73  fTimeOut = 0;
74  fPort = socket.fPort;
75  fSendAddr = socket.fSendAddr;
76  fRecvAddr = socket.fRecvAddr;
77  }
78 
79  JackNetUnixSocket::~JackNetUnixSocket()
80  {
81  Close();
82  }
83 
84  JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
85  {
86  if (this != &socket) {
87  fSockfd = 0;
88  fPort = socket.fPort;
89  fSendAddr = socket.fSendAddr;
90  fRecvAddr = socket.fRecvAddr;
91  }
92  return *this;
93  }
94 
95  //socket***********************************************************************************************************
96  int JackNetUnixSocket::NewSocket()
97  {
98  if (fSockfd) {
99  Close();
100  Reset();
101  }
102  fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
103 
104  /* Enable address reuse */
105  int res, on = 1;
106  #ifdef __APPLE__
107  if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
108  #else
109  if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
110  #endif
111  StrError(NET_ERROR_CODE);
112  }
113 
114  int tos = 0; /* see <netinet/in.h> */
115 
116  /*
117  DSCP Field Hex/Bin/Dec Layer 2 Prio Traffic Type Acronym WMM Access Category
118  0x38 / 111000 / 56 7 Network Control NC AC_VO
119  0x30 / 110000 / 48 6 Voice VO AC_VO
120  0x28 / 101000 / 40 5 Video VI AC_VI
121  0x20 / 100000 / 32 4 Controlled Load CL AC_VI
122  0x18 / 011000 / 24 3 Excellent Effort EE AC_BE
123  0x10 / 010000 / 16 2 Spare -- AC_BK
124  0x08 / 001000 / 8 1 Background BK AC_BK
125  0x00 / 000000 / 0 0 Best Effort BE AC_BE
126  */
127 
128  socklen_t len = sizeof(tos);
129 
130  res = getsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, &len);
131 
132  tos = 46 * 4; // see <netinet/in.h>
133  res = setsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
134 
135  return fSockfd;
136  }
137 
138  bool JackNetUnixSocket::IsLocal(char* ip)
139  {
140  if (strcmp(ip, "127.0.0.1") == 0) {
141  return true;
142  }
143 
144  char host_name[32];
145  gethostname(host_name, sizeof(host_name));
146 
147  struct hostent* host = gethostbyname(host_name);
148  if (host) {
149  for (int i = 0; host->h_addr_list[i] != 0; ++i) {
150  struct in_addr addr;
151  memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
152  if (strcmp(inet_ntoa(addr), ip) == 0) {
153  return true;
154  }
155  }
156  return false;
157  } else {
158  return false;
159  }
160  }
161 
162  int JackNetUnixSocket::Bind()
163  {
164  return ::bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
165  }
166 
167  int JackNetUnixSocket::BindWith(const char* ip)
168  {
169  int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
170  if (addr_conv < 0) {
171  return addr_conv;
172  }
173  return Bind();
174  }
175 
176  int JackNetUnixSocket::BindWith(int port)
177  {
178  fRecvAddr.sin_port = htons(port);
179  return Bind();
180  }
181 
182  int JackNetUnixSocket::Connect()
183  {
184  return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
185  }
186 
187  int JackNetUnixSocket::ConnectTo(const char* ip)
188  {
189  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
190  if (addr_conv < 0) {
191  return addr_conv;
192  }
193  return Connect();
194  }
195 
196  void JackNetUnixSocket::Close()
197  {
198  if (fSockfd) {
199  close(fSockfd);
200  }
201  fSockfd = 0;
202  }
203 
204  void JackNetUnixSocket::Reset()
205  {
206  fSendAddr.sin_family = AF_INET;
207  fSendAddr.sin_port = htons(fPort);
208  fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
209  memset(&fSendAddr.sin_zero, 0, 8);
210  fRecvAddr.sin_family = AF_INET;
211  fRecvAddr.sin_port = htons(fPort);
212  fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
213  memset(&fRecvAddr.sin_zero, 0, 8);
214  }
215 
216  bool JackNetUnixSocket::IsSocket()
217  {
218  return(fSockfd) ? true : false;
219  }
220 
221  //IP/PORT***********************************************************************************************************
222  void JackNetUnixSocket::SetPort(int port)
223  {
224  fPort = port;
225  fSendAddr.sin_port = htons(port);
226  fRecvAddr.sin_port = htons(port);
227  }
228 
229  int JackNetUnixSocket::GetPort()
230  {
231  return fPort;
232  }
233 
234  //address***********************************************************************************************************
235  int JackNetUnixSocket::SetAddress(const char* ip, int port)
236  {
237  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
238  if (addr_conv < 0) {
239  return addr_conv;
240  }
241  fSendAddr.sin_port = htons(port);
242  return 0;
243  }
244 
245  char* JackNetUnixSocket::GetSendIP()
246  {
247  return inet_ntoa(fSendAddr.sin_addr);
248  }
249 
250  char* JackNetUnixSocket::GetRecvIP()
251  {
252  return inet_ntoa(fRecvAddr.sin_addr);
253  }
254 
255  //utility************************************************************************************************************
256  int JackNetUnixSocket::GetName(char* name)
257  {
258  return gethostname(name, 255);
259  }
260 
261  int JackNetUnixSocket::JoinMCastGroup(const char* ip)
262  {
263  struct ip_mreq multicast_req;
264  inet_aton(ip, &multicast_req.imr_multiaddr);
265  multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
266  return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
267  }
268 
269  //options************************************************************************************************************
270  int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
271  {
272  return setsockopt(fSockfd, level, optname, optval, optlen);
273  }
274 
275  int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
276  {
277  return getsockopt(fSockfd, level, optname, optval, optlen);
278  }
279 
280  //timeout************************************************************************************************************
281 
282 #if defined(__sun__) || defined(sun)
283  int JackNetUnixSocket::SetTimeOut(int us)
284  {
285  int flags;
286  fTimeOut = us;
287 
288  if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
289  jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
290  return -1;
291  }
292 
293  flags |= O_NONBLOCK;
294  if (fcntl(fSockfd, F_SETFL, flags) < 0) {
295  jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
296  return 1;
297  }
298 
299  return 0;
300  }
301 
302  int JackNetUnixSocket::WaitRead()
303  {
304  if (fTimeOut > 0) {
305 
306  struct timeval tv;
307  fd_set fdset;
308  ssize_t res;
309 
310  tv.tv_sec = fTimeOut / 1000000;
311  tv.tv_usec = fTimeOut % 1000000;
312 
313  FD_ZERO(&fdset);
314  FD_SET(fSockfd, &fdset);
315 
316  do {
317  res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
318  } while (res < 0 && errno == EINTR);
319 
320  if (res < 0) {
321  return res;
322  } else if (res == 0) {
323  errno = ETIMEDOUT;
324  return -1;
325  }
326  }
327 
328  return 0;
329  }
330 
331  int JackNetUnixSocket::WaitWrite()
332  {
333  if (fTimeOut > 0) {
334 
335  struct timeval tv;
336  fd_set fdset;
337  ssize_t res;
338 
339  tv.tv_sec = fTimeOut / 1000000;
340  tv.tv_usec = fTimeOut % 1000000;
341 
342  FD_ZERO(&fdset);
343  FD_SET(fSockfd, &fdset);
344 
345  do {
346  res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
347  } while (res < 0 && errno == EINTR);
348 
349  if (res < 0) {
350  return res;
351  } else if (res == 0) {
352  errno = ETIMEDOUT;
353  return -1;
354  }
355  }
356 
357  return 0;
358  }
359 
360 #else
361  int JackNetUnixSocket::SetTimeOut(int us)
362  {
363  jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
364  struct timeval timeout;
365 
366  //less than 1 sec
367  if (us < 1000000) {
368  timeout.tv_sec = 0;
369  timeout.tv_usec = us;
370  } else {
371  //more than 1 sec
372  float sec = float(us) / 1000000.f;
373  timeout.tv_sec = (int)sec;
374  float usec = (sec - float(timeout.tv_sec)) * 1000000;
375  timeout.tv_usec =(int)usec;
376  }
377  return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
378  }
379 #endif
380 
381  //local loop**********************************************************************************************************
382  int JackNetUnixSocket::SetLocalLoop()
383  {
384  char disable = 0;
385  return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
386  }
387 
388  //network operations**************************************************************************************************
389  int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
390  {
391  #if defined(__sun__) || defined(sun)
392  if (WaitWrite() < 0) {
393  return -1;
394  }
395  #endif
396  int res;
397  if ((res = sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t))) < 0) {
398  jack_error("SendTo fd = %ld err = %s", fSockfd, strerror(errno));
399  }
400  return res;
401  }
402 
403  int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
404  {
405  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
406  if (addr_conv < 1) {
407  return addr_conv;
408  }
409  fSendAddr.sin_port = htons(fPort);
410  #if defined(__sun__) || defined(sun)
411  if (WaitWrite() < 0) {
412  return -1;
413  }
414  #endif
415  return SendTo(buffer, nbytes, flags);
416  }
417 
418  int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
419  {
420  #if defined(__sun__) || defined(sun)
421  if (WaitWrite() < 0) {
422  return -1;
423  }
424  #endif
425  int res;
426  if ((res = send(fSockfd, buffer, nbytes, flags)) < 0) {
427  jack_error("Send fd = %ld err = %s", fSockfd, strerror(errno));
428  }
429  return res;
430  }
431 
432  int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
433  {
434  socklen_t addr_len = sizeof(socket_address_t);
435  #if defined(__sun__) || defined(sun)
436  if (WaitRead() < 0) {
437  return -1;
438  }
439  #endif
440  int res;
441  if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len)) < 0) {
442  jack_error("RecvFrom fd = %ld err = %s", fSockfd, strerror(errno));
443  }
444  return res;
445  }
446 
447  int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
448  {
449  #if defined(__sun__) || defined(sun)
450  if (WaitRead() < 0) {
451  return -1;
452  }
453  #endif
454  int res;
455  if ((res = recv(fSockfd, buffer, nbytes, flags)) < 0) {
456  jack_error("Recv fd = %ld err = %s", fSockfd, strerror(errno));
457  }
458  return res;
459  }
460 
461  int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
462  {
463  socklen_t addr_len = sizeof(socket_address_t);
464  #if defined(__sun__) || defined(sun)
465  if (WaitRead() < 0) {
466  return -1;
467  }
468  #endif
469  int res;
470  if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len)) < 0) {
471  jack_log("CatchHost fd = %ld err = %s", fSockfd, strerror(errno));
472  }
473  return res;
474  }
475 
476  net_error_t JackNetUnixSocket::GetError()
477  {
478  switch (errno) {
479  case EAGAIN:
480  case ETIMEDOUT:
481  return NET_NO_DATA;
482 
483  case ECONNABORTED:
484  case ECONNREFUSED:
485  case ECONNRESET:
486  case EINVAL:
487  case EHOSTDOWN:
488  case EHOSTUNREACH:
489  case ENETDOWN:
490  case ENETUNREACH:
491  return NET_CONN_ERROR;
492 
493  default:
494  //return NET_OP_ERROR;
495  return NET_CONN_ERROR;
496  }
497  }
498 
499  void JackNetUnixSocket::PrintError()
500  {
501  switch (errno) {
502 
503  case EAGAIN:
504  jack_error("JackNetUnixSocket : EAGAIN");
505  break;
506  case ETIMEDOUT:
507  jack_error("JackNetUnixSocket : ETIMEDOUT");
508  break;
509  case ECONNABORTED:
510  jack_error("JackNetUnixSocket : ECONNABORTED");
511  break;
512  case ECONNREFUSED:
513  jack_error("JackNetUnixSocket : ECONNREFUSED");
514  break;
515  case ECONNRESET:
516  jack_error("JackNetUnixSocket : ECONNRESET");
517  break;
518  case EINVAL:
519  jack_error("JackNetUnixSocket : EINVAL");
520  break;
521  case EHOSTDOWN:
522  jack_error("JackNetUnixSocket : EHOSTDOWN");
523  break;
524  case EHOSTUNREACH:
525  jack_error("JackNetUnixSocket : EHOSTUNREACH");
526  break;
527  case ENETDOWN:
528  jack_error("JackNetUnixSocket : ENETDOWN");
529  break;
530  case ENETUNREACH:
531  jack_error("JackNetUnixSocket : ENETUNREACH");
532  break;
533  default:
534  jack_error("JackNetUnixSocket : %d", errno);
535  break;
536  }
537  }
538 }
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108