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, unsigned *version,
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 char *
estr(int e)147 estr(int e)
148 {
149 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
774 ref_count[0]++;
775 ref_count[0] &= 0x3ffff;
776 if (ref_count[0] == 0) {
777 ref_count[1]++;
778 ref_count[1] &= 0xffffffff;
779 if (ref_count[1] == 0) {
780 ref_count[2]++;
781 ref_count[2] &= 0xffffffff;
782 }
783 }
784
785 #ifdef _REENTRANT
786 ei_mutex_unlock(ref_mtx);
787 #endif
788
789 #endif /* !EI_MAKE_REF_ATOMIC__ */
790
791 return 0;
792 }
793
794 /* two internal functions that will let us support different cookies
795 * (to be able to connect to other nodes that don't have the same
796 * cookie as each other or us)
797 */
ei_getfdcookie(int fd)798 const char *ei_getfdcookie(int fd)
799 {
800 const char* r = ei_cookie(fd);
801 if (r == NULL) r = "";
802 return r;
803 }
804
get_int32(unsigned char * s)805 static int get_int32(unsigned char *s)
806 {
807 return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] ));
808 }
809
810
811 #ifdef __WIN32__
win32_error(char * buf,int buflen)812 void win32_error(char *buf, int buflen)
813 {
814 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
815 0, /* n/a */
816 WSAGetLastError(), /* error code */
817 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* language */
818 buf,
819 buflen,
820 NULL);
821 return;
822 }
823
initWinSock(void)824 static int initWinSock(void)
825 {
826 WORD wVersionRequested;
827 WSADATA wsaData;
828 int i;
829
830 static LONG volatile initialized = 0;
831
832 wVersionRequested = MAKEWORD(1, 1);
833 if (InterlockedCompareExchange((LPLONG) &initialized,1L,0L) == 0L) {
834 /* FIXME not terminate, just a message?! */
835 if ((i = WSAStartup(wVersionRequested, &wsaData))) {
836 EI_TRACE_ERR1("ei_connect_init",
837 "ERROR: can't initialize windows sockets: %d",i);
838 initialized = 2L;
839 return 0;
840 }
841
842 if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
843 EI_TRACE_ERR0("initWinSock","ERROR: this version of windows "
844 "sockets not supported");
845 WSACleanup();
846 initialized = 2L;
847 return 0;
848 }
849 initialized = 3L;
850 } else while (initialized < 2) {
851 SwitchToThread();
852 }
853 return (int) (initialized - 2);
854 }
855 #endif
856
init_connect(int late)857 static int init_connect(int late)
858 {
859 int error;
860
861 /*
862 * 'late' is non-zero when not called via ei_init(). Such a
863 * call is not supported, but we for now save the day if
864 * it easy to do so; otherwise, return ENOTSUP.
865 */
866
867 #ifdef __WIN32__
868 if (!initWinSock()) {
869 EI_TRACE_ERR0("ei_init_connect","can't initiate winsock");
870 return EIO;
871 }
872 #endif /* win32 */
873
874 error = init_socket_info(late);
875 if (error) {
876 EI_TRACE_ERR0("ei_init_connect","can't initiate socket info");
877 return error;
878 }
879
880 error = init_make_ref(late);
881 if (error) {
882 EI_TRACE_ERR0("ei_init_connect","can't initiate ei_make_ref()");
883 return error;
884 }
885
886 error = init_make_pid(late);
887 if (error) {
888 EI_TRACE_ERR0("ei_init_connect","can't initiate ei_make_pid()");
889 return error;
890 }
891
892 ei_connect_initialized = !0;
893 return 0;
894 }
895
ei_init_connect(void)896 int ei_init_connect(void)
897 {
898 return init_connect(0);
899 }
900
901 /*
902 * Perhaps run this routine instead of ei_connect_init/2 ?
903 * Initailize by setting:
904 * thishostname, thisalivename, thisnodename and thisipaddr
905 */
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)906 int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname,
907 const char *thisalivename, const char *thisnodename,
908 Erl_IpAddr thisipaddr, const char *cookie,
909 const short creation, ei_socket_callbacks *cbs,
910 int cbs_sz, void *setup_context)
911 {
912 char *dbglevel;
913
914 if (!ei_connect_initialized)
915 init_connect(!0);
916
917 if (cbs != &ei_default_socket_callbacks)
918 EI_SET_HAVE_PLUGIN_SOCKET_IMPL__;
919
920 if (cbs_sz < EI_SOCKET_CALLBACKS_SZ_V1) {
921 EI_TRACE_ERR0("ei_connect_xinit","invalid size of ei_socket_callbacks struct");
922 return ERL_ERROR;
923 }
924
925 ec->creation = creation;
926 ec->pidsn = 0;
927
928 if (cookie) {
929 if (strlen(cookie) >= sizeof(ec->ei_connect_cookie)) {
930 EI_TRACE_ERR0("ei_connect_xinit",
931 "ERROR: Cookie size too large");
932 return ERL_ERROR;
933 } else {
934 strcpy(ec->ei_connect_cookie, cookie);
935 }
936 } else if (!get_cookie(ec->ei_connect_cookie, sizeof(ec->ei_connect_cookie))) {
937 return ERL_ERROR;
938 }
939
940 if (strlen(thishostname) >= sizeof(ec->thishostname)) {
941 EI_TRACE_ERR0("ei_connect_xinit","ERROR: Thishostname too long");
942 return ERL_ERROR;
943 }
944 strcpy(ec->thishostname, thishostname);
945
946 if (thisalivename) {
947 if (strlen(thisalivename) >= sizeof(ec->thisalivename)) {
948 EI_TRACE_ERR0("ei_connect_init","Thisalivename too long");
949 return ERL_ERROR;
950 }
951
952 strcpy(ec->thisalivename, thisalivename);
953
954 if (strlen(thisnodename) >= sizeof(ec->thisnodename)) {
955 EI_TRACE_ERR0("ei_connect_init","Thisnodename too long");
956 return ERL_ERROR;
957 }
958 strcpy(ec->thisnodename, thisnodename);
959
960 strcpy(ec->self.node, thisnodename);
961 ec->self.num = 0;
962 ec->self.serial = 0;
963 ec->self.creation = creation;
964 }
965 else {
966 /* dynamic name */
967 ec->thisalivename[0] = 0;
968 ec->thisnodename[0] = 0;
969 }
970
971 /* FIXME right now this_ipaddr is never used */
972 /* memmove(&ec->this_ipaddr, thisipaddr, sizeof(ec->this_ipaddr)); */
973
974
975 ec->cbs = cbs;
976 ec->setup_context = setup_context;
977
978 if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL ||
979 (dbglevel = getenv("ERL_DEBUG_DIST")) != NULL)
980 ei_tracelevel = atoi(dbglevel);
981
982 return 0;
983 }
984
ei_connect_xinit(ei_cnode * ec,const char * thishostname,const char * thisalivename,const char * thisnodename,Erl_IpAddr thisipaddr,const char * cookie,const short creation)985 int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
986 const char *thisalivename, const char *thisnodename,
987 Erl_IpAddr thisipaddr, const char *cookie,
988 const short creation)
989 {
990 return ei_connect_xinit_ussi(ec, thishostname, thisalivename, thisnodename,
991 thisipaddr, cookie, creation,
992 &ei_default_socket_callbacks,
993 sizeof(ei_default_socket_callbacks),
994 NULL);
995 }
996
997 /*
998 * Initialize by set: thishostname, thisalivename,
999 * thisnodename and thisipaddr. At success return 0,
1000 * otherwise return -1.
1001 */
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)1002 int ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name,
1003 const char *cookie, short creation,
1004 ei_socket_callbacks *cbs, int cbs_sz,
1005 void *setup_context)
1006 {
1007 char thishostname[EI_MAXHOSTNAMELEN+1];
1008 char thisnodename[MAXNODELEN+1];
1009 char thisalivename[EI_MAXALIVELEN+1];
1010 struct hostent host, *hp;
1011 char buffer[1024];
1012 char *buf = buffer;
1013 int ei_h_errno;
1014 int res;
1015
1016 if (!ei_connect_initialized)
1017 init_connect(!0);
1018
1019 /* gethostname requires len to be max(hostname) + 1 */
1020 if (gethostname(thishostname, EI_MAXHOSTNAMELEN+1) == -1) {
1021 #ifdef __WIN32__
1022 EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d",
1023 WSAGetLastError());
1024 #else
1025 EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d", errno);
1026 #endif /* win32 */
1027 return ERL_ERROR;
1028 }
1029
1030 if (this_node_name == NULL) {
1031 sprintf(thisalivename, "c%d", (int) getpid());
1032 } else 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, &her_version,
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 * The RPC consists of two parts, send and receive.
1856 * Here is the send part !
1857 * { PidFrom, { call, Mod, Fun, Args, user }}
1858 */
1859 /*
1860 * Now returns non-negative number for success, negative for failure.
1861 */
ei_rpc_to(ei_cnode * ec,int fd,char * mod,char * fun,const char * buf,int len)1862 int ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun,
1863 const char *buf, int len)
1864 {
1865
1866 ei_x_buff x;
1867 erlang_pid *self = ei_self(ec);
1868 int err = ERL_ERROR;
1869
1870 /* encode header */
1871 if (ei_x_new_with_version(&x) < 0)
1872 goto einval;
1873 if (ei_x_encode_tuple_header(&x, 2) < 0) /* A */
1874 goto einval;
1875
1876 if (ei_x_encode_pid(&x, self) < 0) /* A 1 */
1877 goto einval;
1878
1879 if (ei_x_encode_tuple_header(&x, 5) < 0) /* B A 2 */
1880 goto einval;
1881 if (ei_x_encode_atom(&x, "call") < 0) /* B 1 */
1882 goto einval;
1883 if (ei_x_encode_atom(&x, mod) < 0) /* B 2 */
1884 goto einval;
1885 if (ei_x_encode_atom(&x, fun) < 0) /* B 3 */
1886 goto einval;
1887 if (ei_x_append_buf(&x, buf, len) < 0) /* B 4 */
1888 goto einval;
1889 if (ei_x_encode_atom(&x, "user") < 0) /* B 5 */
1890 goto einval;
1891
1892 err = ei_send_reg_encoded(fd, self, "rex", x.buff, x.index);
1893 if (err)
1894 goto error;
1895
1896 ei_x_free(&x);
1897
1898 return 0;
1899
1900 einval:
1901 EI_CONN_SAVE_ERRNO__(EINVAL);
1902
1903 error:
1904 if (x.buff != NULL)
1905 ei_x_free(&x);
1906 return err;
1907 } /* rpc_to */
1908
1909 /*
1910 * And here is the rpc receiving part. A negative
1911 * timeout means 'infinity'. Returns either of: ERL_MSG,
1912 * ERL_TICK, ERL_ERROR or ERL_TIMEOUT.
1913 */
ei_rpc_from(ei_cnode * ec,int fd,int timeout,erlang_msg * msg,ei_x_buff * x)1914 int ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg,
1915 ei_x_buff *x)
1916 {
1917 unsigned tmo = timeout < 0 ? EI_SCLBK_INF_TMO : (unsigned) timeout;
1918 int res = ei_xreceive_msg_tmo(fd, msg, x, tmo);
1919 if (res < 0 && erl_errno == ETIMEDOUT)
1920 return ERL_TIMEOUT;
1921 return res;
1922 } /* rpc_from */
1923
ei_rpc(ei_cnode * ec,int fd,char * mod,char * fun,const char * inbuf,int inbuflen,ei_x_buff * x)1924 int ei_rpc(ei_cnode* ec, int fd, char *mod, char *fun,
1925 const char* inbuf, int inbuflen, ei_x_buff* x)
1926 {
1927 int i, index;
1928 ei_term t;
1929 erlang_msg msg;
1930 char rex[MAXATOMLEN];
1931
1932 if (ei_rpc_to(ec, fd, mod, fun, inbuf, inbuflen) < 0) {
1933 return ERL_ERROR;
1934 }
1935
1936 /* ei_rpc_from() responds with a tick if it gets one... */
1937 while ((i = ei_rpc_from(ec, fd, ERL_NO_TIMEOUT, &msg, x)) == ERL_TICK)
1938 ;
1939
1940 if (i == ERL_ERROR) return i;
1941
1942 /* Expect: {rex, RPC_Reply} */
1943
1944 index = 0;
1945 if (ei_decode_version(x->buff, &index, &i) < 0)
1946 goto ebadmsg;
1947
1948 if (ei_decode_ei_term(x->buff, &index, &t) < 0)
1949 goto ebadmsg;
1950
1951 if (t.ei_type != ERL_SMALL_TUPLE_EXT && t.ei_type != ERL_LARGE_TUPLE_EXT)
1952 goto ebadmsg;
1953
1954 if (t.arity != 2)
1955 goto ebadmsg;
1956
1957 if (ei_decode_atom(x->buff, &index, rex) < 0)
1958 goto ebadmsg;
1959
1960 if (strcmp("rex", rex) != 0)
1961 goto ebadmsg;
1962
1963 /* remove header */
1964 x->index -= index;
1965 memmove(x->buff, &x->buff[index], x->index);
1966 return 0;
1967
1968 ebadmsg:
1969
1970 EI_CONN_SAVE_ERRNO__(EBADMSG);
1971 return ERL_ERROR;
1972 }
1973
1974
1975 /*
1976 ** Handshake
1977 */
1978
1979
1980 /* FROM RTP RFC 1889 (except that we use all bits, bug in RFC?) */
md_32(char * string,int length)1981 static unsigned int md_32(char* string, int length)
1982 {
1983 MD5_CTX ctx;
1984 union {
1985 char c[16];
1986 unsigned x[4];
1987 } digest;
1988 ei_MD5Init(&ctx);
1989 ei_MD5Update(&ctx, (unsigned char *) string,
1990 (unsigned) length);
1991 ei_MD5Final((unsigned char *) digest.c, &ctx);
1992 return (digest.x[0] ^ digest.x[1] ^ digest.x[2] ^ digest.x[3]);
1993 }
1994
1995 #if defined(__WIN32__)
gen_challenge(void)1996 unsigned int gen_challenge(void)
1997 {
1998 struct {
1999 SYSTEMTIME tv;
2000 DWORD cpu;
2001 int pid;
2002 } s;
2003 GetSystemTime(&s.tv);
2004 s.cpu = GetTickCount();
2005 s.pid = getpid();
2006 return md_32((char*) &s, sizeof(s));
2007 }
2008
2009 #else /* some unix */
2010
gen_challenge(void)2011 static unsigned int gen_challenge(void)
2012 {
2013 struct {
2014 struct timeval tv;
2015 clock_t cpu;
2016 pid_t pid;
2017 u_long hid;
2018 uid_t uid;
2019 gid_t gid;
2020 struct utsname name;
2021 } s;
2022
2023 memset(&s, 0, sizeof(s));
2024 gettimeofday(&s.tv, 0);
2025 uname(&s.name);
2026 s.cpu = clock();
2027 s.pid = getpid();
2028 #if defined(__ANDROID__) || defined(__HAIKU__)
2029 s.hid = 0;
2030 #else
2031 s.hid = gethostid();
2032 #endif
2033 s.uid = getuid();
2034 s.gid = getgid();
2035
2036 return md_32((char*) &s, sizeof(s));
2037 }
2038 #endif
2039
gen_digest(unsigned challenge,char cookie[],unsigned char digest[16])2040 static void gen_digest(unsigned challenge, char cookie[],
2041 unsigned char digest[16])
2042 {
2043 MD5_CTX c;
2044
2045 char chbuf[21];
2046
2047 sprintf(chbuf,"%u", challenge);
2048 ei_MD5Init(&c);
2049 ei_MD5Update(&c, (unsigned char *) cookie,
2050 (unsigned) strlen(cookie));
2051 ei_MD5Update(&c, (unsigned char *) chbuf,
2052 (unsigned) strlen(chbuf));
2053 ei_MD5Final(digest, &c);
2054 }
2055
2056
hex(char digest[16],char buff[33])2057 static char *hex(char digest[16], char buff[33])
2058 {
2059 static char tab[] = "0123456789abcdef";
2060 unsigned char *d = (unsigned char *) digest;
2061 //static char buff[sizeof(digest)*2 + 1];
2062 char *p = buff;
2063 int i;
2064
2065 for (i = 0; i < 16; ++i) {
2066 *p++ = tab[(int)((*d) >> 4)];
2067 *p++ = tab[(int)((*d++) & 0xF)];
2068 }
2069 *p = '\0';
2070 return buff;
2071 }
2072
read_hs_package(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,char ** buf,int * buflen,int * is_static,unsigned ms)2073 static int read_hs_package(ei_socket_callbacks *cbs, void *ctx,
2074 int pkt_sz, char **buf, int *buflen,
2075 int *is_static, unsigned ms)
2076 {
2077 unsigned char nbuf[4];
2078 unsigned char *x = nbuf;
2079 ssize_t len, need;
2080 int err;
2081
2082 len = (ssize_t) pkt_sz;
2083 err = ei_read_fill_ctx_t__(cbs, ctx, (char *)nbuf, &len, ms);
2084 if (!err && len != (ssize_t) pkt_sz)
2085 err = EIO;
2086 if (err) {
2087 EI_CONN_SAVE_ERRNO__(err);
2088 return -1;
2089 }
2090
2091 switch (pkt_sz) {
2092 case 2:
2093 len = get16be(x);
2094 break;
2095 case 4:
2096 len = get32be(x);
2097 break;
2098 default:
2099 return -1;
2100 }
2101
2102 if (len > *buflen) {
2103 if (*is_static) {
2104 char *tmp = malloc(len);
2105 if (!tmp) {
2106 erl_errno = ENOMEM;
2107 return -1;
2108 }
2109 *buf = tmp;
2110 *is_static = 0;
2111 *buflen = len;
2112 } else {
2113 char *tmp = realloc(*buf, len);
2114 if (!tmp) {
2115 erl_errno = ENOMEM;
2116 return -1;
2117 }
2118 *buf = tmp;
2119 *buflen = len;
2120 }
2121 }
2122 need = len;
2123 err = ei_read_fill_ctx_t__(cbs, ctx, *buf, &len, ms);
2124 if (!err && len != need)
2125 err = EIO;
2126 if (err) {
2127 EI_CONN_SAVE_ERRNO__(err);
2128 return -1;
2129 }
2130 return len;
2131 }
2132
2133
send_status(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,char * status,unsigned ms)2134 static int send_status(ei_socket_callbacks *cbs, void *ctx,
2135 int pkt_sz, char *status, unsigned ms)
2136 {
2137 char *buf, *s;
2138 char dbuf[DEFBUF_SIZ];
2139 int siz = strlen(status) + 1 + pkt_sz;
2140 int err;
2141 ssize_t len;
2142
2143 buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
2144 if (!buf) {
2145 erl_errno = ENOMEM;
2146 return -1;
2147 }
2148 s = buf;
2149 switch (pkt_sz) {
2150 case 2:
2151 put16be(s,siz - 2);
2152 break;
2153 case 4:
2154 put32be(s,siz - 4);
2155 break;
2156 default:
2157 return -1;
2158 }
2159 put8(s, 's');
2160 memcpy(s, status, strlen(status));
2161 len = (ssize_t) siz;
2162 err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
2163 if (!err && len != (ssize_t) siz)
2164 err = EIO;
2165 if (err) {
2166 EI_TRACE_ERR2("send_status","-> SEND_STATUS socket write failed: %s (%d)",
2167 estr(err), err);
2168 if (buf != dbuf)
2169 free(buf);
2170 EI_CONN_SAVE_ERRNO__(err);
2171 return -1;
2172 }
2173 EI_TRACE_CONN1("send_status","-> SEND_STATUS (%s)",status);
2174
2175 if (buf != dbuf)
2176 free(buf);
2177 return 0;
2178 }
2179
recv_status(ei_cnode * ec,void * ctx,int pkt_sz,unsigned ms)2180 static int recv_status(ei_cnode *ec, void *ctx,
2181 int pkt_sz, unsigned ms)
2182 {
2183 char dbuf[DEFBUF_SIZ];
2184 char *buf = dbuf;
2185 int is_static = 1;
2186 int buflen = DEFBUF_SIZ;
2187 int rlen;
2188
2189 if ((rlen = read_hs_package(ec->cbs, ctx, pkt_sz,
2190 &buf, &buflen, &is_static, ms)) <= 0) {
2191 EI_TRACE_ERR1("recv_status",
2192 "<- RECV_STATUS socket read failed (%d)", rlen);
2193 goto error;
2194 }
2195
2196 EI_TRACE_CONN2("recv_status",
2197 "<- RECV_STATUS (%.*s)", (rlen>20 ? 20 : rlen), buf);
2198
2199 if (ec->thisnodename[0]) {
2200 if (rlen >= 3 && buf[0] == 's' && buf[1] == 'o' && buf[2] == 'k') {
2201 /* Expecting "sok" or "sok_simultaneous" */
2202 if (!is_static)
2203 free(buf);
2204 return 0;
2205 }
2206 }
2207 else { /* dynamic node name */
2208 const char* at;
2209 int namelen;
2210 if (rlen >= 7 && strncmp(buf, "snamed:", 7) == 0) {
2211 buf += 7;
2212 rlen -= 7;
2213 namelen = get16be(buf);
2214 rlen -= 2;
2215 if (namelen > MAXNODELEN || (namelen+4) > rlen) {
2216 EI_TRACE_ERR1("recv_status","<- RECV_STATUS nodename too long (%d)",
2217 namelen);
2218 goto error;
2219 }
2220 memcpy(ec->thisnodename, buf, namelen);
2221 ec->thisnodename[namelen] = '\0';
2222 buf += namelen;
2223 ec->creation = get32be(buf);
2224
2225 /* extract alive part from nodename */
2226 if (!(at = strchr(ec->thisnodename,'@'))) {
2227 EI_TRACE_ERR0("ei_connect","Dynamic node name has no @ in name");
2228 return ERL_ERROR;
2229 } else {
2230 const int alen = at - ec->thisnodename;
2231 strncpy(ec->thisalivename, ec->thisnodename, alen);
2232 ec->thisalivename[alen] = '\0';
2233 }
2234
2235 strcpy(ec->self.node, ec->thisnodename);
2236 ec->self.num = 0;
2237 ec->self.serial = 0;
2238 ec->self.creation = ec->creation;
2239 return 0;
2240 }
2241 }
2242 error:
2243 if (!is_static)
2244 free(buf);
2245 return -1;
2246 }
2247
preferred_flags(void)2248 static DistFlags preferred_flags(void)
2249 {
2250 DistFlags flags =
2251 DFLAG_EXTENDED_REFERENCES
2252 | DFLAG_DIST_MONITOR
2253 | DFLAG_EXTENDED_PIDS_PORTS
2254 | DFLAG_FUN_TAGS
2255 | DFLAG_NEW_FUN_TAGS
2256 | DFLAG_NEW_FLOATS
2257 | DFLAG_SMALL_ATOM_TAGS
2258 | DFLAG_UTF8_ATOMS
2259 | DFLAG_MAP_TAG
2260 | DFLAG_BIG_CREATION
2261 | DFLAG_EXPORT_PTR_TAG
2262 | DFLAG_BIT_BINARIES
2263 | DFLAG_HANDSHAKE_23;
2264 if (ei_internal_use_21_bitstr_expfun()) {
2265 flags &= ~(DFLAG_EXPORT_PTR_TAG
2266 | DFLAG_BIT_BINARIES);
2267 }
2268 return flags;
2269 }
2270
send_name(ei_cnode * ec,void * ctx,int pkt_sz,unsigned version,unsigned ms)2271 static int send_name(ei_cnode *ec,
2272 void *ctx,
2273 int pkt_sz,
2274 unsigned version,
2275 unsigned ms)
2276 {
2277 char *buf;
2278 unsigned char *s;
2279 char dbuf[DEFBUF_SIZ];
2280 const char* name_ptr;
2281 unsigned int name_len;
2282 int siz;
2283 int err;
2284 ssize_t len;
2285 DistFlags flags = preferred_flags();
2286 char tag;
2287
2288 if (ec->thisnodename[0]) {
2289 name_ptr = ec->thisnodename;
2290 tag = (version == EI_DIST_5) ? 'n' : 'N';
2291 }
2292 else {
2293 /* dynamic node name */
2294 name_ptr = ec->thishostname;
2295 tag = 'N'; /* presume ver 6 */
2296 flags |= DFLAG_NAME_ME;
2297 }
2298
2299 name_len = strlen(name_ptr);
2300
2301 if (tag == 'n')
2302 siz = pkt_sz + 1 + 2 + 4 + name_len;
2303 else
2304 siz = pkt_sz + 1 + 8 + 4 + 2 + name_len;
2305
2306 buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
2307 if (!buf) {
2308 erl_errno = ENOMEM;
2309 return -1;
2310 }
2311 s = (unsigned char *)buf;
2312 switch (pkt_sz) {
2313 case 2:
2314 put16be(s,siz - 2);
2315 break;
2316 case 4:
2317 put32be(s,siz - 4);
2318 break;
2319 default:
2320 return -1;
2321 }
2322
2323 put8(s, tag);
2324 if (tag == 'n') {
2325 put16be(s, EI_DIST_5); /* some impl (jinterface) demand ver==5 */
2326 put32be(s, flags);
2327 }
2328 else { /* tag == 'N' */
2329 put64be(s, flags);
2330 put32be(s, ec->creation);
2331 put16be(s, name_len);
2332 }
2333 memcpy(s, name_ptr, name_len);
2334 len = (ssize_t) siz;
2335 err = ei_write_fill_ctx_t__(ec->cbs, ctx, buf, &len, ms);
2336 if (!err && len != (ssize_t) siz)
2337 err = EIO;
2338 if (err) {
2339 EI_TRACE_ERR0("send_name", "SEND_NAME -> socket write failed");
2340 if (buf != dbuf)
2341 free(buf);
2342 EI_CONN_SAVE_ERRNO__(err);
2343 return -1;
2344 }
2345
2346 if (buf != dbuf)
2347 free(buf);
2348 return 0;
2349 }
2350
send_challenge(ei_cnode * ec,void * ctx,int pkt_sz,unsigned challenge,DistFlags her_flags,unsigned ms)2351 static int send_challenge(ei_cnode *ec,
2352 void *ctx,
2353 int pkt_sz,
2354 unsigned challenge,
2355 DistFlags her_flags,
2356 unsigned ms)
2357 {
2358 char *buf;
2359 unsigned char *s;
2360 char dbuf[DEFBUF_SIZ];
2361 const unsigned int nodename_len = strlen(ec->thisnodename);
2362 int siz;
2363 int err;
2364 ssize_t len;
2365 DistFlags flags;
2366 const char tag = (her_flags & DFLAG_HANDSHAKE_23) ? 'N' : 'n';
2367
2368 if (tag == 'n')
2369 siz = pkt_sz + 1 + 2 + 4 + 4 + nodename_len;
2370 else
2371 siz = pkt_sz + 1 + 8 + 4 + 4 + 2 + nodename_len;
2372
2373 buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
2374 if (!buf) {
2375 erl_errno = ENOMEM;
2376 return -1;
2377 }
2378 s = (unsigned char *)buf;
2379 switch (pkt_sz) {
2380 case 2:
2381 put16be(s,siz - 2);
2382 break;
2383 case 4:
2384 put32be(s,siz - 4);
2385 break;
2386 default:
2387 return -1;
2388 }
2389
2390 flags = preferred_flags();
2391 put8(s, tag);
2392 if (tag == 'n') {
2393 put16be(s, EI_DIST_5); /* choosen version */
2394 put32be(s, flags);
2395 put32be(s, challenge);
2396 }
2397 else {
2398 put64be(s, flags);
2399 put32be(s, challenge);
2400 put32be(s, ec->creation);
2401 put16be(s, nodename_len);
2402 }
2403 memcpy(s, ec->thisnodename, nodename_len);
2404 len = (ssize_t) siz;
2405 err = ei_write_fill_ctx_t__(ec->cbs, ctx, buf, &len, ms);
2406 if (!err && len != (ssize_t) siz)
2407 err = EIO;
2408 if (err) {
2409 EI_TRACE_ERR0("send_challenge", "-> SEND_CHALLENGE socket write failed");
2410 if (buf != dbuf)
2411 free(buf);
2412 EI_CONN_SAVE_ERRNO__(err);
2413 return -1;
2414 }
2415
2416 if (buf != dbuf)
2417 free(buf);
2418 return 0;
2419 }
2420
recv_challenge(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned * challenge,unsigned * version,DistFlags * flags,char * namebuf,unsigned ms)2421 static int recv_challenge(ei_socket_callbacks *cbs, void *ctx,
2422 int pkt_sz, unsigned *challenge, unsigned *version,
2423 DistFlags *flags, char *namebuf, unsigned ms)
2424 {
2425 char dbuf[DEFBUF_SIZ];
2426 char *buf = dbuf;
2427 int is_static = 1;
2428 int buflen = DEFBUF_SIZ;
2429 int rlen, nodename_len;
2430 char *s;
2431 char tag;
2432 char tmp_nodename[MAXNODELEN+1];
2433
2434 erl_errno = EIO; /* Default */
2435
2436 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen,
2437 &is_static, ms)) <= 0) {
2438 EI_TRACE_ERR1("recv_challenge",
2439 "<- RECV_CHALLENGE socket read failed (%d)",rlen);
2440 goto error;
2441 }
2442 s = buf;
2443 tag = get8(s);
2444 if (tag != 'n' && tag != 'N') {
2445 EI_TRACE_ERR2("recv_challenge",
2446 "<- RECV_CHALLENGE incorrect tag, "
2447 "expected 'n' or 'N', got '%c' (%u)",tag,tag);
2448 goto error;
2449 }
2450 if (tag == 'n') { /* OLD */
2451 unsigned int version;
2452 if (rlen < 1+2+4+4) {
2453 EI_TRACE_ERR1("recv_challenge","<- RECV_CHALLENGE 'n' packet too short (%d)",
2454 rlen)
2455 goto error;
2456 }
2457
2458 version = get16be(s);
2459 if (version != EI_DIST_5) {
2460 EI_TRACE_ERR1("recv_challenge",
2461 "<- RECV_CHALLENGE 'n' incorrect version=%d",
2462 version);
2463 goto error;
2464 }
2465 *flags = get32be(s);
2466 *challenge = get32be(s);
2467 nodename_len = (buf + rlen) - s;
2468 }
2469 else { /* NEW */
2470 if (rlen < 1+8+4+4+2) {
2471 EI_TRACE_ERR1("recv_challenge","<- RECV_CHALLENGE 'N' packet too short (%d)",
2472 rlen)
2473 goto error;
2474 }
2475 *version = EI_DIST_6;
2476 *flags = get64be(s);
2477 *challenge = get32be(s);
2478 s += 4; /* ignore peer 'creation' */
2479 nodename_len = get16be(s);
2480 if (nodename_len > (buf + rlen) - s) {
2481 EI_TRACE_ERR1("recv_challenge",
2482 "<- RECV_CHALLENGE 'N' nodename too long (%d)",
2483 nodename_len);
2484 goto error;
2485 }
2486 }
2487
2488 if (nodename_len > MAXNODELEN) {
2489 EI_TRACE_ERR1("recv_challenge",
2490 "<- RECV_CHALLENGE nodename too long (%d)", nodename_len);
2491 goto error;
2492 }
2493
2494 if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {
2495 EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
2496 "handle extended references");
2497 goto error;
2498 }
2499
2500 if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)) {
2501 EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
2502 "handle extended pids and ports");
2503 erl_errno = EIO;
2504 goto error;
2505 }
2506
2507 if (!(*flags & DFLAG_NEW_FLOATS)) {
2508 EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
2509 "handle binary float encoding");
2510 goto error;
2511 }
2512
2513 if (!namebuf)
2514 namebuf = &tmp_nodename[0];
2515
2516 memcpy(namebuf, s, nodename_len);
2517 namebuf[nodename_len] = '\0';
2518
2519 if (!is_static)
2520 free(buf);
2521 EI_TRACE_CONN4("recv_challenge","<- RECV_CHALLENGE (ok) node = %s, "
2522 "version = %u, "
2523 "flags = %u, "
2524 "challenge = %d",
2525 namebuf,
2526 *version,
2527 *flags,
2528 *challenge
2529 );
2530 erl_errno = 0;
2531 return 0;
2532 error:
2533 if (!is_static)
2534 free(buf);
2535 return -1;
2536 }
2537
send_complement(ei_cnode * ec,void * ctx,int pkt_sz,unsigned epmd_says_version,DistFlags her_flags,unsigned ms)2538 static int send_complement(ei_cnode *ec,
2539 void *ctx,
2540 int pkt_sz,
2541 unsigned epmd_says_version,
2542 DistFlags her_flags,
2543 unsigned ms)
2544 {
2545 if (epmd_says_version == EI_DIST_5 && (her_flags & DFLAG_HANDSHAKE_23)) {
2546 char *buf;
2547 unsigned char *s;
2548 char dbuf[DEFBUF_SIZ];
2549 int err;
2550 ssize_t len;
2551 unsigned int flagsHigh;
2552 const int siz = pkt_sz + 1 + 4 + 4;
2553
2554 buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
2555 if (!buf) {
2556 erl_errno = ENOMEM;
2557 return -1;
2558 }
2559 s = (unsigned char *)buf;
2560 switch (pkt_sz) {
2561 case 2:
2562 put16be(s,siz - 2);
2563 break;
2564 case 4:
2565 put32be(s,siz - 4);
2566 break;
2567 default:
2568 return -1;
2569 }
2570 flagsHigh = preferred_flags() >> 32;
2571
2572 put8(s, 'c');
2573 put32be(s, flagsHigh);
2574 put32be(s, ec->creation);
2575
2576 len = (ssize_t) siz;
2577 err = ei_write_fill_ctx_t__(ec->cbs, ctx, buf, &len, ms);
2578 if (!err && len != (ssize_t) siz)
2579 err = EIO;
2580 if (err) {
2581 EI_TRACE_ERR0("send_name", "SEND_NAME -> socket write failed");
2582 if (buf != dbuf)
2583 free(buf);
2584 EI_CONN_SAVE_ERRNO__(err);
2585 return -1;
2586 }
2587
2588 if (buf != dbuf)
2589 free(buf);
2590 }
2591 return 0;
2592 }
2593
2594
send_challenge_reply(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned char digest[16],unsigned challenge,unsigned ms)2595 static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
2596 int pkt_sz, unsigned char digest[16],
2597 unsigned challenge, unsigned ms)
2598 {
2599 char *s;
2600 char buf[DEFBUF_SIZ];
2601 int siz = pkt_sz + 1 + 4 + 16;
2602 int err;
2603 ssize_t len;
2604
2605 s = buf;
2606 switch (pkt_sz) {
2607 case 2:
2608 put16be(s,siz - 2);
2609 break;
2610 case 4:
2611 put32be(s,siz - 4);
2612 break;
2613 default:
2614 return -1;
2615 }
2616 put8(s, 'r');
2617 put32be(s, challenge);
2618 memcpy(s, digest, 16);
2619
2620 len = (ssize_t) siz;
2621 err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
2622 if (!err && len != (ssize_t) siz)
2623 err = EIO;
2624 if (err) {
2625 EI_TRACE_ERR2("send_challenge_reply",
2626 "-> SEND_CHALLENGE_REPLY socket write failed: %s (%d)",
2627 estr(err), err);
2628 EI_CONN_SAVE_ERRNO__(err);
2629 return -1;
2630 }
2631
2632 if (ei_tracelevel >= 3) {
2633 char buffer[33];
2634 EI_TRACE_CONN2("send_challenge_reply",
2635 "-> SEND_CHALLENGE_REPLY (ok) challenge = %d, digest = %s",
2636 challenge,hex((char*)digest, buffer));
2637 }
2638 return 0;
2639 }
2640
recv_complement(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned ms)2641 static int recv_complement(ei_socket_callbacks *cbs,
2642 void *ctx,
2643 int pkt_sz,
2644 unsigned ms)
2645 {
2646 char dbuf[DEFBUF_SIZ];
2647 char *buf = dbuf;
2648 int is_static = 1;
2649 int buflen = DEFBUF_SIZ;
2650 int rlen;
2651 char *s;
2652 char tag;
2653 unsigned int creation;
2654
2655 erl_errno = EIO; /* Default */
2656
2657 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 21) {
2658 EI_TRACE_ERR1("recv_complement",
2659 "<- RECV_COMPLEMENT socket read failed (%d)",rlen);
2660 goto error;
2661 }
2662
2663 s = buf;
2664 if ((tag = get8(s)) != 'c') {
2665 EI_TRACE_ERR2("recv_complement",
2666 "<- RECV_COMPLEMENT incorrect tag, "
2667 "expected 'c' got '%c' (%u)",tag,tag);
2668 goto error;
2669 }
2670 creation = get32be(s);
2671 if (!is_static)
2672 free(buf);
2673
2674 if (ei_tracelevel >= 3) {
2675 EI_TRACE_CONN1("recv_complement",
2676 "<- RECV_COMPLEMENT (ok) creation = %u",
2677 creation);
2678 }
2679 /* We don't have any use for 'creation' of other node, so we drop it */
2680 erl_errno = 0;
2681 return 0;
2682
2683 error:
2684 if (!is_static)
2685 free(buf);
2686 return -1;
2687 }
2688
recv_challenge_reply(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned our_challenge,char cookie[],unsigned * her_challenge,unsigned ms)2689 static int recv_challenge_reply(ei_socket_callbacks *cbs,
2690 void *ctx,
2691 int pkt_sz,
2692 unsigned our_challenge,
2693 char cookie[],
2694 unsigned *her_challenge,
2695 unsigned ms)
2696 {
2697 char dbuf[DEFBUF_SIZ];
2698 char *buf = dbuf;
2699 int is_static = 1;
2700 int buflen = DEFBUF_SIZ;
2701 int rlen;
2702 char *s;
2703 char tag;
2704 char her_digest[16], expected_digest[16];
2705
2706 erl_errno = EIO; /* Default */
2707
2708 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 21) {
2709 EI_TRACE_ERR1("recv_challenge_reply",
2710 "<- RECV_CHALLENGE_REPLY socket read failed (%d)",rlen);
2711 goto error;
2712 }
2713
2714 s = buf;
2715 if ((tag = get8(s)) != 'r') {
2716 EI_TRACE_ERR2("recv_challenge_reply",
2717 "<- RECV_CHALLENGE_REPLY incorrect tag, "
2718 "expected 'r' got '%c' (%u)",tag,tag);
2719 goto error;
2720 }
2721 *her_challenge = get32be(s);
2722 memcpy(her_digest, s, 16);
2723 gen_digest(our_challenge, cookie, (unsigned char*)expected_digest);
2724 if (memcmp(her_digest, expected_digest, 16)) {
2725 EI_TRACE_ERR0("recv_challenge_reply",
2726 "<- RECV_CHALLENGE_REPLY authorization failure");
2727 goto error;
2728 }
2729 if (!is_static)
2730 free(buf);
2731
2732
2733 if (ei_tracelevel >= 3) {
2734 char buffer[33];
2735 EI_TRACE_CONN2("recv_challenge_reply",
2736 "<- RECV_CHALLENGE_REPLY (ok) challenge = %u, digest = %s",
2737 *her_challenge,hex(her_digest,buffer));
2738 }
2739 erl_errno = 0;
2740 return 0;
2741
2742 error:
2743 if (!is_static)
2744 free(buf);
2745 return -1;
2746 }
2747
send_challenge_ack(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned char digest[16],unsigned ms)2748 static int send_challenge_ack(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
2749 unsigned char digest[16], unsigned ms)
2750 {
2751 char *s;
2752 char buf[DEFBUF_SIZ];
2753 int siz = pkt_sz + 1 + 16;
2754 int err;
2755 ssize_t len;
2756
2757 s = buf;
2758 switch (pkt_sz) {
2759 case 2:
2760 put16be(s,siz - 2);
2761 break;
2762 case 4:
2763 put32be(s,siz - 4);
2764 break;
2765 default:
2766 return -1;
2767 }
2768 put8(s, 'a');
2769 memcpy(s, digest, 16);
2770
2771 len = (ssize_t) siz;
2772 err = ei_write_fill_ctx_t__(cbs, ctx, buf, &len, ms);
2773 if (!err && len != (ssize_t) siz)
2774 err = EIO;
2775 if (err) {
2776 EI_TRACE_ERR2("recv_challenge_reply",
2777 "-> SEND_CHALLENGE_ACK socket write failed: %s (%d)",
2778 estr(err), err);
2779 EI_CONN_SAVE_ERRNO__(err);
2780 return -1;
2781 }
2782
2783 if (ei_tracelevel >= 3) {
2784 char buffer[33];
2785 EI_TRACE_CONN1("recv_challenge_reply",
2786 "-> SEND_CHALLENGE_ACK (ok) digest = %s",hex((char *)digest,buffer));
2787 }
2788
2789 return 0;
2790 }
2791
recv_challenge_ack(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,unsigned our_challenge,char cookie[],unsigned ms)2792 static int recv_challenge_ack(ei_socket_callbacks *cbs, void *ctx,
2793 int pkt_sz, unsigned our_challenge,
2794 char cookie[], unsigned ms)
2795 {
2796 char dbuf[DEFBUF_SIZ];
2797 char *buf = dbuf;
2798 int is_static = 1;
2799 int buflen = DEFBUF_SIZ;
2800 int rlen;
2801 char *s;
2802 char tag;
2803 char her_digest[16], expected_digest[16];
2804
2805 erl_errno = EIO; /* Default */
2806
2807 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 17) {
2808 EI_TRACE_ERR1("recv_challenge_ack",
2809 "<- RECV_CHALLENGE_ACK socket read failed (%d)",rlen);
2810 goto error;
2811 }
2812
2813 s = buf;
2814 if ((tag = get8(s)) != 'a') {
2815 EI_TRACE_ERR2("recv_challenge_ack",
2816 "<- RECV_CHALLENGE_ACK incorrect tag, "
2817 "expected 'a' got '%c' (%u)",tag,tag);
2818 goto error;
2819 }
2820 memcpy(her_digest, s, 16);
2821 gen_digest(our_challenge, cookie, (unsigned char *)expected_digest);
2822 if (memcmp(her_digest, expected_digest, 16)) {
2823 EI_TRACE_ERR0("recv_challenge_ack",
2824 "<- RECV_CHALLENGE_ACK authorization failure");
2825 goto error;
2826 }
2827 if (!is_static)
2828 free(buf);
2829
2830 if (ei_tracelevel >= 3) {
2831 char buffer[33];
2832 EI_TRACE_CONN1("recv_challenge_ack",
2833 "<- RECV_CHALLENGE_ACK (ok) digest = %s",hex(her_digest,buffer));
2834 }
2835 erl_errno = 0;
2836 return 0;
2837
2838 error:
2839 if (!is_static)
2840 free(buf);
2841 return -1;
2842 }
2843
recv_name(ei_socket_callbacks * cbs,void * ctx,int pkt_sz,char * send_name_tag,DistFlags * flags,char * namebuf,unsigned ms)2844 static int recv_name(ei_socket_callbacks *cbs, void *ctx,
2845 int pkt_sz, char *send_name_tag,
2846 DistFlags *flags, char *namebuf, unsigned ms)
2847 {
2848 char dbuf[DEFBUF_SIZ];
2849 char *buf = dbuf;
2850 int is_static = 1;
2851 int buflen = DEFBUF_SIZ;
2852 int rlen;
2853 unsigned int namelen;
2854 char *s;
2855 char tmp_nodename[MAXNODELEN+1];
2856 char tag;
2857
2858 erl_errno = EIO; /* Default */
2859
2860 if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen,
2861 &is_static, ms)) <= 0) {
2862 EI_TRACE_ERR1("recv_name","<- RECV_NAME socket read failed (%d)",rlen);
2863 goto error;
2864 }
2865 s = buf;
2866 tag = get8(s);
2867 *send_name_tag = tag;
2868 if (tag != 'n' && tag != 'N') {
2869 EI_TRACE_ERR2("recv_name","<- RECV_NAME incorrect tag, "
2870 "expected 'n' or 'N', got '%c' (%u)",tag,tag);
2871 goto error;
2872 }
2873 if (tag == 'n') {
2874 unsigned int version;
2875 if (rlen < 1+2+4) {
2876 EI_TRACE_ERR1("recv_name","<- RECV_NAME 'n' packet too short (%d)",
2877 rlen)
2878 goto error;
2879 }
2880 version = get16be(s);
2881 if (version < EI_DIST_5) {
2882 EI_TRACE_ERR1("recv_name","<- RECV_NAME 'n' invalid version=%d",
2883 version)
2884 goto error;
2885 }
2886 *flags = get32be(s);
2887 namelen = rlen - (1+2+4);
2888 }
2889 else { /* tag == 'N' */
2890 if (rlen < 1+8+4+2) {
2891 EI_TRACE_ERR1("recv_name","<- RECV_NAME 'N' packet too short (%d)",
2892 rlen)
2893 goto error;
2894 }
2895 *flags = get64be(s);
2896 s += 4; /* ignore peer 'creation' */
2897 namelen = get16be(s);
2898 }
2899
2900 if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {
2901 EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot handle"
2902 "extended references");
2903 goto error;
2904 }
2905
2906 if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)) {
2907 EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot "
2908 "handle extended pids and ports");
2909 erl_errno = EIO;
2910 goto error;
2911 }
2912
2913 if (!namebuf)
2914 namebuf = &tmp_nodename[0];
2915
2916 if (namelen > MAXNODELEN || s+namelen > buf+rlen) {
2917 EI_TRACE_ERR2("recv_name","<- RECV_NAME '%c' nodename too long (%d)",
2918 tag, namelen);
2919 goto error;
2920 }
2921
2922 memcpy(namebuf, s, namelen);
2923 namebuf[namelen] = '\0';
2924
2925 if (!is_static)
2926 free(buf);
2927 EI_TRACE_CONN3("recv_name",
2928 "<- RECV_NAME (ok) node = %s, tag = %c, flags = %u",
2929 namebuf,tag,*flags);
2930 erl_errno = 0;
2931 return 0;
2932
2933 error:
2934 if (!is_static)
2935 free(buf);
2936 return -1;
2937 }
2938
2939 /***************************************************************************
2940 *
2941 * Returns 1 on success and 0 on failure.
2942 *
2943 ***************************************************************************/
2944
2945
2946 /* size is the buffer size, e.i. string length + 1 */
2947
get_home(char * buf,int size)2948 static int get_home(char *buf, int size)
2949 {
2950 #ifdef __WIN32__
2951 char* homedrive = getenv("HOMEDRIVE");
2952 char* homepath = getenv("HOMEPATH");
2953
2954 if (homedrive && homepath) {
2955 if (strlen(homedrive)+strlen(homepath) >= size)
2956 return 0;
2957 strcpy(buf, homedrive);
2958 strcat(buf, homepath);
2959 return 1;
2960 }
2961 else {
2962 int len = GetWindowsDirectory(buf, size);
2963 if (len) {
2964 return (len < size);
2965 }
2966 }
2967 #else
2968 char* homepath = getenv("HOME");
2969 if (homepath) {
2970 if (strlen(homepath) >= size)
2971 return 0;
2972 strcpy(buf, homepath);
2973 return 1;
2974 }
2975 #endif
2976
2977 buf[0] = '.';
2978 buf[1] = '\0';
2979 return 1;
2980 }
2981
2982
get_cookie(char * buf,int bufsize)2983 static int get_cookie(char *buf, int bufsize)
2984 {
2985 char fname[EI_MAX_HOME_PATH + sizeof(COOKIE_FILE) + 1];
2986 int fd;
2987 int len;
2988 unsigned char next_c;
2989
2990 if (!get_home(fname, EI_MAX_HOME_PATH+1)) {
2991 fprintf(stderr,"<ERROR> get_cookie: too long path to home");
2992 return 0;
2993 }
2994
2995 strcat(fname, COOKIE_FILE);
2996 if ((fd = open(fname, O_RDONLY, 0777)) < 0) {
2997 fprintf(stderr,"<ERROR> get_cookie: can't open cookie file");
2998 return 0;
2999 }
3000
3001 if ((len = read(fd, buf, bufsize-1)) < 0) {
3002 fprintf(stderr,"<ERROR> get_cookie: reading cookie file");
3003 close(fd);
3004 return 0;
3005 }
3006
3007 /* If more to read it is too long. Not 100% correct test but will do. */
3008 if (read(fd, &next_c, 1) > 0 && !isspace(next_c)) {
3009 fprintf(stderr,"<ERROR> get_cookie: cookie in %s is too long",fname);
3010 close(fd);
3011 return 0;
3012 }
3013
3014 close(fd);
3015
3016 /* Remove all newlines after the first newline */
3017 buf[len] = '\0'; /* Terminate string */
3018 len = strcspn(buf,"\r\n");
3019 buf[len] = '\0'; /* Terminate string again */
3020
3021 return 1; /* Success! */
3022 }
3023
3024