1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2000-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 * Purpose: Connect to any node at any host. (EI version)
22 */
23
24 #include "eidef.h"
25
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29
30 #ifdef __WIN32__
31 #include <winsock2.h>
32 #include <windows.h>
33 #include <winbase.h>
34
35 #else /* some unix */
36 #include <unistd.h>
37 #include <sys/times.h>
38
39 #if TIME_WITH_SYS_TIME
40 # include <sys/time.h>
41 # include <time.h>
42 #else
43 # if HAVE_SYS_TIME_H
44 # include <sys/time.h>
45 # else
46 # include <time.h>
47 # endif
48 #endif
49
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <netinet/tcp.h>
53 #include <arpa/inet.h>
54 #include <netdb.h>
55 #include <sys/utsname.h> /* for gen_challenge (NEED FIX?) */
56 #include <time.h>
57 #endif
58
59 /* common includes */
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <errno.h>
64 #include <ctype.h>
65 #include <stddef.h>
66
67 #include "eiext.h"
68 #include "ei_portio.h"
69 #include "ei_internal.h"
70 #include "ei_connect_int.h"
71 #include "ei_locking.h"
72 #include "eisend.h"
73 #include "eirecv.h"
74 #include "eimd5.h"
75 #include "putget.h"
76 #include "ei_resolve.h"
77 #include "ei_epmd.h"
78 #include "ei_internal.h"
79
80 static int ei_connect_initialized = 0;
81 int ei_tracelevel = 0;
82
83 #define COOKIE_FILE "/.erlang.cookie"
84 #define EI_MAX_HOME_PATH 1024
85
86 #define EI_SOCKET_CALLBACKS_SZ_V1 \
87 (offsetof(ei_socket_callbacks, get_fd) \
88 + sizeof(int (*)(void *)))
89
90 static char *null_cookie = "";
91
92 static int get_cookie(char *buf, int len);
93 static int get_home(char *buf, int size);
94
95 /* forwards */
96 static unsigned gen_challenge(void);
97 static void gen_digest(unsigned challenge, char cookie[],
98 unsigned char digest[16]);
99 static int send_status(ei_socket_callbacks *cbs, void *ctx,
100 int pkt_sz, char *status, unsigned ms);
101 static int recv_status(ei_cnode*, void *ctx,
102 int pkt_sz, unsigned ms);
103 static int send_challenge(ei_cnode *ec, void *ctx, int pkt_sz,
104 unsigned challenge,
105 DistFlags version, unsigned ms);
106 static int recv_challenge(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
107 unsigned *challenge,
108 DistFlags *flags, char *namebuf, unsigned ms);
109 static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
110 int pkt_sz, unsigned char digest[16],
111 unsigned challenge, unsigned ms);
112 static int recv_complement(ei_socket_callbacks *cbs, void *ctx,
113 int pkt_sz, unsigned ms);
114 static int recv_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
115 int pkt_sz, unsigned our_challenge,
116 char cookie[],
117 unsigned *her_challenge, unsigned ms);
118 static int send_challenge_ack(ei_socket_callbacks *cbs, void *ctx,
119 int pkt_sz, unsigned char digest[16],
120 unsigned ms);
121 static int recv_challenge_ack(ei_socket_callbacks *cbs, void *ctx,
122 int pkt_sz, unsigned our_challenge,
123 char cookie[], unsigned ms);
124 static int send_name(ei_cnode *ec, void *ctx, int pkt_sz,
125 unsigned version, unsigned ms);
126 static int send_complement(ei_cnode *ec, void *ctx, int pkt_sz,
127 unsigned epmd_says_version, DistFlags her_flags,
128 unsigned ms);
129 static int recv_name(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
130 char* send_name_tag, DistFlags *flags,
131 char *namebuf, unsigned ms);
132 static int ei_connect_helper(ei_cnode* ec,
133 Erl_IpAddr ip_addr,
134 char *alivename,
135 unsigned ms,
136 int rport,
137 int epmd_says_version);
138
139 static struct hostent*
140 dyn_gethostbyname_r(const char *name, struct hostent *hostp, char **buffer_p,
141 int buflen, int *h_errnop);
142
143 static void abort_connection(ei_socket_callbacks *cbs, void *ctx);
144 static int close_connection(ei_socket_callbacks *cbs, void *ctx, int fd);
145
146 static const char *
estr(int e)147 estr(int e)
148 {
149 const char *str = strerror(e);
150 if (!str)
151 return "unknown error";
152 return str;
153 }
154
155
156 /***************************************************************************
157 *
158 * For each file descriptor returned from ei_connect() we save information
159 * about distribution protocol version, node information for this node
160 * and the cookie.
161 *
162 ***************************************************************************/
163
164 typedef struct ei_socket_info_s {
165 int socket;
166 ei_socket_callbacks *cbs;
167 void *ctx;
168 int dist_version;
169 ei_cnode cnode; /* A copy, not a pointer. We don't know when freed */
170 char cookie[EI_MAX_COOKIE_SIZE+1];
171 } ei_socket_info;
172
173 /***************************************************************************
174 *
175 * XXX
176 *
177 ***************************************************************************/
178
179 #ifndef ETHR_HAVE___atomic_compare_exchange_n
180 # define ETHR_HAVE___atomic_compare_exchange_n 0
181 #endif
182 #ifndef ETHR_HAVE___atomic_load_n
183 # define ETHR_HAVE___atomic_load_n 0
184 #endif
185 #ifndef ETHR_HAVE___atomic_store_n
186 # define ETHR_HAVE___atomic_store_n 0
187 #endif
188
189 #if defined(_REENTRANT) \
190 && (!(ETHR_HAVE___atomic_compare_exchange_n & SIZEOF_VOID_P) \
191 || !(ETHR_HAVE___atomic_load_n & SIZEOF_VOID_P) \
192 || !(ETHR_HAVE___atomic_store_n & SIZEOF_VOID_P))
193 # undef EI_DISABLE_SEQ_SOCKET_INFO
194 # define EI_DISABLE_SEQ_SOCKET_INFO
195 #endif
196
197 #ifdef __WIN32__
198 # undef EI_DISABLE_SEQ_SOCKET_INFO
199 # define EI_DISABLE_SEQ_SOCKET_INFO
200 #endif
201
202 #ifndef EI_DISABLE_SEQ_SOCKET_INFO
203
204 #ifdef _REENTRANT
205
206 #define EI_ATOMIC_CMPXCHG_ACQ_REL(VARP, XCHGP, NEW) \
207 __atomic_compare_exchange_n((VARP), (XCHGP), (NEW), 0, \
208 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)
209 #define EI_ATOMIC_LOAD_ACQ(VARP) \
210 __atomic_load_n((VARP), __ATOMIC_ACQUIRE)
211 #define EI_ATOMIC_STORE_REL(VARP, NEW) \
212 __atomic_store_n((VARP), (NEW), __ATOMIC_RELEASE)
213
214 #else /* ! _REENTRANT */
215
216 #define EI_ATOMIC_CMPXCHG_ACQ_REL(VARP, XCHGP, NEW) \
217 (*(VARP) == *(XCHGP) \
218 ? ((*(VARP) = (NEW)), !0) \
219 : ((*(XCHGP) = *(VARP)), 0))
220 #define EI_ATOMIC_LOAD_ACQ(VARP) (*(VARP))
221 #define EI_ATOMIC_STORE_REL(VARP, NEW) (*(VARP) = (NEW))
222
223 #endif /* ! _REENTRANT */
224
225 #define EI_SOCKET_INFO_SEG_BITS 5
226 #define EI_SOCKET_INFO_SEG_SIZE (1 << EI_SOCKET_INFO_SEG_BITS)
227 #define EI_SOCKET_INFO_SEG_MASK (EI_SOCKET_INFO_SEG_SIZE - 1)
228
229 typedef struct {
230 int max_fds;
231 ei_socket_info *segments[1]; /* Larger in reality... */
232 } ei_socket_info_data__;
233
234 static ei_socket_info_data__ *socket_info_data = NULL;
235
init_socket_info(int late)236 static int init_socket_info(int late)
237 {
238 int max_fds;
239 int i;
240 size_t segments_len;
241 ei_socket_info_data__ *info_data, *xchg;
242
243 if (EI_ATOMIC_LOAD_ACQ(&socket_info_data) != NULL)
244 return 0; /* Already initialized... */
245
246 #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
247 max_fds = sysconf(_SC_OPEN_MAX);
248 #else
249 max_fds = 1024;
250 #endif
251
252 if (max_fds < 0)
253 return EIO;
254
255 segments_len = ((max_fds-1)/EI_SOCKET_INFO_SEG_SIZE + 1);
256
257 info_data = malloc(sizeof(ei_socket_info_data__)
258 + (sizeof(ei_socket_info *)*(segments_len-1)));
259 if (!info_data)
260 return ENOMEM;
261
262 info_data->max_fds = max_fds;
263 for (i = 0; i < segments_len; i++)
264 info_data->segments[i] = NULL;
265
266 xchg = NULL;
267 if (!EI_ATOMIC_CMPXCHG_ACQ_REL(&socket_info_data, &xchg, info_data))
268 free(info_data); /* Already initialized... */
269
270 return 0;
271 }
272
put_ei_socket_info(int fd,int dist_version,char * cookie,ei_cnode * ec,ei_socket_callbacks * cbs,void * ctx)273 static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec,
274 ei_socket_callbacks *cbs, void *ctx)
275 {
276 int six;
277 ei_socket_info *seg, *si;
278 int socket;
279
280 if (fd < 0 || socket_info_data->max_fds <= fd)
281 return -1;
282
283 socket = fd;
284 six = fd >> EI_SOCKET_INFO_SEG_BITS;
285 seg = EI_ATOMIC_LOAD_ACQ(&socket_info_data->segments[six]);
286
287 if (!seg) {
288 ei_socket_info *xchg;
289 int i;
290 seg = malloc(sizeof(ei_socket_info)*EI_SOCKET_INFO_SEG_SIZE);
291 if (!seg)
292 return -1;
293 for (i = 0; i < EI_SOCKET_INFO_SEG_SIZE; i++) {
294 seg[i].socket = -1;
295 }
296
297 xchg = NULL;
298 if (!EI_ATOMIC_CMPXCHG_ACQ_REL(&socket_info_data->segments[six], &xchg, seg)) {
299 free(seg);
300 seg = xchg;
301 }
302 }
303
304 si = &seg[fd & EI_SOCKET_INFO_SEG_MASK];
305
306 if (dist_version < 0) {
307 socket = -1;
308 si->cbs = NULL;
309 si->ctx = NULL;
310 }
311 else {
312 si->dist_version = dist_version;
313 si->cnode = *ec;
314 si->cbs = cbs;
315 si->ctx = ctx;
316 strcpy(si->cookie, cookie);
317 }
318
319 EI_ATOMIC_STORE_REL(&si->socket, socket);
320
321 return 0;
322 }
323
get_ei_socket_info(int fd)324 static ei_socket_info* get_ei_socket_info(int fd)
325 {
326 int six, socket;
327 ei_socket_info *seg, *si;
328
329 if (fd < 0 || socket_info_data->max_fds <= fd)
330 return NULL;
331
332 six = fd >> EI_SOCKET_INFO_SEG_BITS;
333 seg = EI_ATOMIC_LOAD_ACQ(&socket_info_data->segments[six]);
334
335 if (!seg)
336 return NULL;
337
338 si = &seg[fd & EI_SOCKET_INFO_SEG_MASK];
339 socket = EI_ATOMIC_LOAD_ACQ(&si->socket);
340 if (socket != fd)
341 return NULL;
342 return si;
343 }
344
345 #else /* EI_DISABLE_SEQ_SOCKET_INFO */
346
347 int ei_n_sockets = 0, ei_sz_sockets = 0;
348 ei_socket_info *ei_sockets = NULL;
349
350 #ifdef _REENTRANT
351 ei_mutex_t* ei_sockets_lock = NULL;
352 #endif /* _REENTRANT */
353
init_socket_info(int late)354 static int init_socket_info(int late)
355 {
356 #ifdef _REENTRANT
357 if (late)
358 return ENOTSUP; /* Refuse doing unsafe initialization... */
359 ei_sockets_lock = ei_mutex_create();
360 if (!ei_sockets_lock)
361 return ENOMEM;
362 #endif /* _REENTRANT */
363 return 0;
364 }
365
put_ei_socket_info(int fd,int dist_version,char * cookie,ei_cnode * ec,ei_socket_callbacks * cbs,void * ctx)366 static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec,
367 ei_socket_callbacks *cbs, void *ctx)
368 {
369 int i;
370
371 #ifdef _REENTRANT
372 ei_mutex_lock(ei_sockets_lock, 0);
373 #endif /* _REENTRANT */
374 for (i = 0; i < ei_n_sockets; ++i) {
375 if (ei_sockets[i].socket == fd) {
376 if (dist_version == -1) {
377 memmove(&ei_sockets[i], &ei_sockets[i+1],
378 sizeof(ei_sockets[0])*(ei_n_sockets-i-1));
379 } else {
380 ei_sockets[i].dist_version = dist_version;
381 /* Copy the content, see ei_socket_info */
382 ei_sockets[i].cbs = cbs;
383 ei_sockets[i].ctx = ctx;
384 ei_sockets[i].cnode = *ec;
385 strcpy(ei_sockets[i].cookie, cookie);
386 }
387 #ifdef _REENTRANT
388 ei_mutex_unlock(ei_sockets_lock);
389 #endif /* _REENTRANT */
390 return 0;
391 }
392 }
393 if (ei_n_sockets == ei_sz_sockets) {
394 ei_sz_sockets += 5;
395 ei_sockets = realloc(ei_sockets,
396 sizeof(ei_sockets[0])*ei_sz_sockets);
397 if (ei_sockets == NULL) {
398 ei_sz_sockets = ei_n_sockets = 0;
399 #ifdef _REENTRANT
400 ei_mutex_unlock(ei_sockets_lock);
401 #endif /* _REENTRANT */
402 return -1;
403 }
404 }
405 ei_sockets[ei_n_sockets].socket = fd;
406 ei_sockets[ei_n_sockets].dist_version = dist_version;
407 ei_sockets[ei_n_sockets].cnode = *ec;
408 ei_sockets[ei_n_sockets].cbs = cbs;
409 ei_sockets[ei_n_sockets].ctx = ctx;
410 strcpy(ei_sockets[ei_n_sockets].cookie, cookie);
411 ++ei_n_sockets;
412 #ifdef _REENTRANT
413 ei_mutex_unlock(ei_sockets_lock);
414 #endif /* _REENTRANT */
415 return 0;
416 }
417
get_ei_socket_info(int fd)418 static ei_socket_info* get_ei_socket_info(int fd)
419 {
420 int i;
421 #ifdef _REENTRANT
422 ei_mutex_lock(ei_sockets_lock, 0);
423 #endif /* _REENTRANT */
424 for (i = 0; i < ei_n_sockets; ++i)
425 if (ei_sockets[i].socket == fd) {
426 /*fprintf("get_ei_socket_info %d %d \"%s\"\n",
427 fd, ei_sockets[i].dist_version, ei_sockets[i].cookie);*/
428 #ifdef _REENTRANT
429 ei_mutex_unlock(ei_sockets_lock);
430 #endif /* _REENTRANT */
431 return &ei_sockets[i];
432 }
433 #ifdef _REENTRANT
434 ei_mutex_unlock(ei_sockets_lock);
435 #endif /* _REENTRANT */
436 return NULL;
437 }
438
439 #endif /* EI_DISABLE_SEQ_SOCKET_INFO */
440
remove_ei_socket_info(int fd)441 static int remove_ei_socket_info(int fd)
442 {
443 return put_ei_socket_info(fd, -1, null_cookie, NULL, NULL, NULL);
444 }
445
ei_fd_to_cnode(int fd)446 ei_cnode *ei_fd_to_cnode(int fd)
447 {
448 ei_socket_info *sockinfo = get_ei_socket_info(fd);
449 if (sockinfo == NULL) return NULL;
450 return &sockinfo->cnode;
451 }
452
ei_get_cbs_ctx__(ei_socket_callbacks ** cbs,void ** ctx,int fd)453 int ei_get_cbs_ctx__(ei_socket_callbacks **cbs, void **ctx, int fd)
454 {
455 ei_socket_info *sockinfo = get_ei_socket_info(fd);
456 if (sockinfo) {
457 *cbs = sockinfo->cbs;
458 *ctx = sockinfo->ctx;
459 return 0;
460 }
461
462 *cbs = NULL;
463 *ctx = NULL;
464 return EBADF;
465 }
466
467 /***************************************************************************
468 * Get/Set tracelevel
469 ***************************************************************************/
470
ei_set_tracelevel(int level)471 void ei_set_tracelevel(int level) {
472 ei_tracelevel = level;
473 }
474
ei_get_tracelevel(void)475 int ei_get_tracelevel(void) {
476 return ei_tracelevel;
477 }
478
479
480 /***************************************************************************
481 * Distversion
482 ***************************************************************************/
483
ei_distversion(int fd)484 int ei_distversion(int fd)
485 {
486 ei_socket_info* e = get_ei_socket_info(fd);
487 if (e == NULL)
488 return -1;
489 else
490 return e->dist_version;
491 }
492
ei_cookie(int fd)493 static const char* ei_cookie(int fd)
494 {
495 ei_socket_info* e = get_ei_socket_info(fd);
496 if (e == NULL)
497 return NULL;
498 else
499 return e->cookie;
500 }
501
ei_thisnodename(const ei_cnode * ec)502 const char *ei_thisnodename(const ei_cnode* ec)
503 {
504 return ec->thisnodename;
505 }
506
ei_thishostname(const ei_cnode * ec)507 const char *ei_thishostname(const ei_cnode* ec)
508 {
509 return ec->thishostname;
510 }
511
ei_thisalivename(const ei_cnode * ec)512 const char *ei_thisalivename(const ei_cnode* ec)
513 {
514 return ec->thisalivename;
515 }
516
ei_thiscreation(const ei_cnode * ec)517 short ei_thiscreation(const ei_cnode* ec)
518 {
519 return ec->creation;
520 }
521
522 /* FIXME: this function is not an api, why not? */
ei_thiscookie(const ei_cnode * ec)523 const char *ei_thiscookie(const ei_cnode* ec)
524 {
525 return (const char *)ec->ei_connect_cookie;
526 }
527
528 static int
check_initialized_node(ei_cnode * ec)529 check_initialized_node(ei_cnode *ec)
530 {
531 /*
532 * Try to guard against returning garbage pids and refs
533 * by verifying that the node has got its name...
534 */
535 int i, at, end;
536 char *nodename = &ec->thisnodename[0];
537
538 for (i = at = end = 0; i < sizeof(ec->thisnodename); i++) {
539 if (!nodename[i]) {
540 end = !0;
541 break;
542 }
543 if (nodename[i] == '@')
544 at = !0;
545 }
546
547 if (!at || !end) {
548 erl_errno = EINVAL;
549 return ERL_ERROR;
550 }
551
552 return 0;
553 }
554
ei_self(ei_cnode * ec)555 erlang_pid *ei_self(ei_cnode* ec)
556 {
557 int err = check_initialized_node(ec);
558 if (err)
559 return NULL;
560 return &ec->self;
561 }
562
563 /*
564 * ei_make_pid()
565 */
566
567 #undef EI_MAKE_PID_ATOMIC__
568 #ifdef _REENTRANT
569 # if (SIZEOF_INT == 4 \
570 && (ETHR_HAVE___atomic_compare_exchange_n & 4) \
571 && (ETHR_HAVE___atomic_load_n & 4))
572 # define EI_MAKE_PID_ATOMIC__
573 # else /* !EI_MAKE_PID_ATOMIC__ */
574 static ei_mutex_t *pid_mtx = NULL;
575 # endif /* !EI_MAKE_PID_ATOMIC__ */
576 #endif /* _REENTRANT */
577
578 static int
init_make_pid(int late)579 init_make_pid(int late)
580 {
581 #if defined(_REENTRANT) && !defined(EI_MAKE_PID_ATOMIC__)
582
583 if (late)
584 return ENOTSUP; /* Refuse doing unsafe initialization... */
585
586 pid_mtx = ei_mutex_create();
587 if (!pid_mtx)
588 return ENOMEM;
589
590 #endif /* _REENTRANT */
591
592 return 0;
593 }
594
ei_make_pid(ei_cnode * ec,erlang_pid * pid)595 int ei_make_pid(ei_cnode *ec, erlang_pid *pid)
596 {
597 unsigned int new;
598 int err;
599
600 if (!ei_connect_initialized) {
601 fprintf(stderr,"<ERROR> erl_interface not initialized\n");
602 exit(1);
603 }
604
605 err = check_initialized_node(ec);
606 if (err) {
607 /*
608 * write invalid utf8 in nodename which will make
609 * ei_encode_pid() fail if used...
610 */
611 pid->node[0] = 0xff;
612 pid->node[1] = 0;
613 pid->serial = -1;
614 pid->num = -1;
615 return err;
616 }
617
618 strcpy(pid->node, ec->thisnodename);
619 pid->creation = ec->creation;
620
621 /*
622 * We avoid creating pids with serial set to 0 since the
623 * documentation previously gave some really bad advise
624 * of modifying the 'num' field in the pid returned by
625 * ei_self(). Since 'serial' field in pid returned by
626 * ei_self() is initialized to 0, pids created by
627 * ei_make_pid() wont clash with such badly created pids
628 * using ei_self() unless user also modified serial, but
629 * that has at least never been suggested by the
630 * documentation.
631 */
632
633 #ifdef EI_MAKE_PID_ATOMIC__
634 {
635 unsigned int xchg = __atomic_load_n(&ec->pidsn, __ATOMIC_RELAXED);
636 do {
637 new = xchg + 1;
638 if ((new & 0x0fff8000) == 0)
639 new = 0x8000; /* serial==0 -> serial=1 num=0 */
640 } while(!__atomic_compare_exchange_n(&ec->pidsn, &xchg, new, 0,
641 __ATOMIC_ACQ_REL,
642 __ATOMIC_RELAXED));
643 }
644 #else /* !EI_MAKE_PID_ATOMIC__ */
645
646 #ifdef _REENTRANT
647 ei_mutex_lock(pid_mtx, 0);
648 #endif
649
650 new = ec->pidsn + 1;
651 if ((new & 0x0fff8000) == 0)
652 new = 0x8000; /* serial==0 -> serial=1 num=0 */
653
654 ec->pidsn = new;
655
656 #ifdef _REENTRANT
657 ei_mutex_unlock(pid_mtx);
658 #endif
659
660 #endif /* !EI_MAKE_PID_ATOMIC__ */
661
662 pid->num = new & 0x7fff; /* 15-bits */
663 pid->serial = (new >> 15) & 0x1fff; /* 13-bits */
664
665 return 0;
666 }
667
668 /*
669 * ei_make_ref()
670 */
671
672 #undef EI_MAKE_REF_ATOMIC__
673 #ifdef _REENTRANT
674 # if ((SIZEOF_LONG == 8 || SIZEOF_LONGLONG == 8) \
675 && (ETHR_HAVE___atomic_compare_exchange_n & 8) \
676 && (ETHR_HAVE___atomic_load_n & 8))
677 # define EI_MAKE_REF_ATOMIC__
678 # if SIZEOF_LONG == 8
679 typedef unsigned long ei_atomic_ref__;
680 # else
681 typedef unsigned long long ei_atomic_ref__;
682 # endif
683 # else /* !EI_MAKE_REF_ATOMIC__ */
684 static ei_mutex_t *ref_mtx = NULL;
685 # endif /* !EI_MAKE_REF_ATOMIC__ */
686 #endif /* _REENTRANT */
687
688 /*
689 * We use a global counter for all c-nodes in this process.
690 * We wont wrap anyway due to the enormous amount of values
691 * available.
692 */
693 #ifdef EI_MAKE_REF_ATOMIC__
694 static ei_atomic_ref__ ref_count;
695 #else
696 static unsigned int ref_count[3];
697 #endif
698
699 static int
init_make_ref(int late)700 init_make_ref(int late)
701 {
702
703 #ifdef EI_MAKE_REF_ATOMIC__
704 ref_count = 0;
705 #else /* !EI_MAKE_REF_ATOMIC__ */
706
707 #ifdef _REENTRANT
708
709 if (late)
710 return ENOTSUP; /* Refuse doing unsafe initialization... */
711
712 ref_mtx = ei_mutex_create();
713 if (!ref_mtx)
714 return ENOMEM;
715
716 #endif /* _REENTRANT */
717
718 ref_count[0] = 0;
719 ref_count[1] = 0;
720 ref_count[2] = 0;
721
722 #endif /* !EI_MAKE_REF_ATOMIC__ */
723
724 return 0;
725 }
726
ei_make_ref(ei_cnode * ec,erlang_ref * ref)727 int ei_make_ref(ei_cnode *ec, erlang_ref *ref)
728 {
729 int err;
730 if (!ei_connect_initialized) {
731 fprintf(stderr,"<ERROR> erl_interface not initialized\n");
732 exit(1);
733 }
734
735 err = check_initialized_node(ec);
736 if (err) {
737 /*
738 * write invalid utf8 in nodename which will make
739 * ei_encode_ref() fail if used...
740 */
741 ref->node[0] = 0xff;
742 ref->node[1] = 0;
743 ref->len = -1;
744 return err;
745 }
746
747 strcpy(ref->node, ec->thisnodename);
748 ref->creation = ec->creation;
749 ref->len = 3;
750
751 #ifdef EI_MAKE_REF_ATOMIC__
752 {
753 ei_atomic_ref__ xchg, new;
754 xchg = __atomic_load_n(&ref_count, __ATOMIC_RELAXED);
755 do {
756 new = xchg + 1;
757 } while(!__atomic_compare_exchange_n(&ref_count, &xchg, new, 0,
758 __ATOMIC_ACQ_REL,
759 __ATOMIC_RELAXED));
760 ref->n[0] = (unsigned int) (new & 0x3ffff);
761 ref->n[1] = (unsigned int) ((new >> 18) & 0xffffffff);
762 ref->n[2] = (unsigned int) ((new >> (18+32)) & 0xffffffff);
763 }
764 #else /* !EI_MAKE_REF_ATOMIC__ */
765
766 #ifdef _REENTRANT
767 ei_mutex_lock(ref_mtx, 0);
768 #endif
769
770 ref->n[0] = ref_count[0];
771 ref->n[1] = ref_count[1];
772 ref->n[2] = ref_count[2];
773 ref->n[3] = 0;
774 ref->n[4] = 0;
775
776 ref_count[0]++;
777 ref_count[0] &= 0x3ffff;
778 if (ref_count[0] == 0) {
779 ref_count[1]++;
780 ref_count[1] &= 0xffffffff;
781 if (ref_count[1] == 0) {
782 ref_count[2]++;
783 ref_count[2] &= 0xffffffff;
784 }
785 }
786
787 #ifdef _REENTRANT
788 ei_mutex_unlock(ref_mtx);
789 #endif
790
791 #endif /* !EI_MAKE_REF_ATOMIC__ */
792
793 return 0;
794 }
795
796 /* two internal functions that will let us support different cookies
797 * (to be able to connect to other nodes that don't have the same
798 * cookie as each other or us)
799 */
ei_getfdcookie(int fd)800 const char *ei_getfdcookie(int fd)
801 {
802 const char* r = ei_cookie(fd);
803 if (r == NULL) r = "";
804 return r;
805 }
806
get_int32(unsigned char * s)807 static int get_int32(unsigned char *s)
808 {
809 return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] ));
810 }
811
812
813 #ifdef __WIN32__
win32_error(char * buf,int buflen)814 void win32_error(char *buf, int buflen)
815 {
816 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
817 0, /* n/a */
818 WSAGetLastError(), /* error code */
819 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* language */
820 buf,
821 buflen,
822 NULL);
823 return;
824 }
825
initWinSock(void)826 static int initWinSock(void)
827 {
828 WORD wVersionRequested;
829 WSADATA wsaData;
830 int i;
831
832 static LONG volatile initialized = 0;
833
834 wVersionRequested = MAKEWORD(1, 1);
835 if (InterlockedCompareExchange((LPLONG) &initialized,1L,0L) == 0L) {
836 /* FIXME not terminate, just a message?! */
837 if ((i = WSAStartup(wVersionRequested, &wsaData))) {
838 EI_TRACE_ERR1("ei_connect_init",
839 "ERROR: can't initialize windows sockets: %d",i);
840 initialized = 2L;
841 return 0;
842 }
843
844 if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
845 EI_TRACE_ERR0("initWinSock","ERROR: this version of windows "
846 "sockets not supported");
847 WSACleanup();
848 initialized = 2L;
849 return 0;
850 }
851 initialized = 3L;
852 } else while (initialized < 2) {
853 SwitchToThread();
854 }
855 return (int) (initialized - 2);
856 }
857 #endif
858
init_connect(int late)859 static int init_connect(int late)
860 {
861 int error;
862
863 /*
864 * 'late' is non-zero when not called via ei_init(). Such a
865 * call is not supported, but we for now save the day if
866 * it easy to do so; otherwise, return ENOTSUP.
867 */
868
869 #ifdef __WIN32__
870 if (!initWinSock()) {
871 EI_TRACE_ERR0("ei_init_connect","can't initiate winsock");
872 return EIO;
873 }
874 #endif /* win32 */
875
876 error = init_socket_info(late);
877 if (error) {
878 EI_TRACE_ERR0("ei_init_connect","can't initiate socket info");
879 return error;
880 }
881
882 error = init_make_ref(late);
883 if (error) {
884 EI_TRACE_ERR0("ei_init_connect","can't initiate ei_make_ref()");
885 return error;
886 }
887
888 error = init_make_pid(late);
889 if (error) {
890 EI_TRACE_ERR0("ei_init_connect","can't initiate ei_make_pid()");
891 return error;
892 }
893
894 ei_connect_initialized = !0;
895 return 0;
896 }
897
ei_init_connect(void)898 int ei_init_connect(void)
899 {
900 return init_connect(0);
901 }
902
903 /*
904 * Perhaps run this routine instead of ei_connect_init/2 ?
905 * Initailize by setting:
906 * thishostname, thisalivename, thisnodename and thisipaddr
907 */
ei_connect_xinit_ussi(ei_cnode * ec,const char * thishostname,const char * thisalivename,const char * thisnodename,Erl_IpAddr thisipaddr,const char * cookie,const short creation,ei_socket_callbacks * cbs,int cbs_sz,void * setup_context)908 int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname,
909 const char *thisalivename, const char *thisnodename,
910 Erl_IpAddr thisipaddr, const char *cookie,
911 const short creation, ei_socket_callbacks *cbs,
912 int cbs_sz, void *setup_context)
913 {
914 char *dbglevel;
915
916 if (!ei_connect_initialized)
917 init_connect(!0);
918
919 if (cbs != &ei_default_socket_callbacks)
920 EI_SET_HAVE_PLUGIN_SOCKET_IMPL__;
921
922 if (cbs_sz < EI_SOCKET_CALLBACKS_SZ_V1) {
923 EI_TRACE_ERR0("ei_connect_xinit","invalid size of ei_socket_callbacks struct");
924 return ERL_ERROR;
925 }
926
927 ec->creation = creation;
928 ec->pidsn = 0;
929
930 if (cookie) {
931 if (strlen(cookie) >= sizeof(ec->ei_connect_cookie)) {
932 EI_TRACE_ERR0("ei_connect_xinit",
933 "ERROR: Cookie size too large");
934 return ERL_ERROR;
935 } else {
936 strcpy(ec->ei_connect_cookie, cookie);
937 }
938 } else if (!get_cookie(ec->ei_connect_cookie, sizeof(ec->ei_connect_cookie))) {
939 return ERL_ERROR;
940 }
941
942 if (strlen(thishostname) >= sizeof(ec->thishostname)) {
943 EI_TRACE_ERR0("ei_connect_xinit","ERROR: Thishostname too long");
944 return ERL_ERROR;
945 }
946 strcpy(ec->thishostname, thishostname);
947
948 if (thisalivename) {
949 if (strlen(thisalivename) >= sizeof(ec->thisalivename)) {
950 EI_TRACE_ERR0("ei_connect_init","Thisalivename too long");
951 return ERL_ERROR;
952 }
953
954 strcpy(ec->thisalivename, thisalivename);
955
956 if (strlen(thisnodename) >= sizeof(ec->thisnodename)) {
957 EI_TRACE_ERR0("ei_connect_init","Thisnodename too long");
958 return ERL_ERROR;
959 }
960 strcpy(ec->thisnodename, thisnodename);
961
962 strcpy(ec->self.node, thisnodename);
963 ec->self.num = 0;
964 ec->self.serial = 0;
965 ec->self.creation = creation;
966 }
967 else {
968 /* dynamic name */
969 ec->thisalivename[0] = 0;
970 ec->thisnodename[0] = 0;
971 }
972
973 /* FIXME right now this_ipaddr is never used */
974 /* memmove(&ec->this_ipaddr, thisipaddr, sizeof(ec->this_ipaddr)); */
975
976
977 ec->cbs = cbs;
978 ec->setup_context = setup_context;
979
980 if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL ||
981 (dbglevel = getenv("ERL_DEBUG_DIST")) != NULL)
982 ei_tracelevel = atoi(dbglevel);
983
984 return 0;
985 }
986
ei_connect_xinit(ei_cnode * ec,const char * thishostname,const char * thisalivename,const char * thisnodename,Erl_IpAddr thisipaddr,const char * cookie,const short creation)987 int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
988 const char *thisalivename, const char *thisnodename,
989 Erl_IpAddr thisipaddr, const char *cookie,
990 const short creation)
991 {
992 return ei_connect_xinit_ussi(ec, thishostname, thisalivename, thisnodename,
993 thisipaddr, cookie, creation,
994 &ei_default_socket_callbacks,
995 sizeof(ei_default_socket_callbacks),
996 NULL);
997 }
998
999 /*
1000 * Initialize by set: thishostname, thisalivename,
1001 * thisnodename and thisipaddr. At success return 0,
1002 * otherwise return -1.
1003 */
ei_connect_init_ussi(ei_cnode * ec,const char * this_node_name,const char * cookie,short creation,ei_socket_callbacks * cbs,int cbs_sz,void * setup_context)1004 int ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name,
1005 const char *cookie, short creation,
1006 ei_socket_callbacks *cbs, int cbs_sz,
1007 void *setup_context)
1008 {
1009 char thishostname[EI_MAXHOSTNAMELEN+1];
1010 char thisnodename[MAXNODELEN+1];
1011 char thisalivename[EI_MAXALIVELEN+1];
1012 struct hostent host, *hp;
1013 char buffer[1024];
1014 char *buf = buffer;
1015 int ei_h_errno;
1016 int res;
1017
1018 if (!ei_connect_initialized)
1019 init_connect(!0);
1020
1021 /* gethostname requires len to be max(hostname) + 1 */
1022 if (gethostname(thishostname, EI_MAXHOSTNAMELEN+1) == -1) {
1023 #ifdef __WIN32__
1024 EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d",
1025 WSAGetLastError());
1026 #else
1027 EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d", errno);
1028 #endif /* win32 */
1029 return ERL_ERROR;
1030 }
1031
1032 if (strlen(this_node_name) >= sizeof(thisalivename)) {
1033 EI_TRACE_ERR0("ei_connect_init","ERROR: this_node_name too long");
1034 return ERL_ERROR;
1035 } else {
1036 strcpy(thisalivename, this_node_name);
1037 }
1038
1039 hp = dyn_gethostbyname_r(thishostname,&host,&buf,sizeof(buffer),&ei_h_errno);
1040 if (hp == NULL) {
1041 /* Looking up IP given hostname fails. We must be on a standalone
1042 host so let's use loopback for communication instead. */
1043 hp = dyn_gethostbyname_r("localhost", &host, &buf, sizeof(buffer),
1044 &ei_h_errno);
1045 if (hp == NULL) {
1046 #ifdef __WIN32__
1047 char reason[1024];
1048
1049 win32_error(reason,sizeof(reason));
1050 EI_TRACE_ERR2("ei_connect_init",
1051 "Can't get ip address for host %s: %s",
1052 thishostname, reason);
1053 #else
1054 EI_TRACE_ERR2("ei_connect_init",
1055 "Can't get ip address for host %s: %d",
1056 thishostname, h_errno);
1057 #endif /* win32 */
1058 return ERL_ERROR;
1059 }
1060 }
1061 {
1062 char* ct;
1063 if (strcmp(hp->h_name, "localhost") == 0) {
1064 /* We use a short node name */
1065 if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
1066 } else {
1067 /* We use a short node name */
1068 if ((ct = strchr(hp->h_name, '.')) != NULL) *ct = '\0';
1069 strcpy(thishostname, hp->h_name);
1070 }
1071 }
1072 if (strlen(this_node_name) + 1 + strlen(thishostname) > MAXNODELEN) {
1073 EI_TRACE_ERR0("ei_connect_init_ussi","this node name is too long");
1074 return ERL_ERROR;
1075 }
1076 sprintf(thisnodename, "%s@%s", this_node_name, thishostname);
1077 res = ei_connect_xinit_ussi(ec, thishostname, thisalivename, thisnodename,
1078 (struct in_addr *)*hp->h_addr_list, cookie, creation,
1079 cbs, cbs_sz, setup_context);
1080 if (buf != buffer)
1081 free(buf);
1082 return res;
1083 }
1084
ei_connect_init(ei_cnode * ec,const char * this_node_name,const char * cookie,short creation)1085 int ei_connect_init(ei_cnode* ec, const char* this_node_name,
1086 const char *cookie, short creation)
1087 {
1088 return ei_connect_init_ussi(ec, this_node_name, cookie, creation,
1089 &ei_default_socket_callbacks,
1090 sizeof(ei_default_socket_callbacks),
1091 NULL);
1092 }
1093
1094 /*
1095 * Same as ei_gethostbyname_r, but also handles ERANGE error
1096 * and may allocate larger buffer with malloc.
1097 */
1098 static
dyn_gethostbyname_r(const char * name,struct hostent * hostp,char ** buffer_p,int buflen,int * h_errnop)1099 struct hostent *dyn_gethostbyname_r(const char *name,
1100 struct hostent *hostp,
1101 char **buffer_p,
1102 int buflen,
1103 int *h_errnop)
1104 {
1105 #ifdef __WIN32__
1106 /*
1107 * Apparently ei_gethostbyname_r not implemented for Windows (?)
1108 * Fall back on ei_gethostbyname like before.
1109 */
1110 return ei_gethostbyname(name);
1111 #else
1112 char* buf = *buffer_p;
1113 struct hostent *hp;
1114
1115 while (1) {
1116 hp = ei_gethostbyname_r(name, hostp, buf, buflen, h_errnop);
1117 if (hp) {
1118 *buffer_p = buf;
1119 break;
1120 }
1121
1122 if (*h_errnop != ERANGE) {
1123 if (buf != *buffer_p)
1124 free(buf);
1125 break;
1126 }
1127
1128 buflen *= 2;
1129 if (buf == *buffer_p)
1130 buf = malloc(buflen);
1131 else {
1132 char* buf2 = realloc(buf, buflen);
1133 if (buf2)
1134 buf = buf2;
1135 else {
1136 free(buf);
1137 buf = NULL;
1138 }
1139 }
1140 if (!buf) {
1141 *h_errnop = ENOMEM;
1142 break;
1143 }
1144 }
1145 return hp;
1146 #endif
1147 }
1148
1149 /* Finds the the IP address for hostname and saves that IP address at
1150 the location that ip_wb points to. Returns a negative error code if
1151 the IP address cannot be found for the hostname. */
ip_address_from_hostname(char * hostname,char ** buffer_p,size_t buffer_size,Erl_IpAddr * ip_wb)1152 static int ip_address_from_hostname(char* hostname,
1153 char** buffer_p,
1154 size_t buffer_size,
1155 Erl_IpAddr* ip_wb)
1156 {
1157 struct hostent *hp;
1158 #ifndef __WIN32__
1159 /* these are needed for the call to gethostbyname_r */
1160 struct hostent host;
1161 int ei_h_errno;
1162 hp = dyn_gethostbyname_r(hostname,&host,buffer_p,buffer_size,&ei_h_errno);
1163 if (hp == NULL) {
1164 char thishostname[EI_MAXHOSTNAMELEN+1];
1165 /* gethostname requies len to be max(hostname) + 1*/
1166 if (gethostname(thishostname,EI_MAXHOSTNAMELEN+1) < 0) {
1167 EI_TRACE_ERR0("ip_address_from_hostname",
1168 "Failed to get name of this host");
1169 erl_errno = EHOSTUNREACH;
1170 return ERL_ERROR;
1171 } else {
1172 char *ct;
1173 /* We use a short node name */
1174 if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
1175 }
1176 if (strcmp(hostname,thishostname) == 0)
1177 /* Both nodes on same standalone host, use loopback */
1178 hp = dyn_gethostbyname_r("localhost",&host,buffer_p,buffer_size,&ei_h_errno);
1179 if (hp == NULL) {
1180 EI_TRACE_ERR2("ei_connect",
1181 "Can't find host for %s: %d\n",hostname,ei_h_errno);
1182 erl_errno = EHOSTUNREACH;
1183 return ERL_ERROR;
1184 }
1185 }
1186 *ip_wb = (Erl_IpAddr) *hp->h_addr_list;
1187 #else /* __WIN32__ */
1188 if ((hp = ei_gethostbyname(hostname)) == NULL) {
1189 char thishostname[EI_MAXHOSTNAMELEN+1];
1190 /* gethostname requires len to be max(hostname) + 1 */
1191 if (gethostname(thishostname,EI_MAXHOSTNAMELEN+1) < 0) {
1192 EI_TRACE_ERR1("ip_address_from_hostname",
1193 "Failed to get name of this host: %d",
1194 WSAGetLastError());
1195 erl_errno = EHOSTUNREACH;
1196 return ERL_ERROR;
1197 } else {
1198 char *ct;
1199 /* We use a short node name */
1200 if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
1201 }
1202 if (strcmp(hostname,thishostname) == 0)
1203 /* Both nodes on same standalone host, use loopback */
1204 hp = ei_gethostbyname("localhost");
1205 if (hp == NULL) {
1206 char reason[1024];
1207 win32_error(reason,sizeof(reason));
1208 EI_TRACE_ERR2("ei_connect",
1209 "Can't find host for %s: %s",hostname,reason);
1210 erl_errno = EHOSTUNREACH;
1211 return ERL_ERROR;
1212 }
1213 }
1214 *ip_wb = (Erl_IpAddr) *hp->h_addr_list;
1215 #endif /* win32 */
1216 return 0;
1217 }
1218
1219 /* Helper function for ei_connect family of functions */
ei_connect_helper(ei_cnode * ec,Erl_IpAddr ip_addr,char * alivename,unsigned ms,int rport,int epmd_says_version)1220 static int ei_connect_helper(ei_cnode* ec,
1221 Erl_IpAddr ip_addr, /* network byte order */
1222 char *alivename,
1223 unsigned ms,
1224 int rport,
1225 int epmd_says_version)
1226 {
1227 ei_socket_callbacks *cbs = ec->cbs;
1228 void *ctx;
1229 int sockd;
1230 unsigned her_version;
1231 DistFlags her_flags;
1232 unsigned our_challenge, her_challenge;
1233 unsigned char our_digest[16];
1234 int err;
1235 int pkt_sz;
1236 struct sockaddr_in addr;
1237 unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
1238
1239 erl_errno = EIO; /* Default error code */
1240
1241 if (alivename != NULL) {
1242 EI_TRACE_CONN1("ei_xconnect","-> CONNECT attempt to connect to %s",
1243 alivename);
1244 } else {
1245 EI_TRACE_CONN1("ei_xconnect","-> CONNECT attempt to connect to port %d",
1246 rport);
1247 }
1248
1249 if (epmd_says_version < EI_DIST_LOW) {
1250 EI_TRACE_ERR1("ei_xconnect","-> CONNECT remote version %d not compatible",
1251 epmd_says_version);
1252 return ERL_ERROR;
1253 }
1254
1255 if (!ec->thisnodename[0] && epmd_says_version < EI_DIST_6) {
1256 /* This is a dynamic node name. We have to use at least vsn 6
1257 of the dist protocol for this to work. */
1258 epmd_says_version = EI_DIST_6;
1259 }
1260
1261 err = ei_socket_ctx__(cbs, &ctx, ec->setup_context);
1262 if (err) {
1263 EI_TRACE_ERR2("ei_xconnect","-> SOCKET failed: %s (%d)",
1264 estr(err), err);
1265 erl_errno = err;
1266 return ERL_CONNECT_FAIL;
1267 }
1268
1269 memset((void *) &addr, 0, sizeof(struct sockaddr_in));
1270 memcpy((void *) &addr.sin_addr, (void *) ip_addr, sizeof(addr.sin_addr));
1271 addr.sin_family = AF_INET;
1272 addr.sin_port = htons(rport);
1273
1274 err = ei_connect_ctx_t__(cbs, ctx, (void *) &addr, sizeof(addr), tmo);
1275 if (err) {
1276 EI_TRACE_ERR2("ei_xconnect","-> CONNECT socket connect failed: %s (%d)",
1277 estr(err), err);
1278 abort_connection(cbs, ctx);
1279 erl_errno = err;
1280 return ERL_CONNECT_FAIL;
1281 }
1282
1283 EI_TRACE_CONN0("ei_xconnect","-> CONNECT connected to remote");
1284
1285 err = EI_GET_FD__(cbs, ctx, &sockd);
1286 if (err) {
1287 EI_CONN_SAVE_ERRNO__(err);
1288 goto error;
1289 }
1290
1291 err = cbs->handshake_packet_header_size(ctx, &pkt_sz);
1292 if (err) {
1293 EI_CONN_SAVE_ERRNO__(err);
1294 goto error;
1295 }
1296
1297 if (send_name(ec, ctx, pkt_sz, epmd_says_version, tmo))
1298 goto error;
1299 if (recv_status(ec, ctx, pkt_sz, tmo))
1300 goto error;
1301 if (recv_challenge(cbs, ctx, pkt_sz, &her_challenge,
1302 &her_flags, NULL, tmo))
1303 goto error;
1304 her_version = (her_flags & DFLAG_HANDSHAKE_23) ? EI_DIST_6 : EI_DIST_5;
1305 our_challenge = gen_challenge();
1306 gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
1307 if (send_complement(ec, ctx, pkt_sz, epmd_says_version, her_flags, tmo))
1308 goto error;
1309 if (send_challenge_reply(cbs, ctx, pkt_sz, our_digest, our_challenge, tmo))
1310 goto error;
1311 if (recv_challenge_ack(cbs, ctx, pkt_sz, our_challenge,
1312 ec->ei_connect_cookie, tmo))
1313 goto error;
1314 if (put_ei_socket_info(sockd, her_version, null_cookie, ec, cbs, ctx) != 0)
1315 goto error;
1316
1317 if (cbs->connect_handshake_complete) {
1318 err = cbs->connect_handshake_complete(ctx);
1319 if (err) {
1320 EI_TRACE_ERR2("ei_xconnect","-> CONNECT failed: %s (%d)",
1321 estr(err), err);
1322 close_connection(cbs, ctx, sockd);
1323 EI_CONN_SAVE_ERRNO__(err);
1324 return ERL_ERROR;
1325 }
1326 }
1327
1328 if (alivename != NULL) {
1329 EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote = %s",alivename);
1330 } else {
1331 EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote port = %d",rport);
1332 }
1333
1334 erl_errno = 0;
1335 return sockd;
1336
1337 error:
1338 EI_TRACE_ERR0("ei_xconnect","-> CONNECT failed");
1339 abort_connection(cbs, ctx);
1340 return ERL_ERROR;
1341 } /* ei_xconnect */
1342
1343 /*
1344 * Set up a connection to a given Node, and
1345 * interchange hand shake messages with it.
1346 * Returns a valid file descriptor at success,
1347 * otherwise a negative error code.
1348 */
ei_connect_tmo(ei_cnode * ec,char * nodename,unsigned ms)1349 int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms)
1350 {
1351 char *hostname, alivename[BUFSIZ];
1352 Erl_IpAddr ip;
1353 int res;
1354 char buffer[1024];
1355 char* buf = buffer;
1356
1357 if (strlen(nodename) > MAXNODELEN) {
1358 EI_TRACE_ERR0("ei_connect","Too long nodename");
1359 return ERL_ERROR;
1360 }
1361
1362 /* extract the host and alive parts from nodename */
1363 if (!(hostname = strchr(nodename,'@'))) {
1364 EI_TRACE_ERR0("ei_connect","Node name has no @ in name");
1365 return ERL_ERROR;
1366 } else {
1367 strncpy(alivename, nodename, hostname - nodename);
1368 alivename[hostname - nodename] = 0x0;
1369 hostname++;
1370 }
1371
1372 res = ip_address_from_hostname(hostname, &buf, sizeof(buffer), &ip);
1373
1374 if (res < 0) {
1375 return res;
1376 }
1377
1378 res = ei_xconnect_tmo(ec, ip, alivename, ms);
1379
1380 if(buf != buffer) {
1381 free(buf);
1382 }
1383
1384 return res;
1385 } /* ei_connect */
1386
ei_connect(ei_cnode * ec,char * nodename)1387 int ei_connect(ei_cnode* ec, char *nodename)
1388 {
1389 return ei_connect_tmo(ec, nodename, 0);
1390 }
1391
ei_connect_host_port_tmo(ei_cnode * ec,char * host,int port,unsigned ms)1392 int ei_connect_host_port_tmo(ei_cnode* ec, char *host, int port, unsigned ms)
1393 {
1394 Erl_IpAddr ip;
1395 char buffer[1024];
1396 char* buf = buffer;
1397 int res = ip_address_from_hostname(host, &buf, sizeof(buffer), &ip);
1398 if (res < 0) {
1399 return res;
1400 }
1401 if(buf != buffer) {
1402 free(buf);
1403 }
1404 return ei_xconnect_host_port_tmo(ec, ip, port, ms);
1405 }
1406
ei_connect_host_port(ei_cnode * ec,char * host,int port)1407 int ei_connect_host_port(ei_cnode* ec, char *host, int port)
1408 {
1409 return ei_connect_host_port_tmo(ec, host, port, 0);
1410 }
1411
ei_xconnect_tmo(ei_cnode * ec,Erl_IpAddr ip_addr,char * alivename,unsigned ms)1412 int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr ip_addr, char *alivename, unsigned ms)
1413 {
1414 int epmd_says_version = 0;
1415 int port;
1416 unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
1417 if ((port = ei_epmd_port_tmo(ip_addr,alivename,&epmd_says_version, tmo)) < 0) {
1418 EI_TRACE_ERR0("ei_xconnect","-> CONNECT can't get remote port");
1419 /* ei_epmd_port_tmo() has set erl_errno */
1420 return ERL_NO_PORT;
1421 }
1422 return ei_connect_helper(ec, ip_addr, alivename, ms, port, epmd_says_version);
1423 }
1424
ei_xconnect(ei_cnode * ec,Erl_IpAddr ip_addr,char * alivename)1425 int ei_xconnect(ei_cnode* ec, Erl_IpAddr ip_addr, char *alivename)
1426 {
1427 return ei_xconnect_tmo(ec, ip_addr, alivename, 0);
1428 }
1429
ei_xconnect_host_port_tmo(ei_cnode * ec,Erl_IpAddr ip_addr,int port,unsigned ms)1430 int ei_xconnect_host_port_tmo(ei_cnode* ec, Erl_IpAddr ip_addr, int port, unsigned ms)
1431 {
1432 return ei_connect_helper(ec, ip_addr, NULL, ms, port, EI_DIST_LOW);
1433 }
1434
ei_xconnect_host_port(ei_cnode * ec,Erl_IpAddr ip_addr,int port)1435 int ei_xconnect_host_port(ei_cnode* ec, Erl_IpAddr ip_addr, int port)
1436 {
1437 return ei_xconnect_host_port_tmo(ec, ip_addr, port, 0);
1438 }
1439
ei_listen(ei_cnode * ec,int * port,int backlog)1440 int ei_listen(ei_cnode *ec, int *port, int backlog)
1441 {
1442 struct in_addr ip_addr;
1443 ip_addr.s_addr = htonl(INADDR_ANY);
1444 return ei_xlisten(ec, &ip_addr, port, backlog);
1445 }
1446
ei_xlisten(ei_cnode * ec,struct in_addr * ip_addr,int * port,int backlog)1447 int ei_xlisten(ei_cnode *ec, struct in_addr *ip_addr, int *port, int backlog)
1448 {
1449 ei_socket_callbacks *cbs = ec->cbs;
1450 struct sockaddr_in sock_addr;
1451 void *ctx;
1452 int fd, err, len;
1453
1454 err = ei_socket_ctx__(cbs, &ctx, ec->setup_context);
1455 if (err) {
1456 EI_TRACE_ERR2("ei_xlisten","-> SOCKET failed: %s (%d)",
1457 estr(err), err);
1458 erl_errno = err;
1459 return ERL_ERROR;
1460 }
1461
1462 memset((void *) &sock_addr, 0, sizeof(struct sockaddr_in));
1463 memcpy((void *) &sock_addr.sin_addr, (void *) ip_addr, sizeof(*ip_addr));
1464 sock_addr.sin_family = AF_INET;
1465 sock_addr.sin_port = htons((short) *port);
1466
1467 len = sizeof(sock_addr);
1468 err = ei_listen_ctx__(cbs, ctx, (void *) &sock_addr, &len, backlog);
1469 if (err) {
1470 EI_TRACE_ERR2("ei_xlisten","-> listen failed: %s (%d)",
1471 estr(err), err);
1472 erl_errno = err;
1473 goto error;
1474 }
1475
1476 if (len != sizeof(sock_addr)) {
1477 if (len < offsetof(struct sockaddr_in, sin_addr) + sizeof(sock_addr.sin_addr)
1478 || len < offsetof(struct sockaddr_in, sin_port) + sizeof(sock_addr.sin_port)) {
1479 erl_errno = EIO;
1480 EI_TRACE_ERR0("ei_xlisten","-> get info failed");
1481 goto error;
1482 }
1483 }
1484
1485 memcpy((void *) ip_addr, (void *) &sock_addr.sin_addr, sizeof(*ip_addr));
1486 *port = (int) ntohs(sock_addr.sin_port);
1487
1488 err = EI_GET_FD__(cbs, ctx, &fd);
1489 if (err) {
1490 erl_errno = err;
1491 goto error;
1492 }
1493
1494 if (put_ei_socket_info(fd, 0, null_cookie, ec, cbs, ctx) != 0) {
1495 EI_TRACE_ERR0("ei_xlisten","-> save socket info failed");
1496 erl_errno = EIO;
1497 goto error;
1498 }
1499
1500 erl_errno = 0;
1501
1502 return fd;
1503
1504 error:
1505 abort_connection(cbs, ctx);
1506 return ERL_ERROR;
1507 }
1508
close_connection(ei_socket_callbacks * cbs,void * ctx,int fd)1509 static int close_connection(ei_socket_callbacks *cbs, void *ctx, int fd)
1510 {
1511 int err;
1512 remove_ei_socket_info(fd);
1513 err = ei_close_ctx__(cbs, ctx);
1514 if (err) {
1515 erl_errno = err;
1516 return ERL_ERROR;
1517 }
1518 return 0;
1519 }
1520
ei_close_connection(int fd)1521 int ei_close_connection(int fd)
1522 {
1523 ei_socket_callbacks *cbs;
1524 void *ctx;
1525 int err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
1526 if (err)
1527 erl_errno = err;
1528 else {
1529 if (close_connection(cbs, ctx, fd) == 0)
1530 return 0;
1531 }
1532 EI_TRACE_ERR2("ei_close_connection","<- CLOSE socket close failed: %s (%d)",
1533 estr(erl_errno), erl_errno);
1534 return ERL_ERROR;
1535 } /* ei_close_connection */
1536
abort_connection(ei_socket_callbacks * cbs,void * ctx)1537 static void abort_connection(ei_socket_callbacks *cbs, void *ctx)
1538 {
1539 (void) ei_close_ctx__(cbs, ctx);
1540 }
1541
1542 /*
1543 * Accept and initiate a connection from another
1544 * Erlang node. Return a file descriptor at success,
1545 * otherwise -1;
1546 */
ei_accept(ei_cnode * ec,int lfd,ErlConnect * conp)1547 int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp)
1548 {
1549 return ei_accept_tmo(ec, lfd, conp, 0);
1550 }
1551
ei_accept_tmo(ei_cnode * ec,int lfd,ErlConnect * conp,unsigned ms)1552 int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
1553 {
1554 int fd;
1555 DistFlags her_flags;
1556 char tmp_nodename[MAXNODELEN+1];
1557 char send_name_tag;
1558 char *her_name;
1559 int pkt_sz, err;
1560 struct sockaddr_in addr;
1561 int addr_len = sizeof(struct sockaddr_in);
1562 ei_socket_callbacks *cbs;
1563 void *ctx;
1564 unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
1565
1566 erl_errno = EIO; /* Default error code */
1567
1568 err = EI_GET_CBS_CTX__(&cbs, &ctx, lfd);
1569 if (err) {
1570 if (lfd < 0) {
1571 EI_CONN_SAVE_ERRNO__(err);
1572 return ERL_ERROR;
1573 }
1574 /*
1575 * This can be a listen socket created without ei_listen or ei_xlisten,
1576 * so we must assume it is.
1577 */
1578 cbs = &ei_default_socket_callbacks;
1579 ctx = EI_FD_AS_CTX__(lfd);
1580 }
1581
1582 if (ec->cbs != cbs) {
1583 EI_CONN_SAVE_ERRNO__(EINVAL);
1584 return ERL_ERROR;
1585 }
1586
1587 EI_TRACE_CONN0("ei_accept","<- ACCEPT waiting for connection");
1588
1589 if (conp) {
1590 her_name = &conp->nodename[0];
1591 }
1592 else {
1593 her_name = &tmp_nodename[0];
1594 }
1595
1596 /*
1597 * ei_accept_ctx_t__() replaces the pointer to the listen context
1598 * with a pointer to the accepted connection context on success.
1599 */
1600 err = ei_accept_ctx_t__(cbs, &ctx, (void *) &addr, &addr_len, tmo);
1601 if (err) {
1602 EI_TRACE_ERR2("ei_accept","<- ACCEPT socket accept failed: %s (%d)",
1603 estr(err), err);
1604 EI_CONN_SAVE_ERRNO__(err);
1605 return ERL_ERROR;
1606 }
1607
1608 err = EI_GET_FD__(cbs, ctx, &fd);
1609 if (err) {
1610 EI_TRACE_ERR2("ei_accept","<- ACCEPT get fd failed: %s (%d)",
1611 estr(err), err);
1612 EI_CONN_SAVE_ERRNO__(err);
1613 }
1614
1615 if (addr_len != sizeof(struct sockaddr_in)) {
1616 if (addr_len < (offsetof(struct sockaddr_in, sin_addr)
1617 + sizeof(addr.sin_addr))) {
1618 EI_TRACE_ERR0("ei_accept","<- ACCEPT get addr failed");
1619 goto error;
1620 }
1621 }
1622
1623 err = cbs->handshake_packet_header_size(ctx, &pkt_sz);
1624 if (err) {
1625 EI_TRACE_ERR2("ei_accept","<- ACCEPT get packet size failed: %s (%d)",
1626 estr(err), err);
1627 EI_CONN_SAVE_ERRNO__(err);
1628 }
1629
1630 EI_TRACE_CONN0("ei_accept","<- ACCEPT connected to remote");
1631
1632 if (recv_name(cbs, ctx, pkt_sz, &send_name_tag, &her_flags,
1633 her_name, tmo)) {
1634 EI_TRACE_ERR0("ei_accept","<- ACCEPT initial ident failed");
1635 goto error;
1636 }
1637
1638 {
1639 unsigned her_version = (her_flags & DFLAG_HANDSHAKE_23) ? 6 : 5;
1640 unsigned our_challenge;
1641 unsigned her_challenge;
1642 unsigned char our_digest[16];
1643
1644 if (send_status(cbs, ctx, pkt_sz, "ok", tmo))
1645 goto error;
1646 our_challenge = gen_challenge();
1647 if (send_challenge(ec, ctx, pkt_sz, our_challenge, her_flags, tmo))
1648 goto error;
1649 if (send_name_tag == 'n' && (her_flags & DFLAG_HANDSHAKE_23)) {
1650 if (recv_complement(cbs, ctx, pkt_sz, tmo))
1651 goto error;
1652 }
1653 if (recv_challenge_reply(cbs, ctx, pkt_sz, our_challenge,
1654 ec->ei_connect_cookie, &her_challenge, tmo))
1655 goto error;
1656 gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
1657 if (send_challenge_ack(cbs, ctx, pkt_sz, our_digest, tmo))
1658 goto error;
1659 if (put_ei_socket_info(fd, her_version, null_cookie, ec, cbs, ctx) != 0)
1660 goto error;
1661 }
1662 if (conp) {
1663 memcpy((void *) conp->ipadr, (void *) &addr.sin_addr, sizeof(conp->ipadr));
1664 }
1665
1666 if (cbs->accept_handshake_complete) {
1667 err = cbs->accept_handshake_complete(ctx);
1668 if (err) {
1669 EI_TRACE_ERR2("ei_xconnect","-> ACCEPT handshake failed: %s (%d)",
1670 estr(err), err);
1671 close_connection(cbs, ctx, fd);
1672 EI_CONN_SAVE_ERRNO__(err);
1673 return ERL_ERROR;
1674 }
1675 }
1676
1677 EI_TRACE_CONN1("ei_accept","<- ACCEPT (ok) remote = %s",her_name);
1678
1679 erl_errno = 0; /* No error */
1680 return fd;
1681
1682 error:
1683 EI_TRACE_ERR0("ei_accept","<- ACCEPT failed");
1684 abort_connection(cbs, ctx);
1685 return ERL_ERROR;
1686 } /* ei_accept */
1687
1688
1689 /* Receives a message from an Erlang socket.
1690 * If the message was a TICK it is immediately
1691 * answered. Returns: ERL_ERROR, ERL_TICK or
1692 * the number of bytes read.
1693 */
ei_receive_tmo(int fd,unsigned char * bufp,int bufsize,unsigned ms)1694 int ei_receive_tmo(int fd, unsigned char *bufp, int bufsize, unsigned ms)
1695 {
1696 ssize_t len;
1697 unsigned char fourbyte[4]={0,0,0,0};
1698 int err;
1699 ei_socket_callbacks *cbs;
1700 void *ctx;
1701 unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;
1702
1703 err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
1704 if (err) {
1705 EI_CONN_SAVE_ERRNO__(err);
1706 return ERL_ERROR;
1707 }
1708
1709 len = (ssize_t) 4;
1710 err = ei_read_fill_ctx_t__(cbs, ctx, (char *) bufp, &len, tmo);
1711 if (!err && len != (ssize_t) 4)
1712 err = EIO;
1713 if (err) {
1714 EI_CONN_SAVE_ERRNO__(err);
1715 return ERL_ERROR;
1716 }
1717
1718 /* Tick handling */
1719 len = get_int32(bufp);
1720 if (len == ERL_TICK) {
1721 len = 4;
1722 ei_write_fill_ctx_t__(cbs, ctx, (char *) fourbyte, &len, tmo);
1723 /* FIXME ok to ignore error or timeout? */
1724 erl_errno = EAGAIN;
1725 return ERL_TICK;
1726 }
1727
1728 if (len > bufsize) {
1729 /* FIXME: We should drain the message. */
1730 erl_errno = EMSGSIZE;
1731 return ERL_ERROR;
1732 }
1733 else {
1734 ssize_t need = len;
1735 err = ei_read_fill_ctx_t__(cbs, ctx, (char *) bufp, &len, tmo);
1736 if (err) {
1737 EI_CONN_SAVE_ERRNO__(err);
1738 return ERL_ERROR;
1739 }
1740 if (len != need) {
1741 erl_errno = EIO;
1742 return ERL_ERROR;
1743 }
1744 }
1745
1746 return (int) len;
1747
1748 }
1749
ei_receive(int fd,unsigned char * bufp,int bufsize)1750 int ei_receive(int fd, unsigned char *bufp, int bufsize)
1751 {
1752 return ei_receive_tmo(fd, bufp, bufsize, 0);
1753 }
1754
ei_reg_send_tmo(ei_cnode * ec,int fd,char * server_name,char * buf,int len,unsigned ms)1755 int ei_reg_send_tmo(ei_cnode* ec, int fd, char *server_name,
1756 char* buf, int len, unsigned ms)
1757 {
1758 /* erl_errno and return code is set by ei_reg_send_encoded_tmo() */
1759 return ei_send_reg_encoded_tmo(fd, ei_self(ec), server_name, buf, len, ms);
1760 }
1761
1762
ei_reg_send(ei_cnode * ec,int fd,char * server_name,char * buf,int len)1763 int ei_reg_send(ei_cnode* ec, int fd, char *server_name, char* buf, int len)
1764 {
1765 return ei_reg_send_tmo(ec,fd,server_name,buf,len,0);
1766 }
1767
1768 /*
1769 * Sends an Erlang message to a process at an Erlang node
1770 */
ei_send_tmo(int fd,erlang_pid * to,char * buf,int len,unsigned ms)1771 int ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned ms)
1772 {
1773 /* erl_errno and return code is set by ei_reg_send_encoded_tmo() */
1774 return ei_send_encoded_tmo(fd, to, buf, len, ms);
1775 }
1776
ei_send(int fd,erlang_pid * to,char * buf,int len)1777 int ei_send(int fd, erlang_pid* to, char* buf, int len)
1778 {
1779 return ei_send_tmo(fd, to, buf, len, 0);
1780 }
1781
1782
1783 /*
1784 * Try to receive an Erlang message on a given socket. Returns
1785 * ERL_TICK, ERL_MSG, or ERL_ERROR. Sets `erl_errno' on ERL_ERROR and
1786 * ERL_TICK (to EAGAIN in the latter case).
1787 */
1788
ei_do_receive_msg(int fd,int staticbuffer_p,erlang_msg * msg,ei_x_buff * x,unsigned ms)1789 int ei_do_receive_msg(int fd, int staticbuffer_p,
1790 erlang_msg* msg, ei_x_buff* x, unsigned ms)
1791 {
1792 int msglen;
1793 int i;
1794
1795 if (!(i=ei_recv_internal(fd, &x->buff, &x->buffsz, msg, &msglen,
1796 staticbuffer_p, ms))) {
1797 erl_errno = EAGAIN;
1798 return ERL_TICK;
1799 }
1800 if (i<0) {
1801 /* erl_errno set by ei_recv_internal() */
1802 return ERL_ERROR;
1803 }
1804 if (staticbuffer_p && msglen > x->buffsz)
1805 {
1806 erl_errno = EMSGSIZE;
1807 return ERL_ERROR;
1808 }
1809 x->index = msglen;
1810 switch (msg->msgtype) { /* FIXME does not handle trace tokens and monitors */
1811 case ERL_SEND:
1812 case ERL_REG_SEND:
1813 case ERL_LINK:
1814 case ERL_UNLINK:
1815 case ERL_GROUP_LEADER:
1816 case ERL_EXIT:
1817 case ERL_EXIT2:
1818 return ERL_MSG;
1819
1820 default:
1821 /*if (emsg->to) 'erl'_free_term(emsg->to);
1822 if (emsg->from) 'erl'_free_term(emsg->from);
1823 if (emsg->msg) 'erl'_free_term(emsg->msg);
1824 emsg->to = NULL;
1825 emsg->from = NULL;
1826 emsg->msg = NULL;*/
1827
1828 erl_errno = EIO;
1829 return ERL_ERROR;
1830 }
1831 } /* do_receive_msg */
1832
1833
ei_receive_msg(int fd,erlang_msg * msg,ei_x_buff * x)1834 int ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)
1835 {
1836 return ei_do_receive_msg(fd, 1, msg, x, 0);
1837 }
1838
ei_xreceive_msg(int fd,erlang_msg * msg,ei_x_buff * x)1839 int ei_xreceive_msg(int fd, erlang_msg *msg, ei_x_buff *x)
1840 {
1841 return ei_do_receive_msg(fd, 0, msg, x, 0);
1842 }
1843
ei_receive_msg_tmo(int fd,erlang_msg * msg,ei_x_buff * x,unsigned ms)1844 int ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms)
1845 {
1846 return ei_do_receive_msg(fd, 1, msg, x, ms);
1847 }
1848
ei_xreceive_msg_tmo(int fd,erlang_msg * msg,ei_x_buff * x,unsigned ms)1849 int ei_xreceive_msg_tmo(int fd, erlang_msg *msg, ei_x_buff *x, unsigned ms)
1850 {
1851 return ei_do_receive_msg(fd, 0, msg, x, ms);
1852 }
1853
1854 /*
1855 * A remote process call consists of two parts, sending a request and
1856 * receiving a response. This function sends the request and the
1857 * ei_rpc_from function receives the response.
1858 *
1859 * Here is the term that is sent when (flags & EI_RPC_FETCH_STDOUT) != 0:
1860 *
1861 * { PidFrom, { call, Mod, Fun, Args, send_stdout_to_caller }}
1862 *
1863 * Here is the term that is sent otherwise:
1864 *
1865 * { PidFrom, { call, Mod, Fun, Args, user }}
1866 *
1867 * Returns a non-negative number for success and a negative number for
1868 * failure.
1869 *
1870 */
ei_xrpc_to(ei_cnode * ec,int fd,char * mod,char * fun,const char * buf,int len,int flags)1871 int ei_xrpc_to(ei_cnode *ec, int fd, char *mod, char *fun,
1872 const char *buf, int len, int flags)
1873 {
1874 ei_x_buff x;
1875 erlang_pid *self = ei_self(ec);
1876 int err = ERL_ERROR;
1877
1878 /* encode header */
1879 if (ei_x_new_with_version(&x) < 0)
1880 goto einval;
1881 if (ei_x_encode_tuple_header(&x, 2) < 0) /* A */
1882 goto einval;
1883
1884 if (ei_x_encode_pid(&x, self) < 0) /* A 1 */
1885 goto einval;
1886
1887 if (ei_x_encode_tuple_header(&x, 5) < 0) /* B A 2 */
1888 goto einval;
1889 if (ei_x_encode_atom(&x, "call") < 0) /* B 1 */
1890 goto einval;
1891 if (ei_x_encode_atom(&x, mod) < 0) /* B 2 */
1892 goto einval;
1893 if (ei_x_encode_atom(&x, fun) < 0) /* B 3 */
1894 goto einval;
1895 if (ei_x_append_buf(&x, buf, len) < 0) /* B 4 */
1896 goto einval;
1897 if (flags & EI_RPC_FETCH_STDOUT) {
1898 if (ei_x_encode_atom(&x, "send_stdout_to_caller") < 0) /* B 5 */
1899 goto einval;
1900 } else {
1901 if (ei_x_encode_atom(&x, "user") < 0) /* B 5 */
1902 goto einval;
1903 }
1904
1905 err = ei_send_reg_encoded(fd, self, "rex", x.buff, x.index);
1906 if (err)
1907 goto error;
1908
1909 ei_x_free(&x);
1910
1911 return 0;
1912
1913 einval:
1914 EI_CONN_SAVE_ERRNO__(EINVAL);
1915
1916 error:
1917 if (x.buff != NULL)
1918 ei_x_free(&x);
1919 return err;
1920 } /* xrpc_to */
1921
1922
ei_rpc_to(ei_cnode * ec,int fd,char * mod,char * fun,const char * buf,int len)1923 int ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun,
1924 const char *buf, int len)
1925 {
1926 return ei_xrpc_to(ec, fd, mod, fun, buf, len, 0);
1927 } /* rpc_to */
1928
1929 /*
1930 * And here is the rpc receiving part. A negative
1931 * timeout means 'infinity'. Returns either of: ERL_MSG,
1932 * ERL_TICK, ERL_ERROR or ERL_TIMEOUT.
1933 */
ei_rpc_from(ei_cnode * ec,int fd,int timeout,erlang_msg * msg,ei_x_buff * x)1934 int ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg,
1935 ei_x_buff *x)
1936 {
1937 unsigned tmo = timeout < 0 ? EI_SCLBK_INF_TMO : (unsigned) timeout;
1938 int res = ei_xreceive_msg_tmo(fd, msg, x, tmo);
1939 if (res < 0 && erl_errno == ETIMEDOUT)
1940 return ERL_TIMEOUT;
1941 return res;
1942 } /* rpc_from */
1943
ei_rpc(ei_cnode * ec,int fd,char * mod,char * fun,const char * inbuf,int inbuflen,ei_x_buff * x)1944 int ei_rpc(ei_cnode* ec, int fd, char *mod, char *fun,
1945 const char* inbuf, int inbuflen, ei_x_buff* x)
1946 {
1947 int i, index;
1948 ei_term t;
1949 erlang_msg msg;
1950 char rex[MAXATOMLEN];
1951
1952 if (ei_rpc_to(ec, fd, mod, fun, inbuf, inbuflen) < 0) {
1953 return ERL_ERROR;
1954 }
1955
1956 /* ei_rpc_from() responds with a tick if it gets one... */
1957 while ((i = ei_rpc_from(ec, fd, ERL_NO_TIMEOUT, &msg, x)) == ERL_TICK)
1958 ;
1959
1960 if (i == ERL_ERROR) return i;
1961
1962 /* Expect: {rex, RPC_Reply} */
1963
1964 index = 0;
1965 if (ei_decode_version(x->buff, &index, &i) < 0)
1966 goto ebadmsg;
1967
1968 if (ei_decode_ei_term(x->buff, &index, &t) < 0)
1969 goto ebadmsg;
1970
1971 if (t.ei_type != ERL_SMALL_TUPLE_EXT && t.ei_type != ERL_LARGE_TUPLE_EXT)
1972 goto ebadmsg;
1973
1974 if (t.arity != 2)
1975 goto ebadmsg;
1976
1977 if (ei_decode_atom(x->buff, &index, rex) < 0)
1978 goto ebadmsg;
1979
1980 if (strcmp("rex", rex) != 0)
1981 goto ebadmsg;
1982
1983 /* remove header */
1984 x->index -= index;
1985 memmove(x->buff, &x->buff[index], x->index);
1986 return 0;
1987
1988 ebadmsg:
1989
1990 EI_CONN_SAVE_ERRNO__(EBADMSG);
1991 return ERL_ERROR;
1992 }
1993
1994
1995 /*
1996 ** Handshake
1997 */
1998
1999
2000 /* FROM RTP RFC 1889 (except that we use all bits, bug in RFC?) */
md_32(char * string,int length)2001 static unsigned int md_32(char* string, int length)
2002 {
2003 MD5_CTX ctx;
2004 union {
2005 char c[16];
2006 unsigned x[4];
2007 } digest;
2008 ei_MD5Init(&ctx);
2009 ei_MD5Update(&ctx, (unsigned char *) string,
2010 (unsigned) length);
2011 ei_MD5Final((unsigned char *) digest.c, &ctx);
2012 return (digest.x[0] ^ digest.x[1] ^ digest.x[2] ^ digest.x[3]);
2013 }
2014
2015 #if defined(__WIN32__)
gen_challenge(void)2016 unsigned int gen_challenge(void)
2017 {
2018 struct {
2019 SYSTEMTIME tv;
2020 DWORD cpu;
2021 int pid;
2022 } s;
2023 GetSystemTime(&s.tv);
2024 s.cpu = GetTickCount();
2025 s.pid = getpid();
2026 return md_32((char*) &s, sizeof(s));
2027 }
2028
2029 #else /* some unix */
2030
gen_challenge(void)2031 static unsigned int gen_challenge(void)
2032 {
2033 struct {
2034 struct timeval tv;
2035 clock_t cpu;
2036 pid_t pid;
2037 u_long hid;
2038 uid_t uid;
2039 gid_t gid;
2040 struct utsname name;
2041 } s;
2042
2043 memset(&s, 0, sizeof(s));
2044 gettimeofday(&s.tv, 0);
2045 uname(&s.name);
2046 s.cpu = clock();
2047 s.pid = getpid();
2048 #if defined(__ANDROID__) || defined(__HAIKU__)
2049 s.hid = 0;
2050 #else
2051 s.hid = gethostid();
2052 #endif
2053 s.uid = getuid();
2054 s.gid = getgid();
2055
2056 return md_32((char*) &s, sizeof(s));
2057 }
2058 #endif
2059
gen_digest(unsigned challenge,char cookie[],unsigned char digest[16])2060 static void gen_digest(unsigned challenge, char cookie[],
2061 unsigned char digest[16])
2062 {
2063 MD5_CTX c;
2064
2065 char chbuf[21];
2066
2067 sprintf(chbuf,"%u", challenge);
2068 ei_MD5Init(&c);
2069 ei_MD5Update(&c, (unsigned char *) cookie,
2070 (unsigned) strlen(cookie));
2071 ei_MD5Update(&c, (unsigned char *) chbuf,
2072 (unsigned) strlen(chbuf));
2073 ei_MD5Final(digest, &c);
2074 }
2075
2076
hex(char digest[16],char buff[33])2077 static char *hex(char digest[16], char buff[33])
2078 {
2079 static char tab[] = "0123456789abcdef";
2080 unsigned char *d = (unsigned char *) digest;
2081 //static char buff[sizeof(digest)*2 + 1];
2082 char *p = buff;
2083 int i;
2084
2085 for (i = 0; i < 16; ++i) {
2086 *p++ = tab[(int)((*d) >> 4)];
2087 *p++ = tab[(int)((*d++) & 0xF)];
2088 }
2089 *p = '\0';
2090 return buff;
2091 }
2092
read_hs_package(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,char ** buf,int * buflen,int * is_static,unsigned ms)2093 static int read_hs_package(ei_socket_callbacks *cbs, void *ctx,
2094 int pkt_sz, char **buf, int *buflen,
2095 int *is_static, unsigned ms)
2096 {
2097 unsigned char nbuf[4];
2098 unsigned char *x = nbuf;
2099 ssize_t len, need;
2100 int err;
2101
2102 len = (ssize_t) pkt_sz;
2103 err = ei_read_fill_ctx_t__(cbs, ctx, (char *)nbuf, &len, ms);
2104 if (!err && len != (ssize_t) pkt_sz)
2105 err = EIO;
2106 if (err) {
2107 EI_CONN_SAVE_ERRNO__(err);
2108 return -1;
2109 }
2110
2111 switch (pkt_sz) {
2112 case 2:
2113 len = get16be(x);
2114 break;
2115 case 4:
2116 len = get32be(x);
2117 break;
2118 default:
2119 return -1;
2120 }
2121
2122 if (len > *buflen) {
2123 if (*is_static) {
2124 char *tmp = malloc(len);
2125 if (!tmp) {
2126 erl_errno = ENOMEM;
2127 return -1;
2128 }
2129 *buf = tmp;
2130 *is_static = 0;
2131 *buflen = len;
2132 } else {
2133 char *tmp = realloc(*buf, len);
2134 if (!tmp) {
2135 erl_errno = ENOMEM;
2136 return -1;
2137 }
2138 *buf = tmp;
2139 *buflen = len;
2140 }
2141 }
2142 need = len;
2143 err = ei_read_fill_ctx_t__(cbs, ctx, *buf, &len, ms);
2144 if (!err && len != need)
2145 err = EIO;
2146 if (err) {
2147 EI_CONN_SAVE_ERRNO__(err);
2148 return -1;
2149 }
2150 return len;
2151 }
2152
2153
send_status(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,char * status,unsigned ms)2154 static int send_status(ei_socket_callbacks *cbs, void *ctx,
2155 int pkt_sz, char *status, unsigned ms)
2156 {
2157 char *buf, *s;
2158 char dbuf[DEFBUF_SIZ];
2159 int siz = strlen(status) + 1 + pkt_sz;
2160 int err, ret;
2161 ssize_t len;
2162
2163 buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
2164 if (!buf) {
2165 erl_errno = ENOMEM;
2166 return -1;
2167 }
2168 s = buf;
2169 switch (pkt_sz) {
2170 case 2:
2171 put16be(s,siz - 2);
2172 break;
2173 case 4:
2174 put32be(s,siz - 4);
2175 break;
2176 default:
2177 ret = -1;
2178 goto done;
2179 }
2180 put8(s, 's');
2181 memcpy(s, status, strlen(status));
2182 len = (ssize_t) siz;
2183 err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
2184 if (!err && len != (ssize_t) siz)
2185 err = EIO;
2186 if (err) {
2187 EI_TRACE_ERR2("send_status","-> SEND_STATUS socket write failed: %s (%d)",
2188 estr(err), err);
2189 EI_CONN_SAVE_ERRNO__(err);
2190 ret = -1;
2191 }
2192 else {
2193 EI_TRACE_CONN1("send_status","-> SEND_STATUS (%s)",status);
2194 ret = 0;
2195 }
2196 done:
2197 if (buf != dbuf)
2198 free(buf);
2199 return ret;
2200 }
2201
recv_status(ei_cnode * ec,void * ctx,int pkt_sz,unsigned ms)2202 static int recv_status(ei_cnode *ec, void *ctx,
2203 int pkt_sz, unsigned ms)
2204 {
2205 char dbuf[DEFBUF_SIZ];
2206 char *buf = dbuf;
2207 int is_static = 1;
2208 int buflen = DEFBUF_SIZ;
2209 int rlen;
2210
2211 if ((rlen = read_hs_package(ec->cbs, ctx, pkt_sz,
2212 &buf, &buflen, &is_static, ms)) <= 0) {
2213 EI_TRACE_ERR1("recv_status",
2214 "<- RECV_STATUS socket read failed (%d)", rlen);
2215 goto error;
2216 }
2217
2218 EI_TRACE_CONN2("recv_status",
2219 "<- RECV_STATUS (%.*s)", (rlen>20 ? 20 : rlen), buf);
2220
2221 if (ec->thisnodename[0]) {
2222 if (rlen >= 3 && buf[0] == 's' && buf[1] == 'o' && buf[2] == 'k') {
2223 /* Expecting "sok" or "sok_simultaneous" */
2224 if (!is_static)
2225 free(buf);
2226 return 0;
2227 }
2228 }
2229 else { /* dynamic node name */
2230 const char* at;
2231 int namelen;
2232 if (rlen >= 7 && strncmp(buf, "snamed:", 7) == 0) {
2233 buf += 7;
2234 rlen -= 7;
2235 namelen = get16be(buf);
2236 rlen -= 2;
2237 if (namelen > MAXNODELEN || (namelen+4) > rlen) {
2238 EI_TRACE_ERR1("recv_status","<- RECV_STATUS nodename too long (%d)",
2239 namelen);
2240 goto error;
2241 }
2242 memcpy(ec->thisnodename, buf, namelen);
2243 ec->thisnodename[namelen] = '\0';
2244 buf += namelen;
2245 ec->creation = get32be(buf);
2246
2247 /* extract alive part from nodename */
2248 if (!(at = strchr(ec->thisnodename,'@'))) {
2249 EI_TRACE_ERR0("ei_connect","Dynamic node name has no @ in name");
2250 return ERL_ERROR;
2251 } else {
2252 const int alen = at - ec->thisnodename;
2253 strncpy(ec->thisalivename, ec->thisnodename, alen);
2254 ec->thisalivename[alen] = '\0';
2255 }
2256
2257 strcpy(ec->self.node, ec->thisnodename);
2258 ec->self.num = 0;
2259 ec->self.serial = 0;
2260 ec->self.creation = ec->creation;
2261 return 0;
2262 }
2263 }
2264 error:
2265 if (!is_static)
2266 free(buf);
2267 return -1;
2268 }
2269
preferred_flags(void)2270 static DistFlags preferred_flags(void)
2271 {
2272 DistFlags flags =
2273 DFLAG_EXTENDED_REFERENCES
2274 | DFLAG_DIST_MONITOR
2275 | DFLAG_EXTENDED_PIDS_PORTS
2276 | DFLAG_FUN_TAGS
2277 | DFLAG_NEW_FUN_TAGS
2278 | DFLAG_NEW_FLOATS
2279 | DFLAG_SMALL_ATOM_TAGS
2280 | DFLAG_UTF8_ATOMS
2281 | DFLAG_MAP_TAG
2282 | DFLAG_BIG_CREATION
2283 | DFLAG_EXPORT_PTR_TAG
2284 | DFLAG_BIT_BINARIES
2285 | DFLAG_HANDSHAKE_23
2286 | DFLAG_V4_NC
2287 | DFLAG_UNLINK_ID;
2288 if (ei_internal_use_21_bitstr_expfun()) {
2289 flags &= ~(DFLAG_EXPORT_PTR_TAG
2290 | DFLAG_BIT_BINARIES);
2291 }
2292 return flags;
2293 }
2294
send_name(ei_cnode * ec,void * ctx,int pkt_sz,unsigned version,unsigned ms)2295 static int send_name(ei_cnode *ec,
2296 void *ctx,
2297 int pkt_sz,
2298 unsigned version,
2299 unsigned ms)
2300 {
2301 char *buf;
2302 unsigned char *s;
2303 char dbuf[DEFBUF_SIZ];
2304 const char* name_ptr;
2305 unsigned int name_len;
2306 int siz;
2307 int err, ret;
2308 ssize_t len;
2309 DistFlags flags = preferred_flags();
2310 char tag;
2311
2312 if (ec->thisnodename[0]) {
2313 name_ptr = ec->thisnodename;
2314 tag = (version == EI_DIST_5) ? 'n' : 'N';
2315 }
2316 else {
2317 /* dynamic node name */
2318 name_ptr = ec->thishostname;
2319 tag = 'N'; /* presume ver 6 */
2320 flags |= DFLAG_NAME_ME;
2321 }
2322
2323 name_len = strlen(name_ptr);
2324
2325 if (tag == 'n')
2326 siz = pkt_sz + 1 + 2 + 4 + name_len;
2327 else
2328 siz = pkt_sz + 1 + 8 + 4 + 2 + name_len;
2329
2330 buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
2331 if (!buf) {
2332 erl_errno = ENOMEM;
2333 return -1;
2334 }
2335 s = (unsigned char *)buf;
2336 switch (pkt_sz) {
2337 case 2:
2338 put16be(s,siz - 2);
2339 break;
2340 case 4:
2341 put32be(s,siz - 4);
2342 break;
2343 default:
2344 ret = -1;
2345 goto done;
2346 }
2347
2348 put8(s, tag);
2349 if (tag == 'n') {
2350 put16be(s, EI_DIST_5); /* some impl (jinterface) demand ver==5 */
2351 put32be(s, flags);
2352 }
2353 else { /* tag == 'N' */
2354 put64be(s, flags);
2355 put32be(s, ec->creation);
2356 put16be(s, name_len);
2357 }
2358 memcpy(s, name_ptr, name_len);
2359 len = (ssize_t) siz;
2360 err = ei_write_fill_ctx_t__(ec->cbs, ctx, buf, &len, ms);
2361 if (!err && len != (ssize_t) siz)
2362 err = EIO;
2363 if (err) {
2364 EI_TRACE_ERR0("send_name", "SEND_NAME -> socket write failed");
2365 EI_CONN_SAVE_ERRNO__(err);
2366 ret = -1;
2367 }
2368 else {
2369 ret = 0;
2370 }
2371 done:
2372 if (buf != dbuf)
2373 free(buf);
2374 return ret;
2375 }
2376
send_challenge(ei_cnode * ec,void * ctx,int pkt_sz,unsigned challenge,DistFlags her_flags,unsigned ms)2377 static int send_challenge(ei_cnode *ec,
2378 void *ctx,
2379 int pkt_sz,
2380 unsigned challenge,
2381 DistFlags her_flags,
2382 unsigned ms)
2383 {
2384 char *buf;
2385 unsigned char *s;
2386 char dbuf[DEFBUF_SIZ];
2387 const unsigned int nodename_len = strlen(ec->thisnodename);
2388 int siz;
2389 int err, ret;
2390 ssize_t len;
2391 DistFlags flags;
2392 const char tag = (her_flags & DFLAG_HANDSHAKE_23) ? 'N' : 'n';
2393
2394 if (tag == 'n')
2395 siz = pkt_sz + 1 + 2 + 4 + 4 + nodename_len;
2396 else
2397 siz = pkt_sz + 1 + 8 + 4 + 4 + 2 + nodename_len;
2398
2399 buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
2400 if (!buf) {
2401 erl_errno = ENOMEM;
2402 return -1;
2403 }
2404 s = (unsigned char *)buf;
2405 switch (pkt_sz) {
2406 case 2:
2407 put16be(s,siz - 2);
2408 break;
2409 case 4:
2410 put32be(s,siz - 4);
2411 break;
2412 default:
2413 ret = -1;
2414 goto done;
2415 }
2416
2417 flags = preferred_flags();
2418 put8(s, tag);
2419 if (tag == 'n') {
2420 put16be(s, EI_DIST_5); /* choosen version */
2421 put32be(s, flags);
2422 put32be(s, challenge);
2423 }
2424 else {
2425 put64be(s, flags);
2426 put32be(s, challenge);
2427 put32be(s, ec->creation);
2428 put16be(s, nodename_len);
2429 }
2430 memcpy(s, ec->thisnodename, nodename_len);
2431 len = (ssize_t) siz;
2432 err = ei_write_fill_ctx_t__(ec->cbs, ctx, buf, &len, ms);
2433 if (!err && len != (ssize_t) siz)
2434 err = EIO;
2435 if (err) {
2436 EI_TRACE_ERR0("send_challenge", "-> SEND_CHALLENGE socket write failed");
2437 EI_CONN_SAVE_ERRNO__(err);
2438 ret = -1;
2439 }
2440 else
2441 ret = 0;
2442 done:
2443 if (buf != dbuf)
2444 free(buf);
2445 return ret;
2446 }
2447
recv_challenge(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned * challenge,DistFlags * flags,char * namebuf,unsigned ms)2448 static int recv_challenge(ei_socket_callbacks *cbs, void *ctx,
2449 int pkt_sz, unsigned *challenge,
2450 DistFlags *flags, char *namebuf, unsigned ms)
2451 {
2452 char dbuf[DEFBUF_SIZ];
2453 char *buf = dbuf;
2454 int is_static = 1;
2455 int buflen = DEFBUF_SIZ;
2456 int rlen, nodename_len;
2457 unsigned version;
2458 char *s;
2459 char tag;
2460 char tmp_nodename[MAXNODELEN+1];
2461
2462 erl_errno = EIO; /* Default */
2463
2464 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen,
2465 &is_static, ms)) <= 0) {
2466 EI_TRACE_ERR1("recv_challenge",
2467 "<- RECV_CHALLENGE socket read failed (%d)",rlen);
2468 goto error;
2469 }
2470 s = buf;
2471 tag = get8(s);
2472 if (tag != 'n' && tag != 'N') {
2473 EI_TRACE_ERR2("recv_challenge",
2474 "<- RECV_CHALLENGE incorrect tag, "
2475 "expected 'n' or 'N', got '%c' (%u)",tag,tag);
2476 goto error;
2477 }
2478 if (tag == 'n') { /* OLD */
2479 if (rlen < 1+2+4+4) {
2480 EI_TRACE_ERR1("recv_challenge","<- RECV_CHALLENGE 'n' packet too short (%d)",
2481 rlen)
2482 goto error;
2483 }
2484
2485 version = get16be(s);
2486 if (version != EI_DIST_5) {
2487 EI_TRACE_ERR1("recv_challenge",
2488 "<- RECV_CHALLENGE 'n' incorrect version=%d",
2489 version);
2490 goto error;
2491 }
2492 *flags = get32be(s);
2493 *challenge = get32be(s);
2494 nodename_len = (buf + rlen) - s;
2495 }
2496 else { /* NEW */
2497 if (rlen < 1+8+4+4+2) {
2498 EI_TRACE_ERR1("recv_challenge","<- RECV_CHALLENGE 'N' packet too short (%d)",
2499 rlen)
2500 goto error;
2501 }
2502 version = EI_DIST_6;
2503 *flags = get64be(s);
2504 *challenge = get32be(s);
2505 s += 4; /* ignore peer 'creation' */
2506 nodename_len = get16be(s);
2507 if (nodename_len > (buf + rlen) - s) {
2508 EI_TRACE_ERR1("recv_challenge",
2509 "<- RECV_CHALLENGE 'N' nodename too long (%d)",
2510 nodename_len);
2511 goto error;
2512 }
2513 }
2514
2515 if (nodename_len > MAXNODELEN) {
2516 EI_TRACE_ERR1("recv_challenge",
2517 "<- RECV_CHALLENGE nodename too long (%d)", nodename_len);
2518 goto error;
2519 }
2520
2521 if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {
2522 EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
2523 "handle extended references");
2524 goto error;
2525 }
2526
2527 if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)) {
2528 EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
2529 "handle extended pids and ports");
2530 erl_errno = EIO;
2531 goto error;
2532 }
2533
2534 if (!(*flags & DFLAG_NEW_FLOATS)) {
2535 EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
2536 "handle binary float encoding");
2537 goto error;
2538 }
2539
2540 if (!namebuf)
2541 namebuf = &tmp_nodename[0];
2542
2543 memcpy(namebuf, s, nodename_len);
2544 namebuf[nodename_len] = '\0';
2545
2546 if (!is_static)
2547 free(buf);
2548 EI_TRACE_CONN4("recv_challenge","<- RECV_CHALLENGE (ok) node = %s, "
2549 "version = %u, "
2550 "flags = %u, "
2551 "challenge = %d",
2552 namebuf,
2553 version,
2554 *flags,
2555 *challenge
2556 );
2557 erl_errno = 0;
2558 return 0;
2559 error:
2560 if (!is_static)
2561 free(buf);
2562 return -1;
2563 }
2564
send_complement(ei_cnode * ec,void * ctx,int pkt_sz,unsigned epmd_says_version,DistFlags her_flags,unsigned ms)2565 static int send_complement(ei_cnode *ec,
2566 void *ctx,
2567 int pkt_sz,
2568 unsigned epmd_says_version,
2569 DistFlags her_flags,
2570 unsigned ms)
2571 {
2572 int ret = 0;
2573 if (epmd_says_version == EI_DIST_5 && (her_flags & DFLAG_HANDSHAKE_23)) {
2574 char *buf;
2575 unsigned char *s;
2576 char dbuf[DEFBUF_SIZ];
2577 int err;
2578 ssize_t len;
2579 unsigned int flagsHigh;
2580 const int siz = pkt_sz + 1 + 4 + 4;
2581
2582 buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
2583 if (!buf) {
2584 erl_errno = ENOMEM;
2585 return -1;
2586 }
2587 s = (unsigned char *)buf;
2588 switch (pkt_sz) {
2589 case 2:
2590 put16be(s,siz - 2);
2591 break;
2592 case 4:
2593 put32be(s,siz - 4);
2594 break;
2595 default:
2596 ret = -1;
2597 goto done;
2598 }
2599 flagsHigh = preferred_flags() >> 32;
2600
2601 put8(s, 'c');
2602 put32be(s, flagsHigh);
2603 put32be(s, ec->creation);
2604
2605 len = (ssize_t) siz;
2606 err = ei_write_fill_ctx_t__(ec->cbs, ctx, buf, &len, ms);
2607 if (!err && len != (ssize_t) siz)
2608 err = EIO;
2609 if (err) {
2610 EI_TRACE_ERR0("send_name", "SEND_NAME -> socket write failed");
2611 EI_CONN_SAVE_ERRNO__(err);
2612 ret = -1;
2613 }
2614 done:
2615 if (buf != dbuf)
2616 free(buf);
2617 }
2618 return ret;
2619 }
2620
2621
send_challenge_reply(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned char digest[16],unsigned challenge,unsigned ms)2622 static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
2623 int pkt_sz, unsigned char digest[16],
2624 unsigned challenge, unsigned ms)
2625 {
2626 char *s;
2627 char buf[DEFBUF_SIZ];
2628 int siz = pkt_sz + 1 + 4 + 16;
2629 int err;
2630 ssize_t len;
2631
2632 s = buf;
2633 switch (pkt_sz) {
2634 case 2:
2635 put16be(s,siz - 2);
2636 break;
2637 case 4:
2638 put32be(s,siz - 4);
2639 break;
2640 default:
2641 return -1;
2642 }
2643 put8(s, 'r');
2644 put32be(s, challenge);
2645 memcpy(s, digest, 16);
2646
2647 len = (ssize_t) siz;
2648 err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
2649 if (!err && len != (ssize_t) siz)
2650 err = EIO;
2651 if (err) {
2652 EI_TRACE_ERR2("send_challenge_reply",
2653 "-> SEND_CHALLENGE_REPLY socket write failed: %s (%d)",
2654 estr(err), err);
2655 EI_CONN_SAVE_ERRNO__(err);
2656 return -1;
2657 }
2658
2659 if (ei_tracelevel >= 3) {
2660 char buffer[33];
2661 EI_TRACE_CONN2("send_challenge_reply",
2662 "-> SEND_CHALLENGE_REPLY (ok) challenge = %d, digest = %s",
2663 challenge,hex((char*)digest, buffer));
2664 }
2665 return 0;
2666 }
2667
recv_complement(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned ms)2668 static int recv_complement(ei_socket_callbacks *cbs,
2669 void *ctx,
2670 int pkt_sz,
2671 unsigned ms)
2672 {
2673 char dbuf[DEFBUF_SIZ];
2674 char *buf = dbuf;
2675 int is_static = 1;
2676 int buflen = DEFBUF_SIZ;
2677 int rlen;
2678 char *s;
2679 char tag;
2680 unsigned int creation;
2681
2682 erl_errno = EIO; /* Default */
2683
2684 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 21) {
2685 EI_TRACE_ERR1("recv_complement",
2686 "<- RECV_COMPLEMENT socket read failed (%d)",rlen);
2687 goto error;
2688 }
2689
2690 s = buf;
2691 if ((tag = get8(s)) != 'c') {
2692 EI_TRACE_ERR2("recv_complement",
2693 "<- RECV_COMPLEMENT incorrect tag, "
2694 "expected 'c' got '%c' (%u)",tag,tag);
2695 goto error;
2696 }
2697 creation = get32be(s);
2698 if (!is_static)
2699 free(buf);
2700
2701 if (ei_tracelevel >= 3) {
2702 EI_TRACE_CONN1("recv_complement",
2703 "<- RECV_COMPLEMENT (ok) creation = %u",
2704 creation);
2705 }
2706 /* We don't have any use for 'creation' of other node, so we drop it */
2707 erl_errno = 0;
2708 return 0;
2709
2710 error:
2711 if (!is_static)
2712 free(buf);
2713 return -1;
2714 }
2715
recv_challenge_reply(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned our_challenge,char cookie[],unsigned * her_challenge,unsigned ms)2716 static int recv_challenge_reply(ei_socket_callbacks *cbs,
2717 void *ctx,
2718 int pkt_sz,
2719 unsigned our_challenge,
2720 char cookie[],
2721 unsigned *her_challenge,
2722 unsigned ms)
2723 {
2724 char dbuf[DEFBUF_SIZ];
2725 char *buf = dbuf;
2726 int is_static = 1;
2727 int buflen = DEFBUF_SIZ;
2728 int rlen;
2729 char *s;
2730 char tag;
2731 char her_digest[16], expected_digest[16];
2732
2733 erl_errno = EIO; /* Default */
2734
2735 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 21) {
2736 EI_TRACE_ERR1("recv_challenge_reply",
2737 "<- RECV_CHALLENGE_REPLY socket read failed (%d)",rlen);
2738 goto error;
2739 }
2740
2741 s = buf;
2742 if ((tag = get8(s)) != 'r') {
2743 EI_TRACE_ERR2("recv_challenge_reply",
2744 "<- RECV_CHALLENGE_REPLY incorrect tag, "
2745 "expected 'r' got '%c' (%u)",tag,tag);
2746 goto error;
2747 }
2748 *her_challenge = get32be(s);
2749 memcpy(her_digest, s, 16);
2750 gen_digest(our_challenge, cookie, (unsigned char*)expected_digest);
2751 if (memcmp(her_digest, expected_digest, 16)) {
2752 EI_TRACE_ERR0("recv_challenge_reply",
2753 "<- RECV_CHALLENGE_REPLY authorization failure");
2754 goto error;
2755 }
2756 if (!is_static)
2757 free(buf);
2758
2759
2760 if (ei_tracelevel >= 3) {
2761 char buffer[33];
2762 EI_TRACE_CONN2("recv_challenge_reply",
2763 "<- RECV_CHALLENGE_REPLY (ok) challenge = %u, digest = %s",
2764 *her_challenge,hex(her_digest,buffer));
2765 }
2766 erl_errno = 0;
2767 return 0;
2768
2769 error:
2770 if (!is_static)
2771 free(buf);
2772 return -1;
2773 }
2774
send_challenge_ack(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned char digest[16],unsigned ms)2775 static int send_challenge_ack(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
2776 unsigned char digest[16], unsigned ms)
2777 {
2778 char *s;
2779 char buf[DEFBUF_SIZ];
2780 int siz = pkt_sz + 1 + 16;
2781 int err;
2782 ssize_t len;
2783
2784 s = buf;
2785 switch (pkt_sz) {
2786 case 2:
2787 put16be(s,siz - 2);
2788 break;
2789 case 4:
2790 put32be(s,siz - 4);
2791 break;
2792 default:
2793 return -1;
2794 }
2795 put8(s, 'a');
2796 memcpy(s, digest, 16);
2797
2798 len = (ssize_t) siz;
2799 err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
2800 if (!err && len != (ssize_t) siz)
2801 err = EIO;
2802 if (err) {
2803 EI_TRACE_ERR2("recv_challenge_reply",
2804 "-> SEND_CHALLENGE_ACK socket write failed: %s (%d)",
2805 estr(err), err);
2806 EI_CONN_SAVE_ERRNO__(err);
2807 return -1;
2808 }
2809
2810 if (ei_tracelevel >= 3) {
2811 char buffer[33];
2812 EI_TRACE_CONN1("recv_challenge_reply",
2813 "-> SEND_CHALLENGE_ACK (ok) digest = %s",hex((char *)digest,buffer));
2814 }
2815
2816 return 0;
2817 }
2818
recv_challenge_ack(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned our_challenge,char cookie[],unsigned ms)2819 static int recv_challenge_ack(ei_socket_callbacks *cbs, void *ctx,
2820 int pkt_sz, unsigned our_challenge,
2821 char cookie[], unsigned ms)
2822 {
2823 char dbuf[DEFBUF_SIZ];
2824 char *buf = dbuf;
2825 int is_static = 1;
2826 int buflen = DEFBUF_SIZ;
2827 int rlen;
2828 char *s;
2829 char tag;
2830 char her_digest[16], expected_digest[16];
2831
2832 erl_errno = EIO; /* Default */
2833
2834 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 17) {
2835 EI_TRACE_ERR1("recv_challenge_ack",
2836 "<- RECV_CHALLENGE_ACK socket read failed (%d)",rlen);
2837 goto error;
2838 }
2839
2840 s = buf;
2841 if ((tag = get8(s)) != 'a') {
2842 EI_TRACE_ERR2("recv_challenge_ack",
2843 "<- RECV_CHALLENGE_ACK incorrect tag, "
2844 "expected 'a' got '%c' (%u)",tag,tag);
2845 goto error;
2846 }
2847 memcpy(her_digest, s, 16);
2848 gen_digest(our_challenge, cookie, (unsigned char *)expected_digest);
2849 if (memcmp(her_digest, expected_digest, 16)) {
2850 EI_TRACE_ERR0("recv_challenge_ack",
2851 "<- RECV_CHALLENGE_ACK authorization failure");
2852 goto error;
2853 }
2854 if (!is_static)
2855 free(buf);
2856
2857 if (ei_tracelevel >= 3) {
2858 char buffer[33];
2859 EI_TRACE_CONN1("recv_challenge_ack",
2860 "<- RECV_CHALLENGE_ACK (ok) digest = %s",hex(her_digest,buffer));
2861 }
2862 erl_errno = 0;
2863 return 0;
2864
2865 error:
2866 if (!is_static)
2867 free(buf);
2868 return -1;
2869 }
2870
recv_name(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,char * send_name_tag,DistFlags * flags,char * namebuf,unsigned ms)2871 static int recv_name(ei_socket_callbacks *cbs, void *ctx,
2872 int pkt_sz, char *send_name_tag,
2873 DistFlags *flags, char *namebuf, unsigned ms)
2874 {
2875 char dbuf[DEFBUF_SIZ];
2876 char *buf = dbuf;
2877 int is_static = 1;
2878 int buflen = DEFBUF_SIZ;
2879 int rlen;
2880 unsigned int namelen;
2881 char *s;
2882 char tmp_nodename[MAXNODELEN+1];
2883 char tag;
2884
2885 erl_errno = EIO; /* Default */
2886
2887 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen,
2888 &is_static, ms)) <= 0) {
2889 EI_TRACE_ERR1("recv_name","<- RECV_NAME socket read failed (%d)",rlen);
2890 goto error;
2891 }
2892 s = buf;
2893 tag = get8(s);
2894 *send_name_tag = tag;
2895 if (tag != 'n' && tag != 'N') {
2896 EI_TRACE_ERR2("recv_name","<- RECV_NAME incorrect tag, "
2897 "expected 'n' or 'N', got '%c' (%u)",tag,tag);
2898 goto error;
2899 }
2900 if (tag == 'n') {
2901 unsigned int version;
2902 if (rlen < 1+2+4) {
2903 EI_TRACE_ERR1("recv_name","<- RECV_NAME 'n' packet too short (%d)",
2904 rlen)
2905 goto error;
2906 }
2907 version = get16be(s);
2908 if (version < EI_DIST_5) {
2909 EI_TRACE_ERR1("recv_name","<- RECV_NAME 'n' invalid version=%d",
2910 version)
2911 goto error;
2912 }
2913 *flags = get32be(s);
2914 namelen = rlen - (1+2+4);
2915 }
2916 else { /* tag == 'N' */
2917 if (rlen < 1+8+4+2) {
2918 EI_TRACE_ERR1("recv_name","<- RECV_NAME 'N' packet too short (%d)",
2919 rlen)
2920 goto error;
2921 }
2922 *flags = get64be(s);
2923 s += 4; /* ignore peer 'creation' */
2924 namelen = get16be(s);
2925 }
2926
2927 if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {
2928 EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot handle"
2929 "extended references");
2930 goto error;
2931 }
2932
2933 if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)) {
2934 EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot "
2935 "handle extended pids and ports");
2936 erl_errno = EIO;
2937 goto error;
2938 }
2939
2940 if (!namebuf)
2941 namebuf = &tmp_nodename[0];
2942
2943 if (namelen > MAXNODELEN || s+namelen > buf+rlen) {
2944 EI_TRACE_ERR2("recv_name","<- RECV_NAME '%c' nodename too long (%d)",
2945 tag, namelen);
2946 goto error;
2947 }
2948
2949 memcpy(namebuf, s, namelen);
2950 namebuf[namelen] = '\0';
2951
2952 if (!is_static)
2953 free(buf);
2954 EI_TRACE_CONN3("recv_name",
2955 "<- RECV_NAME (ok) node = %s, tag = %c, flags = %u",
2956 namebuf,tag,*flags);
2957 erl_errno = 0;
2958 return 0;
2959
2960 error:
2961 if (!is_static)
2962 free(buf);
2963 return -1;
2964 }
2965
2966 /***************************************************************************
2967 *
2968 * Returns 1 on success and 0 on failure.
2969 *
2970 ***************************************************************************/
2971
2972
2973 /* size is the buffer size, e.i. string length + 1 */
2974
get_home(char * buf,int size)2975 static int get_home(char *buf, int size)
2976 {
2977 #ifdef __WIN32__
2978 char* homedrive = getenv("HOMEDRIVE");
2979 char* homepath = getenv("HOMEPATH");
2980
2981 if (homedrive && homepath) {
2982 if (strlen(homedrive)+strlen(homepath) >= size)
2983 return 0;
2984 strcpy(buf, homedrive);
2985 strcat(buf, homepath);
2986 return 1;
2987 }
2988 else {
2989 int len = GetWindowsDirectory(buf, size);
2990 if (len) {
2991 return (len < size);
2992 }
2993 }
2994 #else
2995 char* homepath = getenv("HOME");
2996 if (homepath) {
2997 if (strlen(homepath) >= size)
2998 return 0;
2999 strcpy(buf, homepath);
3000 return 1;
3001 }
3002 #endif
3003
3004 buf[0] = '.';
3005 buf[1] = '\0';
3006 return 1;
3007 }
3008
3009
get_cookie(char * buf,int bufsize)3010 static int get_cookie(char *buf, int bufsize)
3011 {
3012 char fname[EI_MAX_HOME_PATH + sizeof(COOKIE_FILE) + 1];
3013 int fd;
3014 int len;
3015 unsigned char next_c;
3016
3017 if (!get_home(fname, EI_MAX_HOME_PATH+1)) {
3018 fprintf(stderr,"<ERROR> get_cookie: too long path to home");
3019 return 0;
3020 }
3021
3022 strcat(fname, COOKIE_FILE);
3023 if ((fd = open(fname, O_RDONLY, 0777)) < 0) {
3024 fprintf(stderr,"<ERROR> get_cookie: can't open cookie file");
3025 return 0;
3026 }
3027
3028 if ((len = read(fd, buf, bufsize-1)) < 0) {
3029 fprintf(stderr,"<ERROR> get_cookie: reading cookie file");
3030 close(fd);
3031 return 0;
3032 }
3033
3034 /* If more to read it is too long. Not 100% correct test but will do. */
3035 if (read(fd, &next_c, 1) > 0 && !isspace(next_c)) {
3036 fprintf(stderr,"<ERROR> get_cookie: cookie in %s is too long",fname);
3037 close(fd);
3038 return 0;
3039 }
3040
3041 close(fd);
3042
3043 /* Remove all newlines after the first newline */
3044 buf[len] = '\0'; /* Terminate string */
3045 len = strcspn(buf,"\r\n");
3046 buf[len] = '\0'; /* Terminate string again */
3047
3048 return 1; /* Success! */
3049 }
3050
3051