MBDyn-1.7.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
usesock.cc
Go to the documentation of this file.
1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/mbdyn/base/usesock.cc,v 1.37 2017/01/12 14:46:11 masarati Exp $ */
2 /*
3  * MBDyn (C) is a multibody analysis code.
4  * http://www.mbdyn.org
5  *
6  * Copyright (C) 1996-2017
7  *
8  * Pierangelo Masarati <masarati@aero.polimi.it>
9  * Paolo Mantegazza <mantegazza@aero.polimi.it>
10  *
11  * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
12  * via La Masa, 34 - 20156 Milano, Italy
13  * http://www.aero.polimi.it
14  *
15  * Changing this copyright notice is forbidden.
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation (version 2 of the License).
20  *
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */
31 
32 #include "mbconfig.h" /* This goes first in every *.c,*.cc file */
33 
34 #ifdef USE_SOCKET
35 
36 #include "myassert.h"
37 #include "mynewmem.h"
38 #include "mbsleep.h"
39 
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <netdb.h>
45 #include <stdio.h>
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif /* HAVE_UNISTD_H */
49 #include <stdlib.h>
50 #include <errno.h>
51 #include <sys/socket.h>
52 #include <arpa/inet.h>
53 #include <time.h>
54 
55 #include "usesock.h"
56 #include "sock.h"
57 
58 #define DEFAULT_PORT 5500 /* FIXME: da definire meglio */
59 #define DEFAULT_HOST "127.0.0.1"
60 
61 UseSocket::UseSocket(bool c)
62 : sock(-1),
63 socket_type(MBDYN_DEFAULT_SOCKET_TYPE),
64 create(c),
65 connected(false),
66 abandoned(false),
67 socklen(0)
68 {
69  NO_OP;
70 }
71 
72 UseSocket::UseSocket(int t, bool c)
73 : sock(-1),
74 socket_type(t),
75 create(c),
76 connected(false), // t == SOCK_DGRAM),
77 abandoned(false),
78 socklen(0)
79 {
80  NO_OP;
81 }
82 
83 UseSocket::~UseSocket(void)
84 {
85  if (sock != -1) {
86  int status;
87  time_t t = time(NULL);
88 
89  if (socket_type == SOCK_STREAM) {
90  status = shutdown(sock, SHUT_RDWR);
91  int save_errno = errno;
92  if (status == 0) {
93  pedantic_cout("UseSocket::~UseSocket: shutdown: "
94  "socket=" << sock
95  << " status=" << status
96  << " time=" << asctime(localtime(&t))
97  << std::endl);
98 
99  } else {
100  char *msg = strerror(save_errno);
101  silent_cerr("UseSocket::~UseSocket: shutdown "
102  "socket=" << sock
103  << " status=" << status
104  << " time=" << asctime(localtime(&t))
105  << " error=" << save_errno << " (" << msg << ")"
106  << std::endl);
107  }
108  }
109 
110  status = close(sock);
111  pedantic_cout("UseSocket::~UseSocket: close: "
112  "socket=" << sock
113  << " status=" << status
114  << " time=" << asctime(localtime(&t))
115  << std::endl);
116  }
117 }
118 
119 std::ostream&
120 UseSocket::Restart(std::ostream& out) const
121 {
122  const char *sType;
123  switch (socket_type) {
124  case SOCK_STREAM:
125  sType = "tcp";
126  break;
127  case SOCK_DGRAM:
128  sType = "udp";
129  break;
130  default:
131  ASSERT(0);
133  }
134  out << ", socket type, " << sType;
135 
136  if (create) {
137  out << ", create, yes";
138  }
139 
140  return out;
141 }
142 
143 int
144 UseSocket::GetSock(void) const
145 {
146  return sock;
147 }
148 
149 void
150 UseSocket::SetSock(int s)
151 {
152  sock = s;
153 }
154 
155 void
156 UseSocket::PostConnect(void)
157 {
158  struct linger lin;
159  lin.l_onoff = 1;
160  lin.l_linger = 0;
161 
162  if (setsockopt(GetSock(), SOL_SOCKET, SO_LINGER, &lin, sizeof(lin))) {
163  int save_errno = errno;
164  char *msg = strerror(save_errno);
165 
166  silent_cerr("UseSocket::PostConnect: setsockopt() failed "
167  "(" << save_errno << ": " << msg << ")"
168  << std::endl);
170  }
171 }
172 
173 void
174 UseSocket::Connect(void)
175 {
176  if (socket_type != SOCK_STREAM) {
177  return;
178  }
179 
180  // FIXME: retry strategy should be configurable
181  int count = 600;
183  mbsleep_real2sleep(0.1, &timeout);
184 
185  for ( ; count > 0; count--) {
186  if (connect(sock, GetSockaddr(), GetSocklen()) < 0) {
187  int save_errno = errno;
188  switch (save_errno) {
189  case ECONNREFUSED: // inet
190  case ENOENT: // unix
191  /* Socket does not exist yet; retry */
192  mbsleep(&timeout);
193  continue;
194  }
195 
196  /* Connect failed */
197  char *msg = strerror(save_errno);
198  silent_cerr("UseSocket::Connect: connect() failed "
199  "(" << save_errno << ": " << msg << ")"
200  << std::endl);
202  }
203 
204  /* Success */
205  connected = true;
206  PostConnect();
207  return;
208  }
209 
210  silent_cerr("UseSocket(): connection timed out"
211  << std::endl);
213 }
214 
215 void
216 UseSocket::ConnectSock(int s)
217 {
218  SetSock(s);
219 
220  connected = true;
221 
222  PostConnect();
223 }
224 
225 bool
226 UseSocket::Create(void) const
227 {
228  return create;
229 }
230 
231 bool
232 UseSocket::Connected(void) const
233 {
234  return connected;
235 }
236 
237 void
238 UseSocket::Abandon(void)
239 {
240  abandoned = true;
241 }
242 
243 bool
244 UseSocket::Abandoned(void) const
245 {
246  return abandoned;
247 }
248 
249 socklen_t&
250 UseSocket::GetSocklen(void) const
251 {
252  return socklen;
253 }
254 
255 ssize_t
256 UseSocket::send(const void *buf, size_t len, int flags)
257 {
258  switch (socket_type) {
259  case SOCK_STREAM:
260  return ::send(sock, buf, len, flags);
261 
262  case SOCK_DGRAM:
263  return ::sendto(sock, buf, len, flags, GetSockaddr(), GetSocklen());
264 
265  default:
266  ASSERT(0);
267  }
268 
269  return -1;
270 }
271 
272 ssize_t
273 UseSocket::recv(void *buf, size_t len, int flags)
274 {
275  switch (socket_type) {
276  case SOCK_STREAM:
277  return ::recv(sock, buf, len, flags);
278 
279  case SOCK_DGRAM:
280  // struct sockaddr src_addr = { 0 };
281  // socklen_t addrlen = 0;
282  // return ::recvfrom(sock, buf, len, flags, &src_addr, &addrlen);
283  return ::recvfrom(sock, buf, len, flags, 0, 0);
284 
285  default:
286  ASSERT(0);
287  }
288 
289  return -1;
290 }
291 
292 UseInetSocket::UseInetSocket(const std::string& h, unsigned short p, bool c)
293 : UseSocket(c),
294 host(h),
295 port(p)
296 {
297  UseInetSocket_int();
298 }
299 
300 UseInetSocket::UseInetSocket(const std::string& h, unsigned short p, int t, bool c)
301 : UseSocket(t, c),
302 host(h),
303 port(p)
304 {
305  UseInetSocket_int();
306 }
307 
308 void
309 UseInetSocket::UseInetSocket_int(void)
310 {
311  ASSERT(port > 0);
312 
313  socklen = sizeof(addr);
314 
315  /* if 0, means INET on localhost */
316  if (host.empty()) {
317  host = DEFAULT_HOST;
318  }
319 
320  if (create) {
321  int save_errno;
322 
323  sock = mbdyn_make_inet_socket_type(0, host.c_str(), port, socket_type,
324  1, &save_errno);
325 
326  if (sock == -1) {
327  const char *err_msg = strerror(save_errno);
328 
329  silent_cerr("UseInetSocket(" << host << ":" << port << "): "
330  "socket() failed "
331  "(" << save_errno << ": " << err_msg << ")"
332  << std::endl);
334 
335  } else if (sock == -2) {
336  const char *err_msg = strerror(save_errno);
337 
338  silent_cerr("UseInetSocket(" << host << ":" << port << "): "
339  "bind() failed "
340  "(" << save_errno << ": " << err_msg << ")"
341  << std::endl);
343 
344  } else if (sock == -3) {
345  silent_cerr("UseInetSocket(" << host << ":" << port << "): "
346  "illegal host name \"" << host << "\" "
347  "(" << save_errno << ")"
348  << std::endl);
350  }
351 
352  if (socket_type == SOCK_STREAM) {
353  if (listen(sock, 1) < 0) {
354  save_errno = errno;
355  const char *err_msg = strerror(save_errno);
356 
357  silent_cerr("UseInetSocket(" << host << ":" << port << "): "
358  "listen() failed "
359  "(" << save_errno << ": " << err_msg << ")"
360  << std::endl);
362  }
363  }
364  }
365 }
366 
367 UseInetSocket::~UseInetSocket(void)
368 {
369  NO_OP;
370 }
371 
372 std::ostream&
373 UseInetSocket::Restart(std::ostream& out) const
374 {
375  UseSocket::Restart(out);
376  out << ", port, " << port;
377  if (!host.empty()) {
378  out << ", host, " << "\"" << host << "\"";
379  }
380  return out;
381 }
382 
383 void
384 UseInetSocket::Connect(void)
385 {
386  if (connected) {
387  return;
388  }
389 
390 #if 0
391  sock = socket(PF_INET, SOCK_STREAM, 0);
392  if (sock < 0) {
393  silent_cerr("UseSocket(): socket() failed "
394  << "\"" << host << ":" << port << "\""
395  << std::endl);
397  }
398 
399  addr.sin_family = AF_INET;
400  addr.sin_port = htons(port);
401  if (inet_aton(host.c_str(), &addr.sin_addr) == 0) {
402  silent_cerr("UseSocket(): unknown host "
403  "\"" << host << ":" << port << "\""
404  << std::endl);
406  }
407 #endif
408 
409  int save_errno;
410  sock = mbdyn_make_inet_socket_type(&addr, host.c_str(), port, socket_type, 0, &save_errno);
411  if (sock < 0) {
412  const char *err_msg = strerror(save_errno);
413 
414  silent_cerr("UseInetSocket(" << host << ":" << port << "): socket() failed "
415  "(" << save_errno << ": " << err_msg << ")"
416  << std::endl);
418  }
419 
420  pedantic_cout("connecting to inet socket "
421  "\"" << inet_ntoa(addr.sin_addr)
422  << ":" << ntohs(addr.sin_port)
423  << "\" ..." << std::endl);
424 
425  UseSocket::Connect();
426 }
427 
428 void
429 UseInetSocket::ConnectSock(int s)
430 {
431  UseSocket::ConnectSock(s);
432 
433  silent_cout("INET connection to port=" << port << " by client "
434  << "\"" << inet_ntoa(addr.sin_addr)
435  << ":" << ntohs(addr.sin_port) << "\""
436  << std::endl);
437 }
438 
439 struct sockaddr *
440 UseInetSocket::GetSockaddr(void) const
441 {
442  return (struct sockaddr *)&addr;
443 }
444 
445 UseLocalSocket::UseLocalSocket(const std::string& p, bool c)
446 : UseSocket(c), path(p)
447 {
448  UseLocalSocket_int();
449 }
450 
451 UseLocalSocket::UseLocalSocket(const std::string& p, int t, bool c)
452 : UseSocket(t, c), path(p)
453 {
454  UseLocalSocket_int();
455 }
456 
457 void
458 UseLocalSocket::UseLocalSocket_int(void)
459 {
460  ASSERT(!path.empty());
461 
462  socklen = sizeof(addr);
463 
464  if (create) {
465  int save_errno;
466 
467  sock = mbdyn_make_named_socket_type(0, path.c_str(), socket_type, 1, &save_errno);
468 
469  if (sock == -1) {
470  const char *err_msg = strerror(save_errno);
471 
472  silent_cerr("UseLocalSocket(" << path << "): "
473  "socket() failed "
474  "(" << save_errno << ": " << err_msg << ")"
475  << std::endl);
477 
478  } else if (sock == -2) {
479  const char *err_msg = strerror(save_errno);
480 
481  silent_cerr("UseLocalSocket(" << path << "): "
482  "bind() failed "
483  "(" << save_errno << ": " << err_msg << ")"
484  << std::endl);
486  }
487 
488  if (socket_type == SOCK_STREAM) {
489  if (listen(sock, 1) < 0) {
490  save_errno = errno;
491  const char *err_msg = strerror(save_errno);
492 
493  silent_cerr("UseLocalSocket(" << path << "): "
494  "listen() failed "
495  "(" << save_errno << ": " << err_msg << ")"
496  << std::endl);
498  }
499  }
500  }
501 }
502 
503 UseLocalSocket::~UseLocalSocket(void)
504 {
505  if (!path.empty() && create) {
506  unlink(path.c_str());
507  }
508 }
509 
510 std::ostream&
511 UseLocalSocket::Restart(std::ostream& out) const
512 {
513  return UseSocket::Restart(out) << ", path, " << "\"" << path << "\"";
514 }
515 
516 void
517 UseLocalSocket::Connect(void)
518 {
519  if (connected) {
520  return;
521  }
522 
523  sock = socket(PF_LOCAL, socket_type, 0);
524  if (sock < 0) {
525  int save_errno = errno;
526  char *msg = strerror(save_errno);
527 
528  silent_cerr("UseSocket(): socket() failed "
529  "(" << save_errno << ": " << msg << ")"
530  << std::endl);
532  }
533  addr.sun_family = AF_UNIX;
534  if (path.size() >= sizeof(addr.sun_path)) {
535  silent_cerr("UseSocket(): path=\"" << path << "\" exceeds allowable size "
536  "of LOCAL socket path (" << sizeof(addr.sun_path) << ")" << std::endl);
538  }
539  memcpy(addr.sun_path, path.c_str(), path.size() + 1); // terminating '\0'
540 
541  pedantic_cout("connecting to local socket \"" << path << "\" ..."
542  << std::endl);
543 
544  UseSocket::Connect();
545 }
546 
547 void
548 UseLocalSocket::ConnectSock(int s)
549 {
550  UseSocket::ConnectSock(s);
551 
552  silent_cout("LOCAL connection to path=\"" << path << "\""
553  << std::endl);
554 }
555 
556 struct sockaddr *
557 UseLocalSocket::GetSockaddr(void) const
558 {
559  return (struct sockaddr *)&addr;
560 }
561 
562 #endif // USE_SOCKET
static int timeout
#define MBDYN_EXCEPT_ARGS
Definition: except.h:63
int mbdyn_make_named_socket_type(struct sockaddr_un *name, const char *path, int socket_type, int dobind, int *perror)
int mbsleep(const mbsleep_t *t)
Definition: mbsleep.c:90
unsigned long mbsleep_t
Definition: mbsleep.h:51
#define NO_OP
Definition: myassert.h:74
#define MBDYN_DEFAULT_SOCKET_TYPE
Definition: sock.h:73
int mbdyn_make_inet_socket_type(struct sockaddr_in *name, const char *hostname, unsigned short int port, int socket_type, int dobind, int *perror)
Definition: mbdyn.h:76
const char * host
Definition: autopilot.c:142
static int count
Definition: modules.cc:41
#define ASSERT(expression)
Definition: colamd.c:977
static std::stack< cleanup * > c
Definition: cleanup.cc:59
struct mbrtai_msg_t msg
#define DEFAULT_HOST
Definition: streamoutelem.h:41
unsigned short int port
Definition: autopilot.c:143
int mbsleep_real2sleep(doublereal d, mbsleep_t *t)
Definition: mbsleep.c:49
static doublereal buf[BUFSIZE]
Definition: discctrl.cc:333
const char * path
Definition: autopilot.c:141