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
SocketDrive(unsigned int uL,const DriveHandler * pDH,unsigned short int p,AuthMethod * a,integer nd,const std::vector<doublereal> & v0)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);
88 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
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);
97 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
98 }
99
100 Init();
101 }
102
SocketDrive(unsigned int uL,const DriveHandler * pDH,const char * path,integer nd,const std::vector<doublereal> & v0)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);
128 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
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);
137 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
138 }
139
140 Init();
141 }
142
143 void
Init(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);
152 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
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);
159 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
160 }
161
162 if (listen(sock, 1) < 0) {
163 silent_cerr("SocketDrive(" << GetLabel()
164 << "): listen failed" << std::endl);
165 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
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
~SocketDrive(void)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 *
get_line(char * buf,size_t bufsize,FILE * fd)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
get_auth_token(FILE * fd,char * user,char * cred,char ** nextline)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
ServePending(const doublereal &)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&
Restart(std::ostream & out) const521 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 *
Read(unsigned uLabel,const DataManager * pDM,MBDynParser & HP)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="
556 << IPPORT_USERRESERVED
557 << " at line " << HP.GetLineData()
558 << std::endl);
559 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
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);
573 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
574 }
575
576 SAFENEWWITHCONSTRUCTOR(pDr,
577 SocketDrive,
578 SocketDrive(uLabel, pDM->pGetDrvHdl(),
579 port, pAuth, idrives, v0));
580
581 } else {
582 SAFENEWWITHCONSTRUCTOR(pDr,
583 SocketDrive,
584 SocketDrive(uLabel, pDM->pGetDrvHdl(),
585 path, idrives, v0));
586 }
587
588 return pDr;
589 }
590
591 #endif /* USE_SOCKET */
592