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