1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 1997-2020. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 *
20 */
21
22 /* An exception from using eidef.h, use config.h directly */
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28
29 #ifdef __WIN32__
30 #include <winsock2.h>
31 #include <windows.h>
32 #include <winbase.h>
33
34 #elif VXWORKS
35 #include <stdio.h>
36 #include <string.h>
37 #include <vxWorks.h>
38 #include <hostLib.h>
39 #include <selectLib.h>
40 #include <ifLib.h>
41 #include <sockLib.h>
42 #include <taskLib.h>
43 #include <inetLib.h>
44 #include <unistd.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netinet/tcp.h>
48 #include <symLib.h>
49 #include <sysSymTbl.h>
50 #include <sysLib.h>
51 #include <tickLib.h>
52
53 #if TIME_WITH_SYS_TIME
54 # include <sys/time.h>
55 # include <time.h>
56 #else
57 # if HAVE_SYS_TIME_H
58 # include <sys/time.h>
59 # else
60 # include <time.h>
61 # endif
62 #endif
63
64 #include <a_out.h>
65
66 /* #include "netdb.h" */
67 #else /* other unix */
68 #include <errno.h>
69 #include <netdb.h>
70 #include <netinet/in.h>
71 #include <arpa/inet.h>
72 #include <signal.h>
73 #include <stdio.h>
74 #include <string.h>
75 #include <sys/param.h>
76 #include <sys/socket.h>
77 #include <sys/stat.h>
78 #include <sys/wait.h>
79 #include <sys/time.h>
80 #include <time.h>
81 #include <unistd.h>
82 #include <sys/types.h>
83 #include <signal.h>
84 #endif
85
86 #include "ei.h"
87 #include "ei_resolve.h"
88 #include "erl_start.h"
89
90 /* FIXME is this a case a vfork can be used? */
91 #if !HAVE_WORKING_VFORK
92 # define vfork fork
93 #endif
94
95 #ifndef MAXPATHLEN
96 #define MAXPATHLEN 1024
97 #endif
98
99 #ifndef RSH
100 #define RSH "/usr/bin/ssh"
101 #endif
102
103 #ifndef HAVE_SOCKLEN_T
104 typedef int SocklenType;
105 #else
106 typedef socklen_t SocklenType;
107 #endif
108
109 /* FIXME check errors from malloc */
110
111 static struct in_addr *get_addr(const char *hostname, struct in_addr *oaddr);
112
113 static int wait_for_erlang(int sockd, int magic, struct timeval *timeout);
114 #if defined(VXWORKS) || defined(__WIN32__)
115 static int unique_id(void);
116 static unsigned long spawn_erlang_epmd(ei_cnode *ec,
117 char *alive,
118 Erl_IpAddr adr,
119 int flags,
120 char *erl_or_epmd,
121 char *args[],
122 int port,
123 int is_erlang);
124 #else
125 static int exec_erlang(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
126 char *erl, char *args[],int port);
127 #endif
128 /* Start an Erlang node. return value 0 indicates that node was
129 * started successfully, negative values indicate error.
130 *
131 * node - the name of the remote node to start (alivename@hostname).
132 * flags - turn on or off certain options. See erl_start.h for a list.
133 * erl - is the name of the erl script to call. If NULL, the default
134 * name "erl" will be used.
135 * args - a NULL-terminated list of strings containing
136 * additional arguments to be sent to the remote Erlang node. These
137 * strings are simply appended to the end of the command line, so any
138 * quoting of special characters, etc must be done by the caller.
139 * There may be some conflicts between some of these arguments and the
140 * default arguments hard-coded into this function, so be careful.
141 */
erl_start_sys(ei_cnode * ec,char * alive,Erl_IpAddr adr,int flags,char * erl,char * args[])142 int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
143 char *erl, char *args[])
144 {
145 struct timeval timeout;
146 struct sockaddr_in addr;
147 SocklenType namelen;
148 int port;
149 int sockd = 0;
150 int one = 1;
151 #if defined(VXWORKS) || defined(__WIN32__)
152 unsigned long pid = 0;
153 #else
154 int pid = 0;
155 #endif
156 int r = 0;
157
158 if (((sockd = socket(AF_INET, SOCK_STREAM, 0)) < 0) ||
159 (setsockopt(sockd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0)) {
160 r = ERL_SYS_ERROR;
161 goto done;
162 }
163
164 memset(&addr,0,sizeof(addr));
165 addr.sin_family = AF_INET;
166 addr.sin_addr.s_addr = htonl(INADDR_ANY);
167 addr.sin_port = 0;
168
169 if (bind(sockd,(struct sockaddr *)&addr,sizeof(addr))<0) {
170 return ERL_SYS_ERROR;
171 }
172 namelen = sizeof(addr);
173 if (getsockname(sockd,(struct sockaddr *)&addr,&namelen)<0) {
174 return ERL_SYS_ERROR;
175 }
176 port = ntohs(addr.sin_port);
177
178 listen(sockd,5);
179
180 #if defined(VXWORKS) || defined(__WIN32__)
181 if((pid = spawn_erlang_epmd(ec,alive,adr,flags,erl,args,port,1))
182 == 0)
183 return ERL_SYS_ERROR;
184 timeout.tv_usec = 0;
185 timeout.tv_sec = 10; /* ignoring ERL_START_TIME */
186 if((r = wait_for_erlang(sockd,unique_id(),&timeout))
187 == ERL_TIMEOUT) {
188 #if defined(VXWORKS)
189 taskDelete((int) pid);
190 if(taskIdVerify((int) pid) != ERROR)
191 taskDeleteForce((int) pid);
192 #else /* Windows */
193 /* Well, this is not a nice way to do it, and it does not
194 always kill the emulator, but the alternatives are few.*/
195 TerminateProcess((HANDLE) pid,1);
196 #endif /* defined(VXWORKS) */
197 }
198 #else /* Unix */
199 switch ((pid = fork())) {
200 case -1:
201 r = ERL_SYS_ERROR;
202 break;
203
204 case 0:
205 /* child - start the erlang node */
206 exec_erlang(ec, alive, adr, flags, erl, args, port);
207
208 /* error if reached - parent reports back to caller after timeout
209 so we just exit here */
210 exit(1);
211 break;
212
213 default:
214
215 /* parent - waits for response from Erlang node */
216 /* child pid used here as magic number */
217 timeout.tv_usec = 0;
218 timeout.tv_sec = 10; /* ignoring ERL_START_TIME */
219 if ((r = wait_for_erlang(sockd,pid,&timeout)) == ERL_TIMEOUT) {
220 /* kill child if no response */
221 kill(pid,SIGINT);
222 sleep(1);
223 if (waitpid(pid,NULL,WNOHANG) != pid) {
224 /* no luck - try harder */
225 kill(pid,SIGKILL);
226 sleep(1);
227 waitpid(pid,NULL,WNOHANG);
228 }
229 }
230
231 }
232 #endif /* defined(VXWORKS) || defined(__WIN32__) */
233
234 done:
235 #if defined(__WIN32__)
236 if (sockd) closesocket(sockd);
237 #else
238 if (sockd) close(sockd);
239 #endif
240 return r;
241 } /* erl_start_sys() */
242
243 #if defined(VXWORKS) || defined(__WIN32__)
244 #if defined(VXWORKS)
245 #define DEF_ERL_COMMAND ""
246 #define DEF_EPMD_COMMAND ""
247 #define ERLANG_SYM "start_erl"
248 #define EPMD_SYM "start_epmd"
249 #define ERL_REPLY_FMT "-s erl_reply reply %s %d %d"
250 #else
251 #define DEF_ERL_COMMAND "erl"
252 #define DEF_EPMD_COMMAND "epmd"
253 #define ERL_REPLY_FMT "-s erl_reply reply \"%s\" \"%d\" \"%d\""
254 #endif
255 #define ERL_NAME_FMT "-noinput -name %s"
256 #define ERL_SNAME_FMT "-noinput -sname %s"
257
258 #define IP_ADDR_CHARS 15
259 #define FORMATTED_INT_LEN 10
260
unique_id(void)261 static int unique_id(void){
262 #if defined(VXWORKS)
263 return taskIdSelf();
264 #else
265 return (int) GetCurrentThreadId();
266 #endif
267 }
268
enquote_args(char ** oargs,char *** qargs)269 static int enquote_args(char **oargs, char ***qargs){
270 char **args;
271 int len;
272 int i;
273 int qwhole;
274 int extra;
275 char *ptr;
276 char *ptr2;
277
278 if(oargs == NULL){
279 *qargs = malloc(sizeof(char *));
280 **qargs = NULL;
281 return 0;
282 };
283
284 for(len=0;oargs[len] != NULL; ++len)
285 ;
286 args = malloc(sizeof(char *) * (len + 1));
287
288 for(i = 0; i < len; ++i){
289 qwhole = strchr(oargs[i],' ') != NULL;
290 extra = qwhole * 2;
291 for(ptr = oargs[i]; *ptr != '\0'; ++ptr)
292 extra += (*ptr == '"');
293 args[i] = malloc(strlen(oargs[i]) +
294 extra +
295 1);
296 ptr2 = args[i];
297 if(qwhole)
298 *(ptr2++) = '"';
299 for(ptr = oargs[i]; *ptr != '\0'; ++ptr){
300 if(*ptr == '"')
301 *(ptr2++) = '\\';
302 *(ptr2++) = *ptr;
303 }
304 if(qwhole)
305 *(ptr2++) = '"';
306 *ptr2 = '\0';
307 }
308 args[len] = NULL;
309 *qargs = args;
310 return len;
311 }
312
free_args(char ** args)313 static void free_args(char **args){
314 char **ptr = args;
315 while(*ptr != NULL)
316 free(*(ptr++));
317 free(args);
318 }
319
320 #if defined(VXWORKS)
lookup_function(char * symname)321 static FUNCPTR lookup_function(char *symname){
322 char *value;
323 SYM_TYPE type;
324 if(symFindByName(sysSymTbl,
325 symname,
326 &value,
327 &type) == ERROR /*|| type != N_TEXT*/)
328 return NULL;
329 return (FUNCPTR) value;
330 }
331 #endif /* defined(VXWORKS) */
332
333 /* In NT and VxWorks, we cannot fork(), Erlang and Epmd gets
334 spawned by this function instead. */
335
spawn_erlang_epmd(ei_cnode * ec,char * alive,Erl_IpAddr adr,int flags,char * erl_or_epmd,char * args[],int port,int is_erlang)336 static unsigned long spawn_erlang_epmd(ei_cnode *ec,
337 char *alive,
338 Erl_IpAddr adr,
339 int flags,
340 char *erl_or_epmd,
341 char *args[],
342 int port,
343 int is_erlang)
344 {
345 #if defined(VXWORKS)
346 FUNCPTR erlfunc;
347 #else /* Windows */
348 STARTUPINFO sinfo;
349 SECURITY_ATTRIBUTES sa;
350 PROCESS_INFORMATION pinfo;
351 #endif
352 char *cmdbuf;
353 int cmdlen;
354 char *ptr;
355 int i;
356 int num_args;
357 char *name_format;
358 struct in_addr myaddr;
359 struct in_addr *hisaddr = (struct in_addr *)adr;
360 char iaddrbuf[IP_ADDR_CHARS + 1];
361 int ret;
362
363 if(is_erlang){
364 get_addr(ei_thishostname(ec), &myaddr);
365 #if defined(VXWORKS)
366 inet_ntoa_b(myaddr, iaddrbuf);
367 #else /* Windows */
368 if((ptr = inet_ntoa(myaddr)) == NULL)
369 return 0;
370 else
371 strcpy(iaddrbuf,ptr);
372 #endif
373 }
374 if ((flags & ERL_START_REMOTE) ||
375 (is_erlang && (hisaddr->s_addr != myaddr.s_addr))) {
376 return 0;
377 } else {
378 num_args = enquote_args(args, &args);
379 for(cmdlen = i = 0; args[i] != NULL; ++i)
380 cmdlen += strlen(args[i]) + 1;
381 #if !defined(VXWORKS)
382 /* On VxWorks, we dont actually run a command,
383 we call start_erl() */
384 if(!erl_or_epmd)
385 #endif
386 erl_or_epmd = (is_erlang) ? DEF_ERL_COMMAND :
387 DEF_EPMD_COMMAND;
388 if(is_erlang){
389 name_format = (flags & ERL_START_LONG) ? ERL_NAME_FMT :
390 ERL_SNAME_FMT;
391 cmdlen +=
392 strlen(erl_or_epmd) + (*erl_or_epmd != '\0') +
393 strlen(name_format) + 1 + strlen(alive) +
394 strlen(ERL_REPLY_FMT) + 1 + strlen(iaddrbuf) + 2 * FORMATTED_INT_LEN + 1;
395 ptr = cmdbuf = malloc(cmdlen);
396 if(*erl_or_epmd != '\0')
397 ptr += sprintf(ptr,"%s ",erl_or_epmd);
398 ptr += sprintf(ptr, name_format,
399 alive);
400 ptr += sprintf(ptr, " " ERL_REPLY_FMT,
401 iaddrbuf, port, unique_id());
402 } else { /* epmd */
403 cmdlen += strlen(erl_or_epmd) + (*erl_or_epmd != '\0') + 1;
404 ptr = cmdbuf = malloc(cmdlen);
405 if(*erl_or_epmd != '\0')
406 ptr += sprintf(ptr,"%s ",erl_or_epmd);
407 else
408 *(ptr++) = '\0';
409 }
410 for(i= 0; args[i] != NULL; ++i){
411 *(ptr++) = ' ';
412 strcpy(ptr,args[i]);
413 ptr += strlen(args[i]);
414 }
415 free_args(args);
416 if (flags & ERL_START_VERBOSE) {
417 fprintf(stderr,"erl_call: commands are %s\n",cmdbuf);
418 }
419 /* OK, one single command line... */
420 #if defined(VXWORKS)
421 erlfunc = lookup_function((is_erlang) ? ERLANG_SYM :
422 EPMD_SYM);
423 if(erlfunc == NULL){
424 if (flags & ERL_START_VERBOSE) {
425 fprintf(stderr,"erl_call: failed to find symbol %s\n",
426 (is_erlang) ? ERLANG_SYM : EPMD_SYM);
427 }
428 ret = 0;
429 } else {
430 /* Just call it, it spawns itself... */
431 ret = (unsigned long)
432 (*erlfunc)((int) cmdbuf,0,0,0,0,0,0,0,0,0);
433 if(ret == (unsigned long) ERROR)
434 ret = 0;
435 }
436 #else /* Windows */
437 /* Hmmm, hidden or unhidden window??? */
438 memset(&sinfo,0,sizeof(sinfo));
439 sinfo.cb = sizeof(STARTUPINFO);
440 sinfo.dwFlags = STARTF_USESHOWWINDOW /*|
441 STARTF_USESTDHANDLES*/;
442 sinfo.wShowWindow = SW_HIDE; /* Hidden! */
443 sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
444 sinfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
445 sinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
446 sa.nLength = sizeof(sa);
447 sa.lpSecurityDescriptor = NULL;
448 sa.bInheritHandle = /*TRUE*/ FALSE;
449 if(!CreateProcess(
450 NULL,
451 cmdbuf,
452 &sa,
453 NULL,
454 /*TRUE*/ FALSE,
455 0 | CREATE_NEW_CONSOLE,
456 NULL,
457 NULL,
458 &sinfo,
459 &pinfo))
460 ret = 0;
461 else
462 ret = (unsigned long) pinfo.hProcess;
463 #endif
464 free(cmdbuf);
465 return ret;
466 }
467 /* NOTREACHED */
468 }
469 #else /* Unix */
470
471 /* call this from the child process to start an erlang system. This
472 * function just builds the erlang command line and then calls it.
473 *
474 * node - the nodename for the new node
475 * flags - various options that can be set (see erl_start.h)
476 * erl - name of the erlang executable, or NULL for default ("erl")
477 * args - additional arguments to pass to erlang executable
478 * port - the port number where we wait for acknowledgment from the enode
479 *
480 * we have a potential problem if args conflicts with any of the
481 * arguments we use here.
482 */
exec_erlang(ei_cnode * ec,char * alive,Erl_IpAddr adr,int flags,char * erl,char * args[],int port)483 static int exec_erlang(ei_cnode *ec,
484 char *alive,
485 Erl_IpAddr adr,
486 int flags,
487 char *erl,
488 char *args[],
489 int port)
490 {
491 #if !defined(__WIN32__) && !defined(VXWORKS)
492 int fd,len,l,i;
493 char **s;
494 char *argv[4];
495 char argbuf[BUFSIZ];
496 struct in_addr myaddr;
497 struct in_addr *hisaddr = (struct in_addr *)adr;
498
499 if (!get_addr(ei_thishostname(ec), &myaddr)) {
500 fprintf(stderr,"erl_call: failed to find hostname\r\n");
501 return ERL_SYS_ERROR;
502 }
503
504 /* on this host? */
505 /* compare ip addresses, unless forced by flag setting to use rsh */
506 if ((flags & ERL_START_REMOTE) || (hisaddr->s_addr != myaddr.s_addr)) {
507 argv[0] = RSH;
508 len = strlen(inet_ntoa(*hisaddr));
509 argv[1] = malloc(len+1);
510 strcpy(argv[1],inet_ntoa(*hisaddr));
511 }
512 else {
513 /* Yes - use sh to start local Erlang */
514 argv[0] = "sh";
515 argv[1] = "-c";
516 }
517 argv[2] = argbuf;
518 argv[3] = NULL;
519
520 len = 0;
521 *argbuf=(char)0;
522
523 sprintf(argbuf,"exec %s ", (erl? erl: "erl"));
524 len = strlen(argbuf);
525
526 /* *must* be noinput or node (seems to) hang... */
527 /* long or short names? */
528 sprintf(&argbuf[len], "-noinput %s %s ",
529 ((flags & ERL_START_LONG) ? "-name" : "-sname"),
530 alive);
531 len = strlen(argbuf);
532
533 /* now make the new node report back when it's ready */
534 /* add: myip, myport and replymsg */
535 sprintf(&argbuf[len],
536 "-s erl_reply reply %s %d %d ",
537 inet_ntoa(myaddr),port,(int)getpid());
538 #ifdef DEBUG
539 fprintf(stderr,"erl_call: debug %s\n",&argbuf[len]);
540 #endif
541 len = strlen(argbuf);
542
543 /* additional arguments to be passed to the other system */
544 /* make sure that they will fit first */
545 for (l=0, s = args; s && *s; s++) l+= strlen(*s) + 1;
546
547 if (len + l + 1 > BUFSIZ) return ERL_BADARG;
548 else {
549 for (s = args; s && *s; s++) {
550 strcat(argbuf," ");
551 strcat(argbuf,*s);
552 }
553 len += l + 1;
554 }
555
556 if (flags & ERL_START_VERBOSE) {
557 fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
558 }
559
560 /* close all descriptors in child */
561 for (i=0; i<64; i++) close(i);
562
563 /* debug output to file? */
564 if (flags & ERL_START_DEBUG) {
565 char debugfile[MAXPATHLEN+1];
566 char *home=getenv("HOME");
567 sprintf(debugfile,"%s/%s.%s",home,ERL_START_LOGFILE,alive);
568 if ((fd=open(debugfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) >= 0) {
569 time_t t = time(NULL);
570 dup2(fd,1);
571 dup2(fd,2);
572 fprintf(stderr,"\n\n===== Log started ======\n%s \n",ctime(&t));
573 fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
574 }
575 }
576
577 /* start the system */
578 execvp(argv[0], argv);
579
580 if (flags & ERL_START_DEBUG) {
581 fprintf(stderr,"erl_call: exec failed: (%d) %s %s %s\n",
582 errno,argv[0],argv[1],argv[2]);
583 }
584
585 #endif
586 /* (hopefully) NOT REACHED */
587 return ERL_SYS_ERROR;
588 } /* exec_erlang() */
589
590 #endif /* defined(VXWORKS) || defined(WINDOWS) */
591
592 #if defined(__WIN32__)
gettimeofday(struct timeval * now,void * dummy)593 static void gettimeofday(struct timeval *now,void *dummy){
594 SYSTEMTIME systime;
595 FILETIME ft;
596 DWORD x;
597 GetSystemTime(&systime);
598 SystemTimeToFileTime(&systime,&ft);
599 x = ft.dwLowDateTime / 10;
600 now->tv_sec = x / 1000000;
601 now->tv_usec = x % 1000000;
602 }
603
604 #elif defined(VXWORKS)
gettimeofday(struct timeval * now,void * dummy)605 static void gettimeofday(struct timeval *now, void *dummy){
606 int rate = sysClkRateGet(); /* Ticks per second */
607 unsigned long ctick = tickGet();
608 now->tv_sec = ctick / rate; /* secs since reboot */
609 now->tv_usec = ((ctick - (now->tv_sec * rate))*1000000)/rate;
610 }
611 #endif
612
613
614 /* wait for the remote system to reply */
615 /*
616 * sockd - an open socket where we expect a connection from the e-node
617 * magic - sign on message the e-node must provide for verification
618 * timeout - how long to wait before returning failure
619 *
620 * OBS: the socket is blocking, and there is a potential deadlock if we
621 * get an accept but the peer sends no data (and does not close).
622 * in normal cases the timeout will work ok however, i.e. either we
623 * never get any connection, or we get connection then close().
624 */
wait_for_erlang(int sockd,int magic,struct timeval * timeout)625 static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
626 {
627 struct timeval to;
628 struct timeval stop_time;
629 struct timeval now;
630 fd_set rdset;
631 int fd;
632 int n,i;
633 char buf[16];
634 struct sockaddr_in peer;
635 SocklenType len = (SocklenType) sizeof(peer);
636
637 /* determine when we should exit this function */
638 gettimeofday(&now,NULL);
639 stop_time.tv_sec = now.tv_sec + timeout->tv_sec;
640 stop_time.tv_usec = now.tv_usec + timeout->tv_usec;
641 while (stop_time.tv_usec > 1000000) {
642 stop_time.tv_sec++;
643 stop_time.tv_usec -= 1000000;
644 }
645
646 #ifdef DEBUG
647 fprintf(stderr,"erl_call: debug time is %ld.%06ld, "
648 "will timeout at %ld.%06ld\n",
649 now.tv_sec,now.tv_usec,stop_time.tv_sec,stop_time.tv_usec);
650 #endif
651
652 while (1) {
653 FD_ZERO(&rdset);
654 FD_SET(sockd,&rdset);
655
656 /* adjust the timeout to (stoptime - now) */
657 gettimeofday(&now,NULL);
658 to.tv_sec = stop_time.tv_sec - now.tv_sec;
659 to.tv_usec = stop_time.tv_usec - now.tv_usec;
660 while ((to.tv_usec < 0) && (to.tv_sec > 0)) {
661 to.tv_usec += 1000000;
662 to.tv_sec--;
663 }
664 if (to.tv_sec < 0) return ERL_TIMEOUT;
665
666 #ifdef DEBUG
667 fprintf(stderr,"erl_call: debug remaining to timeout: %ld.%06ld\n",
668 to.tv_sec,to.tv_usec);
669 #endif
670 switch ((i = select(sockd+1,&rdset,NULL,NULL,&to))) {
671 case -1:
672 return ERL_SYS_ERROR;
673 break;
674
675 case 0: /* timeout */
676 #ifdef DEBUG
677 gettimeofday(&now,NULL);
678 fprintf(stderr,"erl_call: debug timed out at %ld.%06ld\n",
679 now.tv_sec,now.tv_usec);
680 #endif
681 return ERL_TIMEOUT;
682 break;
683
684 default: /* ready descriptors */
685 #ifdef DEBUG
686 gettimeofday(&now,NULL);
687 fprintf(stderr,"erl_call: debug got select at %ld.%06ld\n",
688 now.tv_sec,now.tv_usec);
689 #endif
690 if (FD_ISSET(sockd,&rdset)) {
691 if ((fd = accept(sockd,(struct sockaddr *)&peer,&len)) < 0)
692 return ERL_SYS_ERROR;
693
694 /* now get sign-on message and terminate it */
695 #if defined(__WIN32__)
696 if ((n=recv(fd,buf,16,0)) >= 0) buf[n]=0x0;
697 closesocket(fd);
698 #else
699 if ((n=read(fd,buf,16)) >= 0) buf[n]=0x0;
700 close(fd);
701 #endif
702 #ifdef DEBUG
703 fprintf(stderr,"erl_call: debug got %d, expected %d\n",
704 atoi(buf),magic);
705 #endif
706 if (atoi(buf) == magic) return 0; /* success */
707 } /* if FD_SET */
708 } /* switch */
709 } /* while */
710
711 /* unreached? */
712 return ERL_SYS_ERROR;
713 } /* wait_for_erlang() */
714
715
get_addr(const char * hostname,struct in_addr * oaddr)716 static struct in_addr *get_addr(const char *hostname, struct in_addr *oaddr)
717 {
718 struct hostent *hp;
719
720 #if !defined (__WIN32__)
721 char buf[1024];
722 struct hostent host;
723 int herror;
724
725 hp = ei_gethostbyname_r(hostname,&host,buf,1024,&herror);
726 #else
727 hp = ei_gethostbyname(hostname);
728 #endif
729
730 if (hp) {
731 memmove(oaddr,hp->h_addr_list[0],sizeof(*oaddr));
732 return oaddr;
733 }
734 return NULL;
735 }
736