Jack2  1.9.8
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 <unistd.h>
22 #include <fcntl.h>
23 
24 namespace Jack
25 {
26  //utility *********************************************************************************************************
27  int GetHostName(char * name, int size)
28  {
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;
33  }
34  return 0;
35  }
36 
37  //construct/destruct***********************************************************************************************
38  JackNetUnixSocket::JackNetUnixSocket()
39  {
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);
49  }
50 
51  JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
52  {
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);
64  }
65 
66  JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
67  {
68  fSockfd = 0;
69  fTimeOut = 0;
70  fPort = socket.fPort;
71  fSendAddr = socket.fSendAddr;
72  fRecvAddr = socket.fRecvAddr;
73  }
74 
75  JackNetUnixSocket::~JackNetUnixSocket()
76  {
77  Close();
78  }
79 
80  JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
81  {
82  if (this != &socket) {
83  fSockfd = 0;
84  fPort = socket.fPort;
85  fSendAddr = socket.fSendAddr;
86  fRecvAddr = socket.fRecvAddr;
87  }
88  return *this;
89  }
90 
91  //socket***********************************************************************************************************
92  int JackNetUnixSocket::NewSocket()
93  {
94  if (fSockfd) {
95  Close();
96  Reset();
97  }
98  fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
99 
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);
108  }
109  return fSockfd;
110  }
111 
112  bool JackNetUnixSocket::IsLocal(char* ip)
113  {
114  if (strcmp(ip, "127.0.0.1") == 0) {
115  return true;
116  }
117 
118  char host_name[32];
119  gethostname(host_name, sizeof(host_name));
120 
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;
128  }
129  }
130  return false;
131  } else {
132  return false;
133  }
134  }
135 
136  int JackNetUnixSocket::Bind()
137  {
138  return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
139  }
140 
141  int JackNetUnixSocket::BindWith(const char* ip)
142  {
143  int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
144  if (addr_conv < 0)
145  return addr_conv;
146  return Bind();
147  }
148 
149  int JackNetUnixSocket::BindWith(int port)
150  {
151  fRecvAddr.sin_port = htons(port);
152  return Bind();
153  }
154 
155  int JackNetUnixSocket::Connect()
156  {
157  return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
158  }
159 
160  int JackNetUnixSocket::ConnectTo(const char* ip)
161  {
162  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
163  if (addr_conv < 0)
164  return addr_conv;
165  return Connect();
166  }
167 
168  void JackNetUnixSocket::Close()
169  {
170  if (fSockfd)
171  close(fSockfd);
172  fSockfd = 0;
173  }
174 
175  void JackNetUnixSocket::Reset()
176  {
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);
185  }
186 
187  bool JackNetUnixSocket::IsSocket()
188  {
189  return(fSockfd) ? true : false;
190  }
191 
192  //IP/PORT***********************************************************************************************************
193  void JackNetUnixSocket::SetPort(int port)
194  {
195  fPort = port;
196  fSendAddr.sin_port = htons(port);
197  fRecvAddr.sin_port = htons(port);
198  }
199 
200  int JackNetUnixSocket::GetPort()
201  {
202  return fPort;
203  }
204 
205  //address***********************************************************************************************************
206  int JackNetUnixSocket::SetAddress(const char* ip, int port)
207  {
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;
213  }
214 
215  char* JackNetUnixSocket::GetSendIP()
216  {
217  return inet_ntoa(fSendAddr.sin_addr);
218  }
219 
220  char* JackNetUnixSocket::GetRecvIP()
221  {
222  return inet_ntoa(fRecvAddr.sin_addr);
223  }
224 
225  //utility************************************************************************************************************
226  int JackNetUnixSocket::GetName(char* name)
227  {
228  return gethostname(name, 255);
229  }
230 
231  int JackNetUnixSocket::JoinMCastGroup(const char* ip)
232  {
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));
237  }
238 
239  //options************************************************************************************************************
240  int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
241  {
242  return setsockopt(fSockfd, level, optname, optval, optlen);
243  }
244 
245  int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
246  {
247  return getsockopt(fSockfd, level, optname, optval, optlen);
248  }
249 
250  //timeout************************************************************************************************************
251 
252 #if defined(__sun__) || defined(sun)
253  int JackNetUnixSocket::SetTimeOut(int us)
254  {
255  int flags;
256  fTimeOut = us;
257 
258  if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
259  jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
260  return -1;
261  }
262 
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;
267  }
268 
269  return 0;
270  }
271 
272  int JackNetUnixSocket::WaitRead()
273  {
274  if (fTimeOut > 0) {
275 
276  struct timeval tv;
277  fd_set fdset;
278  ssize_t res;
279 
280  tv.tv_sec = fTimeOut / 1000000;
281  tv.tv_usec = fTimeOut % 1000000;
282 
283  FD_ZERO(&fdset);
284  FD_SET(fSockfd, &fdset);
285 
286  do {
287  res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
288  } while(res < 0 && errno == EINTR);
289 
290  if (res < 0) {
291  return res;
292  } else if (res == 0) {
293  errno = ETIMEDOUT;
294  return -1;
295  }
296  }
297 
298  return 0;
299  }
300 
301  int JackNetUnixSocket::WaitWrite()
302  {
303  if (fTimeOut > 0) {
304 
305  struct timeval tv;
306  fd_set fdset;
307  ssize_t res;
308 
309  tv.tv_sec = fTimeOut / 1000000;
310  tv.tv_usec = fTimeOut % 1000000;
311 
312  FD_ZERO(&fdset);
313  FD_SET(fSockfd, &fdset);
314 
315  do {
316  res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
317  } while(res < 0 && errno == EINTR);
318 
319  if (res < 0) {
320  return res;
321  } else if (res == 0) {
322  errno = ETIMEDOUT;
323  return -1;
324  }
325  }
326 
327  return 0;
328  }
329 
330 #else
331  int JackNetUnixSocket::SetTimeOut(int us)
332  {
333  jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
334 
335  //negative timeout, or exceding 10s, return
336  if ((us < 0) ||(us > 10000000))
337  return SOCKET_ERROR;
338  struct timeval timeout;
339 
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;
350  }
351  return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
352  }
353 #endif
354 
355  //local loop**********************************************************************************************************
356  int JackNetUnixSocket::SetLocalLoop()
357  {
358  char disable = 0;
359  return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
360  }
361 
362  //network operations**************************************************************************************************
363  int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
364  {
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));
370  }
371 
372  int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
373  {
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);
382  }
383 
384  int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
385  {
386  #if defined(__sun__) || defined(sun)
387  if (WaitWrite() < 0)
388  return -1;
389  #endif
390  return send(fSockfd, buffer, nbytes, flags);
391  }
392 
393  int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
394  {
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);
401  }
402 
403  int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
404  {
405  #if defined(__sun__) || defined(sun)
406  if (WaitRead() < 0)
407  return -1;
408  #endif
409  return recv(fSockfd, buffer, nbytes, flags);
410  }
411 
412  int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
413  {
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);
420  }
421 
422  net_error_t JackNetUnixSocket::GetError()
423  {
424  switch(errno)
425  {
426  case EAGAIN:
427  case ETIMEDOUT:
428  return NET_NO_DATA;
429 
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;
439 
440  default:
441  //return NET_OP_ERROR;
442  return NET_CONN_ERROR;
443  }
444  }
445 }