MBDyn-1.7.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
sockdrv.cc
Go to the documentation of this file.
1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/mbdyn/base/sockdrv.cc,v 1.48 2017/01/12 14:46:10 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 #include "dataman.h"
34 #include "sockdrv.h"
35 
36 #ifdef USE_SOCKET
37 
38 #include <stdio.h>
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stddef.h>
43 #include <ctype.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <netdb.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <sys/un.h>
55 #include <arpa/inet.h>
56 
57 #include "sock.h"
58 
59 const size_t USERLEN = 32;
60 const size_t CREDLEN = 128;
61 const size_t BUFSIZE = 1024;
62 const char *MBDynSocketDrivePath = "/var/mbdyn/mbdyn.sock";
63 
64 SocketDrive::SocketDrive(unsigned int uL, const DriveHandler* pDH,
65  unsigned short int p, AuthMethod* a,
66  integer nd, const std::vector<doublereal>& v0)
67 : FileDrive(uL, pDH, "socket", nd, v0),
68 type(AF_INET),
69 auth(a),
70 pFlags(NULL)
71 {
72  int save_errno;
73 
74  ASSERT(p > 0);
75  ASSERT(auth != NULL);
76  ASSERT(nd > 0);
77 
78  /* Create the socket and set it up to accept connections. */
79  data.Port = p;
80  sock = mbdyn_make_inet_socket(0, NULL, data.Port, 1, &save_errno);
81  if (sock == -1) {
82  const char *err_msg = strerror(save_errno);
83 
84  silent_cerr("SocketDrive(" << GetLabel()
85  << "): socket failed "
86  "(" << save_errno << ": "<< err_msg << ")"
87  << std::endl);
89 
90  } else if (sock == -2) {
91  const char *err_msg = strerror(save_errno);
92 
93  silent_cerr("SocketDrive(" << GetLabel()
94  << "): bind failed "
95  "(" << save_errno << ": "<< err_msg << ")"
96  << std::endl);
98  }
99 
100  Init();
101 }
102 
103 SocketDrive::SocketDrive(unsigned int uL, const DriveHandler* pDH,
104  const char *path,
105  integer nd, const std::vector<doublereal>& v0)
106 : FileDrive(uL, pDH, "socket", nd, v0),
107 type(AF_LOCAL),
108 auth(NULL),
109 pFlags(NULL)
110 {
111  int save_errno;
112 
113  ASSERT(path != NULL);
114  ASSERT(nd > 0);
115 
116  SAFENEW(auth, NoAuth);
117 
118  /* Create the socket and set it up to accept connections. */
119  SAFESTRDUP(data.Path, path);
120  sock = mbdyn_make_named_socket(0, data.Path, 1, &save_errno);
121  if (sock == -1) {
122  const char *err_msg = strerror(save_errno);
123 
124  silent_cerr("SocketDrive(" << GetLabel()
125  << "): socket failed "
126  "(" << save_errno << ": "<< err_msg << ")"
127  << std::endl);
129 
130  } else if (sock == -2) {
131  const char *err_msg = strerror(save_errno);
132 
133  silent_cerr("SocketDrive(" << GetLabel()
134  << "): bind failed "
135  "(" << save_errno << ": "<< err_msg << ")"
136  << std::endl);
138  }
139 
140  Init();
141 }
142 
143 void
144 SocketDrive::Init(void)
145 {
146  /* non-blocking */
147  int oldflags = fcntl(sock, F_GETFL, 0);
148  if (oldflags == -1) {
149  silent_cerr("SocketDrive(" << GetLabel()
150  << ": unable to get socket flags"
151  << std::endl);
153  }
154  oldflags |= O_NONBLOCK;
155  if (fcntl(sock, F_SETFL, oldflags) == -1) {
156  silent_cerr("SocketDrive(" << GetLabel()
157  << ": unable to set socket flags"
158  << std::endl);
160  }
161 
162  if (listen(sock, 1) < 0) {
163  silent_cerr("SocketDrive(" << GetLabel()
164  << "): listen failed" << std::endl);
166  }
167 
168  SAFENEWARR(pFlags, int, iNumDrives + 1);
169  for (int iCnt = 0; iCnt <= iNumDrives; iCnt++) {
170  pFlags[iCnt] = SocketDrive::DEFAULT;
171  }
172 }
173 
174 
175 SocketDrive::~SocketDrive(void)
176 {
177  /* some shutdown stuff ... */
178  shutdown(sock, SHUT_RDWR /* 2 */ );
179 
180  switch (type) {
181  case AF_LOCAL:
182  if (data.Path) {
183  unlink(data.Path);
184  SAFEDELETEARR(data.Path);
185  }
186  break;
187 
188  default:
189  NO_OP;
190  break;
191  }
192 
193  if (auth != NULL) {
194  SAFEDELETE(auth);
195  }
196 }
197 
198 static char *
199 get_line(char *buf, size_t bufsize, FILE *fd)
200 {
201  int len;
202 
203  if (fgets(buf, bufsize, fd) == NULL) {
204  return NULL;
205  }
206 
207  len = strlen(buf);
208  if (len > 0 && buf[len-1] == '\n') {
209  buf[len-1] = '\0';
210  if (len > 1 && buf[len-2] == '\r') {
211  buf[len-2] = '\0';
212  }
213  } else {
214  fprintf(stderr, "buffer overflow\n");
215  return NULL;
216  }
217 
218  return buf;
219 }
220 
221 /*
222  * in/out:
223  * user : puntatore a buffer di 9 bytes (8+'\0')
224  * cred : puntatore a buffer di 129 bytes (128+'\0')
225  *
226  * out:
227  * buf : puntatore a buffer statico che contiene una copia della nuova
228  * linea nel caso sia stata accidentalmente letta
229  */
230 int
231 get_auth_token(FILE *fd, char *user, char *cred, char **nextline)
232 {
233  char buf[BUFSIZE];
234 
235  if (get_line(buf, BUFSIZE, fd) == NULL) {
236  return -1;
237  }
238 
239  user[0] = '\0';
240  cred[0] = '\0';
241 
242  if (strncasecmp(buf, "user:", 5) != 0) {
243  *nextline = (char *)malloc(sizeof(char)*(strlen(buf)+1));
244  if ((*nextline) == NULL) {
245  return -1;
246  }
247  strcpy(*nextline, buf);
248  return 0;
249  } else {
250  char *p;
251  unsigned int i;
252 
253  p = buf+5;
254  while (isspace(*p)) {
255  p++;
256  }
257  for (i = 0; i < USERLEN; i++) {
258  if ((user[i] = p[i]) == '\0' || isspace(user[i])) {
259  break;
260  }
261  }
262  user[i] = '\0';
263  }
264 
265  if (get_line(buf, BUFSIZE, fd) == NULL) {
266  return -1;
267  }
268 
269  if (strncasecmp(buf, "password:", 9) != 0) {
270  *nextline = (char *)malloc(sizeof(char)*(strlen(buf)+1));
271  if ((*nextline) == NULL) {
272  return -1;
273  }
274  strcpy(*nextline, buf);
275  return 0;
276  } else {
277  char *p;
278  unsigned int i;
279 
280  p = buf+9;
281  while (isspace(*p)) {
282  p++;
283  }
284  for (i = 0; i < CREDLEN; i++) {
285  if ((cred[i] = p[i]) == '\0' || isspace(cred[i])) {
286  break;
287  }
288  }
289  cred[i] = '\0';
290  }
291 
292  return 1;
293 }
294 
295 void
296 SocketDrive::ServePending(const doublereal& /* t */ )
297 {
298  struct sockaddr_in client_name;
299  socklen_t socklen;
300 
301  /* prova */
302  for (integer iCnt = 1; iCnt <= iNumDrives; iCnt++) {
303  if (pFlags[iCnt] & SocketDrive::IMPULSIVE) {
304  pdVal[iCnt] = 0.;
305  }
306  }
307 
308  while (true) {
309  int got_value = 0;
310  char *nextline = NULL;
311  const size_t bufsize = BUFSIZE;
312  char buf[bufsize];
313 
314  int label;
315  doublereal value;
316 
317  int cur_sock = accept(sock,
318  (struct sockaddr *)&client_name,
319  &socklen);
320 
321  if (cur_sock == -1) {
322  int save_errno = errno;
323  if (save_errno != EWOULDBLOCK) {
324  silent_cerr(
325  "SocketDrive(" << GetLabel() << "): "
326  "accept failed "
327  "(" << save_errno << ": "
328  << strerror(save_errno) << ")"
329  << std::endl);
330  }
331  return;
332  }
333 
334  silent_cout("SocketDrive(" << GetLabel() << "): "
335  "connect from " << inet_ntoa(client_name.sin_addr)
336  << ":" << ntohs(client_name.sin_port) << std::endl);
337 
338  bool bAuthc = false;
339 #ifdef HAVE_SASL2
340  if (dynamic_cast<SASL2_Auth*>(auth)) {
341  if (auth->Auth(cur_sock) != AuthMethod::AUTH_OK) {
342  silent_cerr(
343  "SocketDrive(" << GetLabel() << "): "
344  "authentication failed" << std::endl);
345  continue;
346  }
347  bAuthc = true;
348  }
349 #endif /* HAVE_SASL2 */
350 
351  FILE* fd = fdopen(cur_sock, "r");
352 
353  if (!bAuthc) {
354  char user[USERLEN + 1];
355  char cred[CREDLEN + 1];
356 
357  if (get_auth_token(fd, user, cred, &nextline) == -1) {
358  silent_cerr(
359  "SocketDrive(" << GetLabel() << "): "
360  "corrupted stream" << std::endl);
361  fclose(fd);
362  continue;
363  }
364 
365  DEBUGCOUT("got auth token: user=\"" << user
366  << "\", cred=\"" << cred << "\"" << std::endl);
367 
368  if (auth->Auth(user, cred) != AuthMethod::AUTH_OK) {
369  silent_cerr(
370  "SocketDrive(" << GetLabel() << "): "
371  "authentication failed" << std::endl);
372  fclose(fd);
373  continue;
374  }
375  }
376 
377  DEBUGCOUT("authenticated" << std::endl);
378 
379  /*
380  * la nuova linea puo' essere gia' stata letta
381  * da get_auth_token
382  */
383  if (nextline == NULL) {
384  if (get_line(buf, bufsize, fd) == NULL) {
385  silent_cerr(
386  "SocketDrive(" << GetLabel() << "): "
387  "corrupted stream" << std::endl);
388  fclose(fd);
389  continue;
390  }
391  } else {
392  strncpy(buf, nextline, bufsize);
393  free(nextline);
394  }
395  nextline = buf;
396 
397  /* legge la label */
398  if (strncasecmp(nextline, "label:", 6) != 0) {
399  silent_cerr("SocketDrive(" << GetLabel() << "): "
400  "missing label" << std::endl);
401  fclose(fd);
402  continue;
403  }
404 
405  char *p = nextline + 6;
406  while (isspace(p[0])) {
407  p++;
408  }
409 
410  if (sscanf(p, "%d", &label) != 1) {
411  silent_cerr("SocketDrive(" << GetLabel() << "): "
412  "unable to read label" << std::endl);
413  fclose(fd);
414  continue;
415  }
416 
417  if (label <= 0 || label > iNumDrives) {
418  silent_cerr("SocketDrive(" << GetLabel() << "): "
419  "illegal label " << label << std::endl);
420  fclose(fd);
421  continue;
422  }
423 
424  while (true) {
425  if (get_line(buf, bufsize, fd) == NULL) {
426  silent_cerr(
427  "SocketDrive(" << GetLabel() << "): "
428  "corrupted stream" << std::endl);
429  fclose(fd);
430  break;
431  }
432 
433  nextline = buf;
434 
435  if (nextline[0] == '.') {
436  fclose(fd);
437  break;
438  }
439 
440  if (strncasecmp(nextline, "value:", 6) == 0) {
441  char *p = nextline+6;
442  while (isspace(p[0])) {
443  p++;
444  }
445 
446  if (sscanf(p, "%lf", &value) != 1) {
447  silent_cerr("SocketDrive(" << GetLabel() << "): "
448  "unable to read value"
449  << std::endl);
450  fclose(fd);
451  break;
452  }
453  got_value = 1;
454 
455  } else if (strncasecmp(nextline, "inc:", 4) == 0) {
456  char *p = nextline+4;
457  while (isspace(p[0])) {
458  p++;
459  }
460 
461  if (strncasecmp(p, "yes", 3) == 0) {
462  pFlags[label] |= SocketDrive::INCREMENTAL;
463  } else if (strncasecmp(p, "no", 2) == 0) {
464  pFlags[label] &= !SocketDrive::INCREMENTAL;
465  } else {
466  silent_cerr("SocketDrive(" << GetLabel() << "): "
467  "\"inc\" line in "
468  "\"" << nextline << "\" "
469  "looks corrupted"
470  << std::endl);
471  fclose(fd);
472  break;
473  }
474  nextline = NULL;
475 
476  } else if (strncasecmp(nextline, "imp:", 4) == 0) {
477  char *p = nextline+4;
478  while (isspace(p[0])) {
479  p++;
480  }
481 
482  if (strncasecmp(p, "yes", 3) == 0) {
483  pFlags[label] |= SocketDrive::IMPULSIVE;
484  } else if (strncasecmp(p, "no", 2) == 0) {
485  pFlags[label] &= !SocketDrive::IMPULSIVE;
486  } else {
487  silent_cerr("SocketDrive(" << GetLabel() << "): "
488  "\"imp\" line" " in "
489  "\"" << nextline << "\""
490  " looks corrupted"
491  << std::endl);
492  fclose(fd);
493  break;
494  }
495  nextline = NULL;
496  }
497 
498  /* usa i valori */
499  if (got_value) {
500  if (pFlags[label] & SocketDrive::INCREMENTAL) {
501  silent_cout("SocketDrive(" << GetLabel() << "): "
502  "adding " << value
503  << " to label " << label
504  << std::endl);
505  pdVal[label] += value;
506 
507  } else {
508  silent_cout("SocketDrive(" << GetLabel() << "): "
509  "setting label " << label
510  << " to value " << value
511  << std::endl);
512  pdVal[label] = value;
513  }
514  }
515  }
516  }
517 }
518 
519 /* Scrive il contributo del DriveCaller al file di restart */
520 std::ostream&
521 SocketDrive::Restart(std::ostream& out) const
522 {
523  return out << "SocketDrive not implemented yet" << std::endl;
524 }
525 
526 /* legge i drivers tipo socket */
527 
528 Drive *
529 SocketDR::Read(unsigned uLabel, const DataManager *pDM, MBDynParser& HP)
530 {
531  Drive* pDr = NULL;
532 
533  integer idrives = HP.GetInt();
534  unsigned short int port = MBDynSocketDrivePort;
535  const char *path = NULL;
536 
537  std::vector<doublereal> v0;
538  if (HP.IsKeyWord("initial" "values")) {
539  v0.resize(idrives);
540  for (integer i = 0; i < idrives; i++) {
541  v0[i] = HP.GetReal();
542  }
543  }
544 
545  if (HP.IsKeyWord("local")) {
546  path = HP.GetFileName();
547  ASSERT(path != NULL);
548 
549  } else if (HP.IsKeyWord("port")) {
550  port = HP.GetInt();
551 #ifdef IPPORT_USERRESERVED
552  if (port < IPPORT_USERRESERVED) {
553  silent_cerr("SocketDrive(" << uLabel << "): "
554  "cannot listen on port " << port
555  << ": less than IPPORT_USERRESERVED="
557  << " at line " << HP.GetLineData()
558  << std::endl);
560  }
561  /* if #undef'd, don't bother checking;
562  * the OS will do it for us */
563 #endif /* IPPORT_USERRESERVED */
564  }
565 
566  if (path == NULL) {
567  AuthMethod* pAuth = ReadAuthMethod(pDM, HP);
568 
569  if (pAuth == NULL) {
570  silent_cerr("need an authentication method "
571  "at line " << HP.GetLineData()
572  << std::endl);
574  }
575 
577  SocketDrive,
578  SocketDrive(uLabel, pDM->pGetDrvHdl(),
579  port, pAuth, idrives, v0));
580 
581  } else {
583  SocketDrive,
584  SocketDrive(uLabel, pDM->pGetDrvHdl(),
585  path, idrives, v0));
586  }
587 
588  return pDr;
589 }
590 
591 #endif /* USE_SOCKET */
#define MBDYN_EXCEPT_ARGS
Definition: except.h:63
virtual integer GetInt(integer iDefval=0)
Definition: parser.cc:1050
Definition: drive.h:89
#define SAFEDELETEARR(pnt)
Definition: mynewmem.h:713
virtual const char * GetFileName(enum Delims Del=DEFAULTDELIM)
Definition: parsinc.cc:673
const DriveHandler * pGetDrvHdl(void) const
Definition: dataman.h:340
int get_auth_token(FILE *fd, char *user, char *cred, char **nextline)
#define NO_OP
Definition: myassert.h:74
virtual Drive * Read(unsigned uLabel, const DataManager *pDM, MBDynParser &HP)
int mbdyn_make_inet_socket(struct sockaddr_in *name, const char *hostname, unsigned short int port, int dobind, int *perror)
Definition: auth.h:58
#define SAFENEW(pnt, item)
Definition: mynewmem.h:695
virtual bool IsKeyWord(const char *sKeyWord)
Definition: parser.cc:910
#define DEBUGCOUT(msg)
Definition: myassert.h:232
int get_line(FILE *fin, char *buf, int buf_size)
Definition: deriv.c:38
#define ASSERT(expression)
Definition: colamd.c:977
#define SAFENEWWITHCONSTRUCTOR(pnt, item, constructor)
Definition: mynewmem.h:698
const unsigned long BUFSIZE
Definition: discctrl.cc:332
int mbdyn_make_named_socket(struct sockaddr_un *name, const char *path, int dobind, int *perror)
#define SAFESTRDUP(pnt, src)
Definition: mynewmem.h:707
AuthMethod * ReadAuthMethod(const DataManager *, MBDynParser &HP)
Definition: auth.cc:451
#define SAFENEWARR(pnt, item, sz)
Definition: mynewmem.h:701
static const doublereal a
Definition: hfluid_.h:289
#define IPPORT_USERRESERVED
Definition: sock.h:66
static const std::vector< doublereal > v0
Definition: fixedstep.cc:45
unsigned short int port
Definition: autopilot.c:143
static doublereal buf[BUFSIZE]
Definition: discctrl.cc:333
double doublereal
Definition: colamd.c:52
long int integer
Definition: colamd.c:51
virtual HighParser::ErrOut GetLineData(void) const
Definition: parsinc.cc:697
const char * path
Definition: autopilot.c:141
#define SAFEDELETE(pnt)
Definition: mynewmem.h:710
virtual doublereal GetReal(const doublereal &dDefval=0.0)
Definition: parser.cc:1056