Jack2  1.9.9
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 namespace Jack
27 {
28  //utility *********************************************************************************************************
29  int GetHostName(char * name, int size)
30  {
31  if (gethostname(name, size) == SOCKET_ERROR) {
32  jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
33  strcpy(name, "default");
34  return SOCKET_ERROR;
35  }
36  return 0;
37  }
38 
39  //construct/destruct***********************************************************************************************
40  JackNetUnixSocket::JackNetUnixSocket()
41  {
42  fSockfd = 0;
43  fPort = 0;
44  fTimeOut = 0;
45  fSendAddr.sin_family = AF_INET;
46  fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
47  memset(&fSendAddr.sin_zero, 0, 8);
48  fRecvAddr.sin_family = AF_INET;
49  fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
50  memset(&fRecvAddr.sin_zero, 0, 8);
51  }
52 
53  JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
54  {
55  fSockfd = 0;
56  fPort = port;
57  fTimeOut = 0;
58  fSendAddr.sin_family = AF_INET;
59  fSendAddr.sin_port = htons(port);
60  inet_aton(ip, &fSendAddr.sin_addr);
61  memset(&fSendAddr.sin_zero, 0, 8);
62  fRecvAddr.sin_family = AF_INET;
63  fRecvAddr.sin_port = htons(port);
64  fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
65  memset(&fRecvAddr.sin_zero, 0, 8);
66  }
67 
68  JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
69  {
70  fSockfd = 0;
71  fTimeOut = 0;
72  fPort = socket.fPort;
73  fSendAddr = socket.fSendAddr;
74  fRecvAddr = socket.fRecvAddr;
75  }
76 
77  JackNetUnixSocket::~JackNetUnixSocket()
78  {
79  Close();
80  }
81 
82  JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
83  {
84  if (this != &socket) {
85  fSockfd = 0;
86  fPort = socket.fPort;
87  fSendAddr = socket.fSendAddr;
88  fRecvAddr = socket.fRecvAddr;
89  }
90  return *this;
91  }
92 
93  //socket***********************************************************************************************************
94  int JackNetUnixSocket::NewSocket()
95  {
96  if (fSockfd) {
97  Close();
98  Reset();
99  }
100  fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
101 
102  /* Enable address reuse */
103  int res, on = 1;
104  #ifdef __APPLE__
105  if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
106  #else
107  if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
108  #endif
109  StrError(NET_ERROR_CODE);
110  }
111  return fSockfd;
112  }
113 
114  bool JackNetUnixSocket::IsLocal(char* ip)
115  {
116  if (strcmp(ip, "127.0.0.1") == 0) {
117  return true;
118  }
119 
120  char host_name[32];
121  gethostname(host_name, sizeof(host_name));
122 
123  struct hostent* host = gethostbyname(host_name);
124  if (host) {
125  for (int i = 0; host->h_addr_list[i] != 0; ++i) {
126  struct in_addr addr;
127  memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
128  if (strcmp(inet_ntoa(addr), ip) == 0) {
129  return true;
130  }
131  }
132  return false;
133  } else {
134  return false;
135  }
136  }
137 
138  int JackNetUnixSocket::Bind()
139  {
140  return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
141  }
142 
143  int JackNetUnixSocket::BindWith(const char* ip)
144  {
145  int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
146  if (addr_conv < 0)
147  return addr_conv;
148  return Bind();
149  }
150 
151  int JackNetUnixSocket::BindWith(int port)
152  {
153  fRecvAddr.sin_port = htons(port);
154  return Bind();
155  }
156 
157  int JackNetUnixSocket::Connect()
158  {
159  return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
160  }
161 
162  int JackNetUnixSocket::ConnectTo(const char* ip)
163  {
164  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
165  if (addr_conv < 0)
166  return addr_conv;
167  return Connect();
168  }
169 
170  void JackNetUnixSocket::Close()
171  {
172  if (fSockfd)
173  close(fSockfd);
174  fSockfd = 0;
175  }
176 
177  void JackNetUnixSocket::Reset()
178  {
179  fSendAddr.sin_family = AF_INET;
180  fSendAddr.sin_port = htons(fPort);
181  fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
182  memset(&fSendAddr.sin_zero, 0, 8);
183  fRecvAddr.sin_family = AF_INET;
184  fRecvAddr.sin_port = htons(fPort);
185  fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
186  memset(&fRecvAddr.sin_zero, 0, 8);
187  }
188 
189  bool JackNetUnixSocket::IsSocket()
190  {
191  return(fSockfd) ? true : false;
192  }
193 
194  //IP/PORT***********************************************************************************************************
195  void JackNetUnixSocket::SetPort(int port)
196  {
197  fPort = port;
198  fSendAddr.sin_port = htons(port);
199  fRecvAddr.sin_port = htons(port);
200  }
201 
202  int JackNetUnixSocket::GetPort()
203  {
204  return fPort;
205  }
206 
207  //address***********************************************************************************************************
208  int JackNetUnixSocket::SetAddress(const char* ip, int port)
209  {
210  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
211  if (addr_conv < 0)
212  return addr_conv;
213  fSendAddr.sin_port = htons(port);
214  return 0;
215  }
216 
217  char* JackNetUnixSocket::GetSendIP()
218  {
219  return inet_ntoa(fSendAddr.sin_addr);
220  }
221 
222  char* JackNetUnixSocket::GetRecvIP()
223  {
224  return inet_ntoa(fRecvAddr.sin_addr);
225  }
226 
227  //utility************************************************************************************************************
228  int JackNetUnixSocket::GetName(char* name)
229  {
230  return gethostname(name, 255);
231  }
232 
233  int JackNetUnixSocket::JoinMCastGroup(const char* ip)
234  {
235  struct ip_mreq multicast_req;
236  inet_aton(ip, &multicast_req.imr_multiaddr);
237  multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
238  return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
239  }
240 
241  //options************************************************************************************************************
242  int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
243  {
244  return setsockopt(fSockfd, level, optname, optval, optlen);
245  }
246 
247  int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
248  {
249  return getsockopt(fSockfd, level, optname, optval, optlen);
250  }
251 
252  //timeout************************************************************************************************************
253 
254 #if defined(__sun__) || defined(sun)
255  int JackNetUnixSocket::SetTimeOut(int us)
256  {
257  int flags;
258  fTimeOut = us;
259 
260  if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
261  jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
262  return -1;
263  }
264 
265  flags |= O_NONBLOCK;
266  if (fcntl(fSockfd, F_SETFL, flags) < 0) {
267  jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
268  return 1;
269  }
270 
271  return 0;
272  }
273 
274  int JackNetUnixSocket::WaitRead()
275  {
276  if (fTimeOut > 0) {
277 
278  struct timeval tv;
279  fd_set fdset;
280  ssize_t res;
281 
282  tv.tv_sec = fTimeOut / 1000000;
283  tv.tv_usec = fTimeOut % 1000000;
284 
285  FD_ZERO(&fdset);
286  FD_SET(fSockfd, &fdset);
287 
288  do {
289  res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
290  } while(res < 0 && errno == EINTR);
291 
292  if (res < 0) {
293  return res;
294  } else if (res == 0) {
295  errno = ETIMEDOUT;
296  return -1;
297  }
298  }
299 
300  return 0;
301  }
302 
303  int JackNetUnixSocket::WaitWrite()
304  {
305  if (fTimeOut > 0) {
306 
307  struct timeval tv;
308  fd_set fdset;
309  ssize_t res;
310 
311  tv.tv_sec = fTimeOut / 1000000;
312  tv.tv_usec = fTimeOut % 1000000;
313 
314  FD_ZERO(&fdset);
315  FD_SET(fSockfd, &fdset);
316 
317  do {
318  res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
319  } while(res < 0 && errno == EINTR);
320 
321  if (res < 0) {
322  return res;
323  } else if (res == 0) {
324  errno = ETIMEDOUT;
325  return -1;
326  }
327  }
328 
329  return 0;
330  }
331 
332 #else
333  int JackNetUnixSocket::SetTimeOut(int us)
334  {
335  jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
336  struct timeval timeout;
337 
338  //less than 1sec
339  if (us < 1000000) {
340  timeout.tv_sec = 0;
341  timeout.tv_usec = us;
342  } else {
343  //more than 1sec
344  float sec = float(us) / 1000000.f;
345  timeout.tv_sec = (int)sec;
346  float usec = (sec - float(timeout.tv_sec)) * 1000000;
347  timeout.tv_usec =(int)usec;
348  }
349  return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
350  }
351 #endif
352 
353  //local loop**********************************************************************************************************
354  int JackNetUnixSocket::SetLocalLoop()
355  {
356  char disable = 0;
357  return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
358  }
359 
360  //network operations**************************************************************************************************
361  int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
362  {
363  #if defined(__sun__) || defined(sun)
364  if (WaitWrite() < 0)
365  return -1;
366  #endif
367  return sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
368  }
369 
370  int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
371  {
372  int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
373  if (addr_conv < 1)
374  return addr_conv;
375  #if defined(__sun__) || defined(sun)
376  if (WaitWrite() < 0)
377  return -1;
378  #endif
379  return SendTo(buffer, nbytes, flags);
380  }
381 
382  int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
383  {
384  #if defined(__sun__) || defined(sun)
385  if (WaitWrite() < 0)
386  return -1;
387  #endif
388  return send(fSockfd, buffer, nbytes, flags);
389  }
390 
391  int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
392  {
393  socklen_t addr_len = sizeof(socket_address_t);
394  #if defined(__sun__) || defined(sun)
395  if (WaitRead() < 0)
396  return -1;
397  #endif
398  return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len);
399  }
400 
401  int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
402  {
403  #if defined(__sun__) || defined(sun)
404  if (WaitRead() < 0)
405  return -1;
406  #endif
407  return recv(fSockfd, buffer, nbytes, flags);
408  }
409 
410  int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
411  {
412  socklen_t addr_len = sizeof(socket_address_t);
413  #if defined(__sun__) || defined(sun)
414  if (WaitRead() < 0)
415  return -1;
416  #endif
417  return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len);
418  }
419 
420  net_error_t JackNetUnixSocket::GetError()
421  {
422  switch(errno)
423  {
424  case EAGAIN:
425  case ETIMEDOUT:
426  return NET_NO_DATA;
427 
428  case ECONNABORTED:
429  case ECONNREFUSED:
430  case ECONNRESET:
431  case EINVAL:
432  case EHOSTDOWN:
433  case EHOSTUNREACH:
434  case ENETDOWN:
435  case ENETUNREACH:
436  return NET_CONN_ERROR;
437 
438  default:
439  //return NET_OP_ERROR;
440  return NET_CONN_ERROR;
441  }
442  }
443 }
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107