MBDyn-1.7.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
s2s.cc
Go to the documentation of this file.
1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/utils/s2s.cc,v 1.31 2017/01/12 15:10:28 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 <cstring>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <netdb.h>
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cerrno>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <sys/un.h>
47 #include <arpa/inet.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <signal.h>
51 #include "ac/getopt.h"
52 
53 #include <iostream>
54 #include <cstring>
55 #include <sstream>
56 #include <vector>
57 
58 #include "sock.h"
59 #include "s2s.h"
60 
61 static struct s2s_t *s2s_list = 0;
62 
63 s2s_t::s2s_t(void)
64 : nChannels(0),
65 path(0),
66 host(0),
67 port(-1),
68 create(false),
70 sock(-1),
72 progname(0)
73 {
74  addr.ms_type = SOCK_STREAM;
75 
76  next = ::s2s_list;
77  ::s2s_list = next;
78 }
79 
80 s2s_t::~s2s_t(void)
81 {
82  struct s2s_t **p;
83 
84  for (p = &::s2s_list; *p != 0; p = &(*p)->next) {
85  if (*p == this) {
86  *p = (*p)->next;
87  break;
88  }
89  }
90 }
91 
92 void
93 s2s_t::usage(int rc) const
94 {
95  const char
96  *b = "",
97  *C = "",
98  *F = "",
99  *h = "",
100  *n = "",
101  *p = "",
102  *P = "",
103  *s = "",
104  *t = "";
105 
106  b = " -b {y|n}\t\t" "blocking mode (default: yes)\n";
107  C = " -C\t\t\t" "create socket (default: connect to existing)\n";
108  h = " -h <host>\t\t" "host name (for INET sockets; default: \"localhost\")\n";
109  n = " -n <channels>\t" "number of channels (default: auto-detect)\n";
110  p = " -p <port>\t\t" "port number (for INET sockets)\n";
111  P = " -P <path>\t\t" "path (for LOCAL sockets)\n";
112  s = " -s\t\t\t" "decrease verbosity level\n";
113  t = " -t <type>\t\t" "socket type { tcp | udp }\n";
114 
115  if (!this->stream2socket) {
116  F = " -F <format>\t\t" "output format (%[.<precision>]{eEfF})\n";
117  }
118 
119  silent_cerr(
120 "\n"
121 " MBDyn (C) is a multibody analysis code.\n"
122 " http://www.mbdyn.org\n"
123 "\n"
124 " Copyright (C) 1996-2017\n"
125 "\n"
126 " Pierangelo Masarati <masarati@aero.polimi.it>\n"
127 "\n"
128 " Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano\n"
129 " via La Masa, 34 - 20156 Milano, Italy\n"
130 " http://www.aero.polimi.it\n"
131 "\n"
132 " usage: " << this->progname << " [options]\n"
133 "\n"
134  << b
135  << C
136  << F
137  << h
138  << n
139  << p
140  << P
141  << s
142  << t
143  << std::endl);
144  exit(rc);
145 }
146 
147 void
148 s2s_t::shutdown(void)
149 {
150  if (this->sock >= 0) {
151  ::shutdown(this->sock, SHUT_RDWR);
152  sock = -1;
153  }
154 
155  if (this->path) {
156  unlink(this->path);
157  this->path = 0;
158  }
159 }
160 
161 void
162 s2s_shutdown(int signum)
163 {
164  struct s2s_t **p, **nextp;
165 
166  for (p = &::s2s_list; *p != 0; p = nextp ) {
167  nextp = &(*p)->next;
168  (*p)->shutdown();
169  *p = 0;
170  }
171 
172  ::s2s_list = 0;
173 
174  exit(EXIT_SUCCESS);
175 }
176 
177 static void
178 parse_format(const char *fmt)
179 {
180  char *f = (char *)fmt, *next;
181 
182  if (f[0] == '%') {
183  f++;
184  }
185 
186  if (f[0] == '.') {
187  f++;
188  unsigned precision = strtoul(f, &next, 10);
189  if (next == f) {
190  silent_cerr("unable to parse \"precision\" "
191  "in format string "
192  "\"" << fmt << "\"" << std::endl);
193  throw;
194  }
195  std::cout.precision(precision);
196  f = next;
197  }
198 
199  if (f[0] == 'e' || f[0] == 'E') {
200  std::cout.setf(std::ios::scientific);
201 
202  } else if (f[0] != 'f' && f[0] != 'F') {
203  silent_cerr("unable to parse format string "
204  "\"" << fmt << "\"" << std::endl);
205  throw;
206  }
207 }
208 
209 void
210 s2s_t::parse(int argc, char *argv[])
211 {
212  char *next;
213 
214  next = std::strrchr(argv[0], '/');
215  if (next != 0) {
216  next++;
217 
218  } else {
219  next = argv[0];
220  }
221 
222  // libtool paranoia
223  if (strncmp(next, "lt-", STRLENOF("lt-")) == 0) {
224  next += STRLENOF("lt-");
225  }
226 
227  if (strcmp(next, "socket2stream") == 0) {
228  this->stream2socket = false;
229  this->progname = "socket2stream";
230 
231  } else if (strcmp(next, "stream2socket") == 0) {
232  this->stream2socket = true;
233  this->progname = "stream2socket";
234 
235  } else {
236  silent_cerr("tool name mismatch: \"" << argv[0] << "\"" << std::endl);
237  exit(EXIT_FAILURE);
238  }
239 
240  const char *optstring;
241  if (this->stream2socket) {
242  optstring = "b:Ch:n:p:P:st:";
243 
244  } else {
245  optstring = "b:CF:h:n:p:P:st:";
246  }
247 
248  while (true) {
249  int opt = getopt(argc, argv, optstring);
250 
251  if (opt == EOF) {
252  break;
253  }
254 
255  switch (opt) {
256  case 'b':
257  if (strcmp(optarg, "y") == 0) {
258  this->block = BLOCK_YES;
259  } else if (strcmp(optarg, "n") == 0) {
260  this->block = BLOCK_NO;
261  } else {
262  silent_cerr("invalid value "
263  "\"" << optarg << "\""
264  " for option -b"
265  << std::endl);
266  usage(EXIT_FAILURE);
267  }
268  break;
269 
270  case 'C':
271  this->create = true;
272  break;
273 
274  case 'F':
275  parse_format(optarg);
276  break;
277 
278  case 'h':
279  this->host = optarg;
280  break;
281 
282  case 'n':
283  this->nChannels = strtoul(optarg, &next, 10);
284  if (next[0] != '\0') {
285  silent_cerr("unable to parse option -n "
286  "\"" << optarg << "\""
287  << std::endl);
288  usage(EXIT_FAILURE);
289  }
290  break;
291 
292  case 'p':
293  this->port = strtoul(optarg, &next, 10);
294  if (next[0] != '\0') {
295  silent_cerr("unable to parse option -p "
296  "\"" << optarg << "\""
297  << std::endl);
298  usage(EXIT_FAILURE);
299  }
300  break;
301 
302  case 'P':
303  this->path = optarg;
304  break;
305 
306  case 's':
307  ::fSilent++;
308  break;
309 
310  case 't':
311  if (strcasecmp(optarg, "udp") == 0) {
312  this->addr.ms_type = SOCK_DGRAM;
313 
314  } else if (strcasecmp(optarg, "tcp") != 0) {
315  silent_cerr("unable to parse option -p "
316  "\"" << optarg << "\""
317  << std::endl);
318  usage(EXIT_FAILURE);
319  }
320  break;
321 
322  default:
323  usage(EXIT_SUCCESS);
324  }
325  }
326 
327  if (this->path == 0 && (this->host == 0 && this->port == -1)) {
328  usage(EXIT_FAILURE);
329  }
330 }
331 
332 void
333 s2s_t::prepare(void)
334 {
335  int save_errno;
336  struct sockaddr *addrp = 0;
337 
338  if (this->path) {
339  this->addr.ms_domain = AF_LOCAL;
340  addrp = (struct sockaddr *)&this->addr.ms_addr.ms_addr_local;
341  this->addr.ms_len = sizeof(this->addr.ms_addr.ms_addr_local);
342 
343  this->buf = this->path;
344 
346  this->path, this->addr.ms_type, this->create, &save_errno);
347 
348  if (this->sock == -1) {
349  const char *err_msg = strerror(save_errno);
350 
351  silent_cerr("socket(" << this->buf << ") failed "
352  "(" << save_errno << ": " << err_msg << ")"
353  << std::endl);
354  throw;
355 
356  } else if (this->sock == -2) {
357  const char *err_msg = strerror(save_errno);
358 
359  silent_cerr("bind(" << this->buf << ") failed "
360  "(" << save_errno << ": " << err_msg << ")"
361  << std::endl);
362  throw;
363  }
364 
365  } else {
366  addr.ms_domain = AF_INET;
367  addrp = (struct sockaddr *)&this->addr.ms_addr.ms_addr_inet;
368  addr.ms_len = sizeof(this->addr.ms_addr.ms_addr_inet);
369 
370  if (this->host == 0) {
371  // default to localhost
372  this->host = "127.0.0.1";
373 
374  } else {
375  char *p = std::strchr(const_cast<char *>(this->host), ':');
376  if (p != 0) {
377  if (this->port != -1) {
378  silent_cerr("port already passed as '-p'" << std::endl);
379  exit(EXIT_FAILURE);
380  }
381 
382  char *next;
383  unsigned long tmp_port;
384 
385  p[0] = '\0';
386  p++;
387  tmp_port = strtoul(p, &next, 10);
388  if (next[0] != '\0') {
389  silent_cerr("unable to parse port out of "
390  "\"" << this->host << ":" << p << "\""
391  << std::endl);
392  exit(EXIT_FAILURE);
393  }
394 
395  this->port = tmp_port;
396  }
397  }
398 
399  std::ostringstream os;
400  os << this->host << ":" << this->port;
401  this->buf = os.str();
402 
404  this->host, this->port, this->addr.ms_type, this->create, &save_errno);
405 
406  if (this->sock == -1) {
407  const char *err_msg = strerror(save_errno);
408 
409  silent_cerr("socket(" << this->buf << ") failed "
410  "(" << save_errno << ": " << err_msg << ")"
411  << std::endl);
412  throw;
413 
414  } else if (this->sock == -2) {
415  const char *err_msg = strerror(save_errno);
416 
417  silent_cerr("bind(" << this->buf << ") failed "
418  "(" << save_errno << ": " << err_msg << ")"
419  << std::endl);
420  throw;
421 
422  } else if (this->sock == -3) {
423  silent_cerr("illegal host[:port] name \"" << this->buf << "\" "
424  "(" << save_errno << ")"
425  << std::endl);
426  throw;
427  }
428  }
429 
430  if (this->addr.ms_type == SOCK_STREAM) {
431  if (this->create) {
432  if (listen(this->sock, 1) < 0) {
433  save_errno = errno;
434  const char *err_msg = strerror(save_errno);
435 
436  silent_cerr("listen(" << this->sock << "," << this->buf << ") failed "
437  "(" << save_errno << ": " << err_msg << ")"
438  << std::endl);
439  throw;
440  }
441 
442  int sock = this->sock;
443  socklen_t len;
444  this->sock = accept(sock, addrp, &len);
445  close(sock);
446  if (this->sock == -1) {
447  save_errno = errno;
448  const char *err_msg = strerror(save_errno);
449 
450  silent_cerr("accept(" << this->sock << ",\"" << this->buf << "\") "
451  "failed (" << save_errno << ": " << err_msg << ")"
452  << std::endl);
453  throw;
454  }
455 
456  } else {
457  if (connect(this->sock, addrp, addr.ms_len) < 0) {
458  save_errno = errno;
459  const char *err_msg = strerror(save_errno);
460 
461  silent_cerr("connect(" << this->sock << ",\"" << this->buf << "\"," << addr.ms_len << ") "
462  "failed (" << save_errno << ": " << err_msg << ")"
463  << std::endl);
464  throw;
465  }
466  }
467  }
468 
469  signal(SIGTERM, s2s_shutdown);
470  signal(SIGINT, s2s_shutdown);
471  signal(SIGPIPE, s2s_shutdown);
472 }
473 
474 bool
475 s2s_t::is_blocking(void) const
476 {
477  return block == BLOCK_YES;
478 }
479 
480 ssize_t
481 s2s_t::send(int flags) const
482 {
483  switch (block) {
484  case BLOCK_NO:
485  flags |= MSG_DONTWAIT;
486  break;
487 
488  case BLOCK_YES:
489  flags &= ~MSG_DONTWAIT;
490  break;
491  }
492 
493  switch (this->addr.ms_type) {
494  case SOCK_STREAM:
495  return ::send(sock, (char *)&dbuf[0], sizeof(double)*nChannels, flags);
496 
497  case SOCK_DGRAM:
498  return ::sendto(sock, (char *)&dbuf[0], sizeof(double)*nChannels, flags,
500  }
501 
502  return -1;
503 }
504 
505 ssize_t
506 s2s_t::recv(int flags)
507 {
508  switch (block) {
509  case BLOCK_NO:
510  flags |= MSG_DONTWAIT;
511  break;
512 
513  case BLOCK_YES:
514  flags &= ~MSG_DONTWAIT;
515  break;
516  }
517 
518  switch (this->addr.ms_type) {
519  case SOCK_STREAM:
520  return ::recv(sock, (char *)&dbuf[0], sizeof(double)*nChannels, flags);
521 
522  case SOCK_DGRAM:
523  return ::recvfrom(sock, (char *)&dbuf[0], sizeof(double)*nChannels, flags, 0, 0);
524  }
525 
526  return -1;
527 }
528 
529 #endif // USE_SOCKET
std::string buf
Definition: s2s.h:68
int ms_type
Definition: s2s.h:38
union s2s_sockaddr_t::@54 ms_addr
int mbdyn_make_named_socket_type(struct sockaddr_un *name, const char *path, int socket_type, int dobind, int *perror)
Definition: s2s.h:50
void usage(int rc) const
int fSilent
Definition: myassert.cc:58
const char * progname
Definition: s2s.h:71
socklen_t ms_len
Definition: s2s.h:45
struct sockaddr_in ms_addr_inet
Definition: s2s.h:42
struct sockaddr ms_addr_generic
Definition: s2s.h:41
ssize_t send(int flags) const
void prepare(void)
ssize_t recv(int flags)
s2s_sockaddr_t addr
Definition: s2s.h:61
int nChannels
Definition: s2s.h:56
int ms_domain
Definition: s2s.h:39
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: s2s.h:51
Definition: mbdyn.h:76
bool is_blocking(void) const
struct sockaddr_un ms_addr_local
Definition: s2s.h:43
std::vector< double > dbuf
Definition: s2s.h:69
const char * host
Definition: autopilot.c:142
int sock
Definition: s2s.h:66
Definition: mbdyn.h:77
s2s_t(void)
const char * path
Definition: s2s.h:57
int getopt(int argc, char *const argv[], const char *opts)
Definition: getopt.c:93
#define STRLENOF(s)
Definition: mbdyn.h:166
const char * host
Definition: s2s.h:59
Definition: s2s.h:54
int block
Definition: s2s.h:63
char * optarg
Definition: getopt.c:74
unsigned short int port
Definition: autopilot.c:143
void parse(int argc, char *argv[])
bool stream2socket
Definition: s2s.h:70
int create
Definition: s2s.h:62
struct s2s_t * next
Definition: s2s.h:86
~s2s_t(void)
int port
Definition: s2s.h:60
const char * path
Definition: autopilot.c:141
void shutdown(void)