1 /*
2     This file is part of GNU APL, a free implementation of the
3     ISO/IEC Standard 13751, "Programming Language APL, Extended"
4 
5     Copyright (C) 2008-2015  Dr. Jürgen Sauermann
6 
7     This program is free software: you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <errno.h>
22 #include <fcntl.h>           /* For O_* constants */
23 #include <limits.h>
24 #include <netinet/tcp.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <sys/time.h>
29 
30 #include "config.h"   // for HAVE_ macros
31 
32 #ifdef HAVE_SYS_UN_H
33 #include <sys/un.h>
34 #endif
35 
36 #include <iomanip>
37 
38 #include "Backtrace.hh"
39 #include "Logging.hh"
40 #include "Svar_DB.hh"
41 #include "Svar_signals.hh"
42 #include "UserPreferences.hh"
43 
44 extern ostream & get_CERR();
45 
46 uint16_t Svar_DB::APserver_port = APSERVER_PORT;
47 
48 TCP_socket Svar_DB::DB_tcp = NO_TCP_SOCKET;
49 
50 Svar_record Svar_record_P::cache;
51 
52 //-----------------------------------------------------------------------------
53 bool
start_APserver(const char * server_sockname,const char * bin_dir,bool logit)54 Svar_DB::start_APserver(const char * server_sockname,
55                         const char * bin_dir, bool logit)
56 {
57    // bin_dir is the directory where the apl interpreter binary lives.
58    // The APserver then lives in:
59    //
60    // bin_dir/      if apl was built and installed, or
61    // bin_dir/APs/  if apl was started from the src directory in the source tree
62    //
63    // set APserver_path to the case that applies.
64    //
65 char APserver_path[APL_PATH_MAX + 1];
66 const int slen = snprintf(APserver_path, APL_PATH_MAX, "%s/APserver", bin_dir);
67    if (slen >= APL_PATH_MAX)   APserver_path[APL_PATH_MAX] = 0;
68 
69    APserver_path[APL_PATH_MAX] = 0;
70    if (access(APserver_path, X_OK) != 0)   // no APserver
71       {
72         logit && get_CERR() << "    Executable " << APserver_path
73                  << " not found (this is OK when apl was started\n"
74                     "    from the src directory): " << strerror(errno) << endl;
75 
76         const int slen = snprintf(APserver_path, APL_PATH_MAX,
77                                   "%s/APs/APserver", bin_dir);
78         if (slen >= APL_PATH_MAX)   APserver_path[APL_PATH_MAX] = 0;
79         if (access(APserver_path, X_OK) != 0)   // no APs/APserver either
80            {
81              get_CERR() << "Executable " << APserver_path << " not found.\n"
82 "This could means that 'apl' was not installed ('make install') or that it\n"
83 "was started in a non-standard way. The expected location of APserver is \n"
84 "either the same directory as the binary 'apl' or the subdirectory 'APs' of\n"
85 "that directory (the directory should also be in $PATH)." << endl;
86 
87              return true;   // error
88            }
89       }
90 
91    logit && get_CERR() << "Found " << APserver_path << endl;
92 
93 char popen_args[APL_PATH_MAX + 1];
94    {
95      int slen;
96      if (server_sockname)
97         slen = snprintf(popen_args, APL_PATH_MAX,
98                  "%s --path %s --auto", APserver_path, server_sockname);
99      else
100         slen = snprintf(popen_args, APL_PATH_MAX,
101                  "%s --port %u --auto", APserver_path, APserver_port);
102      if (slen >= APL_PATH_MAX)   popen_args[APL_PATH_MAX] = 0;
103    }
104 
105    logit && get_CERR() << "Starting " << popen_args << "..." << endl;
106 
107 FILE * fp = popen(popen_args, "r");
108    if (fp == 0)
109       {
110         get_CERR() << "popen(" << popen_args << " failed: " << strerror(errno)
111              << endl;
112         return true;   // error
113       }
114 
115    for (int cc; (cc = getc(fp)) != EOF;)
116        {
117          logit && get_CERR() << char(cc);
118        }
119 
120    logit && get_CERR() << endl;
121 
122 const int APserver_result = pclose(fp);
123    if (APserver_result)
124       {
125          get_CERR() << "pclose(APserver) returned error:"
126                     << strerror(errno) << endl;
127       }
128 
129    return false;   // success
130 }
131 //-----------------------------------------------------------------------------
132 TCP_socket
connect_to_APserver(const char * bin_dir,const char * prog,int retry_max,bool logit)133 Svar_DB::connect_to_APserver(const char * bin_dir, const char * prog,
134                                       int retry_max, bool logit)
135 {
136 int sock = NO_TCP_SOCKET;
137 const char * server_sockname = APSERVER_PATH;
138 char peer[100];
139 
140    // we use AF_UNIX sockets if the platform supports it and unix_socket_name
141    // is provided. Otherwise fall back to TCP.
142    //
143 #if HAVE_SYS_UN_H && APSERVER_TRANSPORT != 0
144       {
145         logit && get_CERR() << prog
146                             << ": Using AF_UNIX socket towards APserver..."
147                             << endl;
148         sock = socket(AF_UNIX, SOCK_STREAM, 0);
149         if (sock == NO_TCP_SOCKET)
150            {
151              get_CERR() << prog
152                         << ": socket(AF_UNIX, SOCK_STREAM, 0) failed at "
153                         << LOC << endl;
154              return NO_TCP_SOCKET;
155            }
156 
157         const unsigned int slen = snprintf(peer, sizeof(peer),
158                                            "%s", server_sockname);
159         if (slen >= sizeof(peer))   peer[sizeof(peer) - 1] = 0;
160       }
161 #else // use TCP
162       {
163         server_sockname = 0;
164         logit && get_CERR() << "Using TCP socket towards APserver..."
165                             << endl;
166         sock = TCP_socket(socket(AF_INET, SOCK_STREAM, 0));
167         if (sock == NO_TCP_SOCKET)
168            {
169              get_CERR() << "*** socket(AF_INET, SOCK_STREAM, 0) failed at "
170                         << LOC << endl;
171              return NO_TCP_SOCKET;
172            }
173 
174         // disable nagle
175         {
176           const int ndelay = 1;
177           setsockopt(sock, 6, TCP_NODELAY, &ndelay, sizeof(int));
178         }
179 
180         // bind local port to 127.0.0.1
181         //
182         SockAddr local;
183         memset(&local, 0, sizeof(SockAddr));
184         local.inet.sin_family = AF_INET;
185         local.inet.sin_addr.s_addr = htonl(0x7F000001);
186 
187         if (::bind(sock, &local.addr, sizeof(sockaddr_in)))
188            {
189              get_CERR() << "bind(127.0.0.1) failed:" << strerror(errno) << endl;
190              ::close(sock);
191              return NO_TCP_SOCKET;
192            }
193 
194         const unsigned int slen = snprintf(peer, sizeof(peer),
195                                   "127.0.0.1 TCP port %d", APserver_port);
196         if (slen >= sizeof(peer))   peer[sizeof(peer) - 1] = 0;
197       }
198 #endif
199 
200    // We try to connect to the APserver. If that fails then no
201    // APserver is running; we fork one and try again.
202    //
203    //  If emacs mode is enabled then we try a little longer since emacs starts
204    // up at the same time (and we know that emacs is slow).
205    //
206    loop(retry, retry_max)
207        {
208 #if HAVE_SYS_UN_H
209         if (server_sockname)
210            {
211              SockAddr remote;
212              memset(&remote, 0, sizeof(SockAddr));
213              remote.uNix.sun_family = AF_UNIX;
214              strcpy(remote.uNix.sun_path + ABSTRACT_OFFSET, server_sockname);
215 
216              if (::connect(sock, &remote.addr, sizeof(sockaddr_un)) == 0)
217                 break;   // success
218            }
219         else   // TCP
220 #endif
221            {
222              SockAddr remote;
223              memset(&remote, 0, sizeof(sockaddr_in));
224              remote.inet.sin_family = AF_INET;
225              remote.inet.sin_port = htons(APserver_port);
226              remote.inet.sin_addr.s_addr = htonl(0x7F000001);
227 
228              if (::connect(sock, &remote.addr, sizeof(sockaddr_in)) == 0)
229                 break;   // success
230            }
231 
232          // ::connect() to APserver failed. If
233          // then most likely no APserver was started and we do it.
234          //
235          if (logit)   get_CERR() << "connecting to " << peer
236                                  << " failed." << endl;
237 
238          if (retry == 0)   // first attempt
239             {
240               // this was the first ::connect() that has failed.
241               // most likely no APserver was started yet and we do it now
242               //
243               if (logit)   get_CERR() <<
244 "    (the first ::connect() to APserver is expected to fail, unless\n" <<
245 "     APserver was started manually)\n" <<
246 "Starting a new APserver listening on " << peer << endl;
247 
248               if (start_APserver(server_sockname, bin_dir, logit))
249                  {
250                    // starting of APserver failed: no point to try longer
251                    //
252                    ::close(sock);
253                    return NO_TCP_SOCKET;
254                  }
255 
256               usleep(300000);   // give APserver some time to start up
257               continue;
258             }
259 
260          if ((retry == (retry_max - 1)) && bin_dir)   // last attempt: give up
261             {
262               get_CERR() <<
263                          "::connect() to supposedly existing APserver failed: "
264                          << strerror(errno) << endl;
265 
266               ::close(sock);
267               return NO_TCP_SOCKET;
268            }
269 
270          if (logit)   get_CERR() <<
271             "    (::connect() should succeed eventually. This was attempt "
272             << retry << " of " << retry_max << ")" << endl;
273 
274          usleep(200000);   // more time for APserver to start up
275        }
276 
277    // at this point sock is != NO_TCP_SOCKET and connected.
278    //
279    usleep(50000);
280    logit && get_CERR() << "connected to APserver, socket is " << sock << endl;
281 
282    return TCP_socket(sock);
283 }
284 //-----------------------------------------------------------------------------
285 void
DB_tcp_error(const char * op,int got,int expected)286 Svar_DB::DB_tcp_error(const char * op, int got, int expected)
287 {
288    // op == 0 indicates close
289    //
290    if (op)
291       {
292         get_CERR() << "⋆⋆⋆ " << op << " failed: got " << got << " when expecting "
293                    << expected << " (" << strerror(errno) << ")" << endl;
294       }
295 
296    shutdown(DB_tcp, SHUT_RDWR);
297 }
298 //=============================================================================
299 
Svar_record_P(SV_key key)300 Svar_record_P::Svar_record_P(SV_key key)
301 {
302    cache.clear();
303 
304    if (!Svar_DB::APserver_available())   return;
305 
306 const int sock = Svar_DB::get_DB_tcp();
307 
308    { READ_SVAR_RECORD_c request(sock, key); }
309 
310 char * del = 0;
311 char buffer[2*MAX_SIGNAL_CLASS_SIZE + sizeof(Svar_record)];
312 ostream * log = (LOG_startup != 0 || LOG_Svar_DB_signals != 0) ? & cerr : 0;
313 Signal_base * response = Signal_base::recv_TCP(sock, buffer, sizeof(buffer),
314                                                del, log);
315    if (response)
316       {
317         memcpy(static_cast<void *>(&cache),
318                response->get__SVAR_RECORD_IS__record().data(),
319                sizeof(Svar_record));
320 
321         delete response;
322       }
323    else   get_CERR() << "Svar_record_P() failed at " << LOC << endl;
324    if (del)   delete del;
325 }
326 //=============================================================================
327 void
init(const char * bin_dir,const char * prog,int retry_max,bool logit,bool do_svars)328 Svar_DB::init(const char * bin_dir, const char * prog, int retry_max,
329               bool logit, bool do_svars)
330 {
331    if (!do_svars)   // shared variables disabled
332       {
333         if (logit)
334            get_CERR() << "Not opening shared memory because command "
335                          "line option --noSV (or similar) was given." << endl;
336         return;
337       }
338 
339    DB_tcp = connect_to_APserver(bin_dir, prog, retry_max, logit);
340    if (APserver_available())
341       {
342         if (logit)   get_CERR() << "using Svar_DB on APserver!" << endl;
343       }
344 }
345 //-----------------------------------------------------------------------------
346 SV_key
match_or_make(const uint32_t * UCS_varname,const AP_num3 & to,const Svar_partner & from)347 Svar_DB::match_or_make(const uint32_t * UCS_varname, const AP_num3 & to,
348                        const Svar_partner & from)
349 {
350 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
351    if (tcp == NO_TCP_SOCKET)   return 0;
352 
353 
354 uint32_t vname1[MAX_SVAR_NAMELEN];
355    memset(vname1, 0, sizeof(vname1));
356    loop(v, MAX_SVAR_NAMELEN)
357       {
358         if (*UCS_varname)   vname1[v] = *UCS_varname++;
359         else                break;
360       }
361 
362 string vname(charP(vname1), MAX_SVAR_NAMELEN*sizeof(uint32_t));
363 
364 MATCH_OR_MAKE_c request(tcp, vname,
365                              to.proc,      to.parent,      to.grand,
366                              from.id.proc, from.id.parent, from.id.grand);
367 
368 char * del = 0;
369 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
370 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
371                                                del, 0);
372 
373    if (response)
374       {
375         const SV_key ret = response->get__MATCH_OR_MAKE_RESULT__key();
376         delete response;
377         return ret;
378      }
379 
380    else            return 0;
381 }
382 //-----------------------------------------------------------------------------
383 SV_key
get_events(Svar_event & events,AP_num3 id)384 Svar_DB::get_events(Svar_event & events, AP_num3 id)
385 {
386 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
387    if (tcp == NO_TCP_SOCKET)
388       {
389         events = SVE_NO_EVENTS;
390         return 0;
391       }
392 
393 GET_EVENTS_c request(tcp, id.proc, id.parent, id.grand);
394 
395 char * del = 0;
396 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
397 Signal_base * response =
398                     Signal_base::recv_TCP(tcp, buffer, sizeof(buffer), del, 0);
399 
400    if (response)
401       {
402         events = Svar_event(response->get__EVENTS_ARE__events());
403         const SV_key ret = response->get__EVENTS_ARE__key();
404         delete response;
405         return ret;
406       }
407    else
408       {
409         events = SVE_NO_EVENTS;
410         return 0;
411       }
412 }
413 //-----------------------------------------------------------------------------
414 Svar_event
clear_all_events(AP_num3 id)415 Svar_DB::clear_all_events(AP_num3 id)
416 {
417 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
418    if (tcp == NO_TCP_SOCKET)
419       {
420         return SVE_NO_EVENTS;
421       }
422 
423 CLEAR_ALL_EVENTS_c request(tcp, id.proc, id.parent, id.grand);
424 
425 char * del = 0;
426 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
427 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
428                                                del, 0);
429 
430    if (response)
431       {
432         const Svar_event ret = Svar_event(response->get__EVENTS_ARE__events());
433         delete response;
434         return ret;
435       }
436    else
437       {
438         return SVE_NO_EVENTS;
439       }
440 }
441 //-----------------------------------------------------------------------------
442 void
set_control(SV_key key,Svar_Control ctl)443 Svar_DB::set_control(SV_key key, Svar_Control ctl)
444 {
445 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
446    if (tcp == NO_TCP_SOCKET)   return;
447 
448 SET_CONTROL_c request(tcp, key, ctl);
449 }
450 //-----------------------------------------------------------------------------
451 void
set_state(SV_key key,bool used,const char * loc)452 Svar_DB::set_state(SV_key key, bool used, const char * loc)
453 {
454 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
455    if (tcp == NO_TCP_SOCKET)   return;
456 
457 string sloc(loc);
458 SET_STATE_c request(tcp, key, used, sloc);
459 }
460 //-----------------------------------------------------------------------------
461 bool
may_set(SV_key key,int attempt)462 Svar_DB::may_set(SV_key key, int attempt)
463 {
464 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
465    if (tcp == NO_TCP_SOCKET)   return 0;
466 
467 MAY_SET_c request(tcp, key, attempt);
468 
469 char * del = 0;
470 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
471 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
472                                                del, 0);
473 
474    if (response)
475       {
476         const bool ret = response->get__YES_NO__yes();
477         delete response;
478         return ret;
479      }
480 
481    return true;
482 }
483 //-----------------------------------------------------------------------------
484 bool
may_use(SV_key key,int attempt)485 Svar_DB::may_use(SV_key key, int attempt)
486 {
487 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
488    if (tcp == NO_TCP_SOCKET)   return 0;
489 
490 MAY_USE_c request(tcp, key, attempt);
491 
492 char * del = 0;
493 char buffer[2*MAX_SIGNAL_CLASS_SIZE];
494 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
495                                                del, 0);
496 
497    if (response)
498       {
499         const bool ret = response->get__YES_NO__yes();
500         delete response;
501         return ret;
502      }
503    return true;
504 }
505 //-----------------------------------------------------------------------------
506 void
add_event(SV_key key,AP_num3 id,Svar_event event)507 Svar_DB::add_event(SV_key key, AP_num3 id, Svar_event event)
508 {
509 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
510    if (tcp == NO_TCP_SOCKET)   return;
511 
512 ADD_EVENT_c request(tcp, key, id.proc, id.parent, id.grand, event);
513 }
514 //-----------------------------------------------------------------------------
515 void
retract_var(SV_key key)516 Svar_DB::retract_var(SV_key key)
517 {
518 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
519    if (tcp == NO_TCP_SOCKET)   return;
520 
521 RETRACT_VAR_c request(tcp, key);
522 }
523 //-----------------------------------------------------------------------------
524 AP_num3
find_offering_id(SV_key key)525 Svar_DB::find_offering_id(SV_key key)
526 {
527 AP_num3 offering_id;
528 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
529    if (tcp == NO_TCP_SOCKET)   return offering_id;
530 
531 FIND_OFFERING_ID_c request(tcp, key);
532 
533 char * del = 0;
534 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
535 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
536                                                del, 0);
537 
538    if (response)
539       {
540          offering_id.proc = AP_num(response->get__OFFERING_ID_IS__proc());
541          offering_id.parent = AP_num(response->get__OFFERING_ID_IS__parent());
542          offering_id.grand = AP_num(response->get__OFFERING_ID_IS__grand());
543         delete response;
544       }
545 
546    return offering_id;
547 }
548 //-----------------------------------------------------------------------------
549 void
get_offering_processors(AP_num to_proc,std::vector<AP_num> & processors)550 Svar_DB::get_offering_processors(AP_num to_proc,
551                                  std::vector<AP_num> & processors)
552 {
553 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
554    if (tcp == NO_TCP_SOCKET)   return;
555 
556 GET_OFFERING_PROCS_c request(tcp, to_proc);
557 
558 char * del = 0;
559 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
560 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
561                                                del, 0);
562 
563    if (response)
564       {
565         const string & op = response->get__OFFERING_PROCS_ARE__offering_procs();
566         const AP_num * procs = reinterpret_cast<const AP_num *>(op.data());
567         const size_t count = op.size() / sizeof(AP_num);
568 
569         loop(c, count)   processors.push_back(*procs++);
570         delete response;
571       }
572 }
573 //-----------------------------------------------------------------------------
574 void
get_offered_variables(AP_num to_proc,AP_num from_proc,std::vector<uint32_t> & varnames)575 Svar_DB::get_offered_variables(AP_num to_proc, AP_num from_proc,
576                                std::vector<uint32_t> & varnames)
577 {
578 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
579    if (tcp == NO_TCP_SOCKET)   return;
580 
581 GET_OFFERED_VARS_c request(tcp, to_proc, from_proc);
582 
583 char * del = 0;
584 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
585 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
586                                                del, 0);
587 
588    if (response)
589       {
590         const string & ov = response->get__OFFERED_VARS_ARE__offered_vars();
591         const uint32_t * names = reinterpret_cast<const uint32_t *>(ov.data());
592         const size_t count = ov.size() / sizeof(uint32_t);
593 
594         loop(c, count)   varnames.push_back(*names++);
595         delete response;
596       }
597 }
598 //-----------------------------------------------------------------------------
599 bool
is_registered_id(const AP_num3 & id)600 Svar_DB::is_registered_id(const AP_num3 & id)
601 {
602 const TCP_socket tcp = get_Svar_DB_tcp(__FUNCTION__);
603    if (tcp == NO_TCP_SOCKET)   return 0;
604 
605 IS_REGISTERED_ID_c request(tcp, id.proc, id.parent, id.grand);
606 
607 char * del = 0;
608 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
609 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
610                                                del, 0);
611 
612    if (response)
613       {
614         const bool ret = response->get__YES_NO__yes();
615         delete response;
616         return ret;
617      }
618 
619    return false;
620 }
621 //-----------------------------------------------------------------------------
622 TCP_socket
get_Svar_DB_tcp(const char * calling_function)623 Svar_DB::get_Svar_DB_tcp(const char * calling_function)
624 {
625 const TCP_socket tcp = Svar_DB::get_DB_tcp();
626    if (tcp == NO_TCP_SOCKET)
627       {
628         get_CERR() << "Svar_DB not connected in Svar_DB::"
629              << calling_function << "()" << endl;
630       }
631 
632    return tcp;
633 }
634 //-----------------------------------------------------------------------------
635 SV_key
find_pairing_key(SV_key key)636 Svar_DB::find_pairing_key(SV_key key)
637 {
638 const TCP_socket tcp = Svar_DB::get_DB_tcp();
639    if (tcp == NO_TCP_SOCKET)   return 0;
640 
641 FIND_PAIRING_KEY_c request(tcp, key);
642 
643 char * del = 0;
644 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 16];
645 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
646                                                del, 0);
647 
648    if (response)
649       {
650         const SV_key ret = response->get__PAIRING_KEY_IS__pairing_key();
651         delete response;
652         return ret;
653      }
654 
655    return 0;
656 }
657 //-----------------------------------------------------------------------------
658 void
print(ostream & out)659 Svar_DB::print(ostream & out)
660 {
661 const TCP_socket tcp = Svar_DB::get_DB_tcp();
662    if (tcp == NO_TCP_SOCKET)   return;
663 
664 PRINT_SVAR_DB_c request(tcp);
665 
666 char * del = 0;
667 char buffer[2*MAX_SIGNAL_CLASS_SIZE + 4000];
668 Signal_base * response = Signal_base::recv_TCP(tcp, buffer, sizeof(buffer),
669                                                del, 0);
670 
671    if (response)
672       {
673         out << response->get__SVAR_DB_PRINTED__printout();
674         delete response;
675       }
676 }
677 //-----------------------------------------------------------------------------
678 
679