Jack2  1.9.12
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  /*
129  socklen_t len = sizeof(tos);
130 
131  res = getsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, &len);
132  printf("getsockopt IPPROTO_IP res = %d tos = %d\n", res, tos);
133 
134  tos = 46 * 4; // see <netinet/in.h>
135  res = setsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
136 
137  printf("setsockopt IPPROTO_IP res = %d tos = %d\n", res, tos );
138 
139  res = getsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, &len);
140  printf("getsockopt IPPROTO_IP res = %d tos = %d\n", res, tos);
141  */
142 
143  return fSockfd;
144  }
145 
146  bool JackNetUnixSocket::IsLocal(char* ip)
147  {
148  if (strcmp(ip, "127.0.0.1") == 0) {
149  return true;
150  }
151 
152  char host_name[32];
153  gethostname(host_name, sizeof(host_name));
154 
155  struct hostent* host = gethostbyname(host_name);
156  if (host) {
157  for (int i = 0; host->h_addr_list[i] != 0; ++i) {
158  struct in_addr addr;
159  memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
160  if (strcmp(inet_ntoa(addr), ip) == 0) {
161  return true;
162  }
163  }
164  return false;
165  } else {
166  return false;
167  }
168  }
169 
170  int JackNetUnixSocket::Bind()
171  {
172  return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
173  }
174 
175  int JackNetUnixSocket::BindWith(const char* ip)
176  {
177  int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
178  if (addr_conv < 0) {
179  return addr_conv;
180  }
181  return Bind();
182  }
183 
184  int JackNetUnixSocket::BindWith(int port)
185  {
186  fRecvAddr.sin_port = htons(port);
187  return Bind();
188  }
189 
190  int JackNetUnixSocket::Connect()
191  {
192  return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
193  }
194 
195  int JackNetUnixSocket::ConnectTo(const char* ip)
196  {
197  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
198  if (addr_conv < 0) {
199  return addr_conv;
200  }
201  return Connect();
202  }
203 
204  void JackNetUnixSocket::Close()
205  {
206  if (fSockfd) {
207  close(fSockfd);
208  }
209  fSockfd = 0;
210  }
211 
212  void JackNetUnixSocket::Reset()
213  {
214  fSendAddr.sin_family = AF_INET;
215  fSendAddr.sin_port = htons(fPort);
216  fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
217  memset(&fSendAddr.sin_zero, 0, 8);
218  fRecvAddr.sin_family = AF_INET;
219  fRecvAddr.sin_port = htons(fPort);
220  fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
221  memset(&fRecvAddr.sin_zero, 0, 8);
222  }
223 
224  bool JackNetUnixSocket::IsSocket()
225  {
226  return(fSockfd) ? true : false;
227  }
228 
229  //IP/PORT***********************************************************************************************************
230  void JackNetUnixSocket::SetPort(int port)
231  {
232  fPort = port;
233  fSendAddr.sin_port = htons(port);
234  fRecvAddr.sin_port = htons(port);
235  }
236 
237  int JackNetUnixSocket::GetPort()
238  {
239  return fPort;
240  }
241 
242  //address***********************************************************************************************************
243  int JackNetUnixSocket::SetAddress(const char* ip, int port)
244  {
245  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
246  if (addr_conv < 0) {
247  return addr_conv;
248  }
249  fSendAddr.sin_port = htons(port);
250  return 0;
251  }
252 
253  char* JackNetUnixSocket::GetSendIP()
254  {
255  return inet_ntoa(fSendAddr.sin_addr);
256  }
257 
258  char* JackNetUnixSocket::GetRecvIP()
259  {
260  return inet_ntoa(fRecvAddr.sin_addr);
261  }
262 
263  //utility************************************************************************************************************
264  int JackNetUnixSocket::GetName(char* name)
265  {
266  return gethostname(name, 255);
267  }
268 
269  int JackNetUnixSocket::JoinMCastGroup(const char* ip)
270  {
271  struct ip_mreq multicast_req;
272  inet_aton(ip, &multicast_req.imr_multiaddr);
273  multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
274  return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
275  }
276 
277  //options************************************************************************************************************
278  int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
279  {
280  return setsockopt(fSockfd, level, optname, optval, optlen);
281  }
282 
283  int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
284  {
285  return getsockopt(fSockfd, level, optname, optval, optlen);
286  }
287 
288  //timeout************************************************************************************************************
289 
290 #if defined(__sun__) || defined(sun)
291  int JackNetUnixSocket::SetTimeOut(int us)
292  {
293  int flags;
294  fTimeOut = us;
295 
296  if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
297  jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
298  return -1;
299  }
300 
301  flags |= O_NONBLOCK;
302  if (fcntl(fSockfd, F_SETFL, flags) < 0) {
303  jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
304  return 1;
305  }
306 
307  return 0;
308  }
309 
310  int JackNetUnixSocket::WaitRead()
311  {
312  if (fTimeOut > 0) {
313 
314  struct timeval tv;
315  fd_set fdset;
316  ssize_t res;
317 
318  tv.tv_sec = fTimeOut / 1000000;
319  tv.tv_usec = fTimeOut % 1000000;
320 
321  FD_ZERO(&fdset);
322  FD_SET(fSockfd, &fdset);
323 
324  do {
325  res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
326  } while (res < 0 && errno == EINTR);
327 
328  if (res < 0) {
329  return res;
330  } else if (res == 0) {
331  errno = ETIMEDOUT;
332  return -1;
333  }
334  }
335 
336  return 0;
337  }
338 
339  int JackNetUnixSocket::WaitWrite()
340  {
341  if (fTimeOut > 0) {
342 
343  struct timeval tv;
344  fd_set fdset;
345  ssize_t res;
346 
347  tv.tv_sec = fTimeOut / 1000000;
348  tv.tv_usec = fTimeOut % 1000000;
349 
350  FD_ZERO(&fdset);
351  FD_SET(fSockfd, &fdset);
352 
353  do {
354  res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
355  } while (res < 0 && errno == EINTR);
356 
357  if (res < 0) {
358  return res;
359  } else if (res == 0) {
360  errno = ETIMEDOUT;
361  return -1;
362  }
363  }
364 
365  return 0;
366  }
367 
368 #else
369  int JackNetUnixSocket::SetTimeOut(int us)
370  {
371  jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
372  struct timeval timeout;
373 
374  //less than 1 sec
375  if (us < 1000000) {
376  timeout.tv_sec = 0;
377  timeout.tv_usec = us;
378  } else {
379  //more than 1 sec
380  float sec = float(us) / 1000000.f;
381  timeout.tv_sec = (int)sec;
382  float usec = (sec - float(timeout.tv_sec)) * 1000000;
383  timeout.tv_usec =(int)usec;
384  }
385  return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
386  }
387 #endif
388 
389  //local loop**********************************************************************************************************
390  int JackNetUnixSocket::SetLocalLoop()
391  {
392  char disable = 0;
393  return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
394  }
395 
396  //network operations**************************************************************************************************
397  int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
398  {
399  #if defined(__sun__) || defined(sun)
400  if (WaitWrite() < 0) {
401  return -1;
402  }
403  #endif
404  int res;
405  if ((res = sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t))) < 0) {
406  jack_error("SendTo fd = %ld err = %s", fSockfd, strerror(errno));
407  }
408  return res;
409  }
410 
411  int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
412  {
413  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
414  if (addr_conv < 1) {
415  return addr_conv;
416  }
417  fSendAddr.sin_port = htons(fPort);
418  #if defined(__sun__) || defined(sun)
419  if (WaitWrite() < 0) {
420  return -1;
421  }
422  #endif
423  return SendTo(buffer, nbytes, flags);
424  }
425 
426  int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
427  {
428  #if defined(__sun__) || defined(sun)
429  if (WaitWrite() < 0) {
430  return -1;
431  }
432  #endif
433  int res;
434  if ((res = send(fSockfd, buffer, nbytes, flags)) < 0) {
435  jack_error("Send fd = %ld err = %s", fSockfd, strerror(errno));
436  }
437  return res;
438  }
439 
440  int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
441  {
442  socklen_t addr_len = sizeof(socket_address_t);
443  #if defined(__sun__) || defined(sun)
444  if (WaitRead() < 0) {
445  return -1;
446  }
447  #endif
448  int res;
449  if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len)) < 0) {
450  jack_error("RecvFrom fd = %ld err = %s", fSockfd, strerror(errno));
451  }
452  return res;
453  }
454 
455  int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
456  {
457  #if defined(__sun__) || defined(sun)
458  if (WaitRead() < 0) {
459  return -1;
460  }
461  #endif
462  int res;
463  if ((res = recv(fSockfd, buffer, nbytes, flags)) < 0) {
464  jack_error("Recv fd = %ld err = %s", fSockfd, strerror(errno));
465  }
466  return res;
467  }
468 
469  int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
470  {
471  socklen_t addr_len = sizeof(socket_address_t);
472  #if defined(__sun__) || defined(sun)
473  if (WaitRead() < 0) {
474  return -1;
475  }
476  #endif
477  int res;
478  if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len)) < 0) {
479  jack_log("CatchHost fd = %ld err = %s", fSockfd, strerror(errno));
480  }
481  return res;
482  }
483 
484  net_error_t JackNetUnixSocket::GetError()
485  {
486  switch (errno) {
487  case EAGAIN:
488  case ETIMEDOUT:
489  return NET_NO_DATA;
490 
491  case ECONNABORTED:
492  case ECONNREFUSED:
493  case ECONNRESET:
494  case EINVAL:
495  case EHOSTDOWN:
496  case EHOSTUNREACH:
497  case ENETDOWN:
498  case ENETUNREACH:
499  return NET_CONN_ERROR;
500 
501  default:
502  //return NET_OP_ERROR;
503  return NET_CONN_ERROR;
504  }
505  }
506 
507  void JackNetUnixSocket::PrintError()
508  {
509  switch (errno) {
510 
511  case EAGAIN:
512  jack_error("JackNetUnixSocket : EAGAIN");
513  break;
514  case ETIMEDOUT:
515  jack_error("JackNetUnixSocket : ETIMEDOUT");
516  break;
517  case ECONNABORTED:
518  jack_error("JackNetUnixSocket : ECONNABORTED");
519  break;
520  case ECONNREFUSED:
521  jack_error("JackNetUnixSocket : ECONNREFUSED");
522  break;
523  case ECONNRESET:
524  jack_error("JackNetUnixSocket : ECONNRESET");
525  break;
526  case EINVAL:
527  jack_error("JackNetUnixSocket : EINVAL");
528  break;
529  case EHOSTDOWN:
530  jack_error("JackNetUnixSocket : EHOSTDOWN");
531  break;
532  case EHOSTUNREACH:
533  jack_error("JackNetUnixSocket : EHOSTUNREACH");
534  break;
535  case ENETDOWN:
536  jack_error("JackNetUnixSocket : ENETDOWN");
537  break;
538  case ENETUNREACH:
539  jack_error("JackNetUnixSocket : ENETUNREACH");
540  break;
541  default:
542  jack_error("JackNetUnixSocket : %d", errno);
543  break;
544  }
545  }
546 }
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92