1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2001-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 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <ctype.h>
26
27 #define ERTS_WANT_EXTERNAL_TAGS
28 #include "sys.h"
29 #include "erl_vm.h"
30 #include "erl_sys_driver.h"
31 #include "global.h"
32 #include "erl_process.h"
33 #include "error.h"
34 #include "bif.h"
35 #include "big.h"
36 #include "dist.h"
37 #include "erl_version.h"
38 #include "erl_binary.h"
39 #include "erl_db_util.h"
40 #include "register.h"
41 #include "external.h"
42 #include "packet_parser.h"
43 #include "erl_bits.h"
44 #include "erl_bif_unique.h"
45 #include "dtrace-wrapper.h"
46 #include "erl_proc_sig_queue.h"
47 #include "erl_osenv.h"
48
49 static Port *open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump);
50 static int merge_global_environment(erts_osenv_t *env, Eterm key_value_pairs);
51 static char **convert_args(Eterm);
52 static void free_args(char **);
53
54 char *erts_default_arg0 = "default";
55
erts_internal_open_port_2(BIF_ALIST_2)56 BIF_RETTYPE erts_internal_open_port_2(BIF_ALIST_2)
57 {
58 BIF_RETTYPE ret;
59 Port *port;
60 Eterm res;
61 char *str;
62 int err_type, err_num;
63 ErtsLink *proc_lnk, *port_lnk;
64
65 port = open_port(BIF_P, BIF_ARG_1, BIF_ARG_2, &err_type, &err_num);
66 if (!port) {
67 if (err_type == -4) {
68 /* Invalid settings arguments. */
69 return am_badopt;
70 } else if (err_type == -3) {
71 ASSERT(err_num == BADARG || err_num == SYSTEM_LIMIT);
72 if (err_num == BADARG)
73 res = am_badarg;
74 else if (err_num == SYSTEM_LIMIT)
75 res = am_system_limit;
76 else
77 /* this is only here to silence gcc, it should not happen */
78 BIF_ERROR(BIF_P, EXC_INTERNAL_ERROR);
79 } else if (err_type == -2) {
80 str = erl_errno_id(err_num);
81 res = erts_atom_put((byte *) str, sys_strlen(str), ERTS_ATOM_ENC_LATIN1, 1);
82 } else {
83 res = am_einval;
84 }
85 BIF_RET(res);
86 }
87
88 proc_lnk = erts_link_internal_create(ERTS_LNK_TYPE_PORT, port->common.id);
89 port_lnk = erts_link_internal_create(ERTS_LNK_TYPE_PORT, BIF_P->common.id);
90 /*
91 * This link should not already be present, but can potentially
92 * due to id wrapping...
93 */
94 if (!!erts_link_tree_lookup_insert(&ERTS_P_LINKS(BIF_P), proc_lnk))
95 erts_link_internal_release(proc_lnk);
96 erts_link_tree_insert(&ERTS_P_LINKS(port), port_lnk);
97
98 if (port->drv_ptr->flags & ERL_DRV_FLAG_USE_INIT_ACK) {
99
100 /* Copied from erl_port_task.c */
101 port->async_open_port = erts_alloc(ERTS_ALC_T_PRTSD,
102 sizeof(*port->async_open_port));
103 erts_make_ref_in_array(port->async_open_port->ref);
104 port->async_open_port->to = BIF_P->common.id;
105
106 /*
107 * We unconditionaly *must* do a receive on a message
108 * containing the reference after this...
109 */
110 erts_msgq_set_save_end(BIF_P);
111
112 res = erts_proc_store_ref(BIF_P, port->async_open_port->ref);
113 } else {
114 res = port->common.id;
115 }
116
117 if (IS_TRACED_FL(BIF_P, F_TRACE_PROCS))
118 trace_proc(BIF_P, ERTS_PROC_LOCK_MAIN, BIF_P,
119 am_link, port->common.id);
120
121 ERTS_BIF_PREP_RET(ret, res);
122
123 erts_port_release(port);
124
125 return ret;
126 }
127
128 static ERTS_INLINE Port *
lookup_port(Process * c_p,Eterm id_or_name,Uint32 invalid_flags)129 lookup_port(Process *c_p, Eterm id_or_name, Uint32 invalid_flags)
130 {
131 /* TODO: Implement nicer lookup in register... */
132 Eterm id;
133 if (is_atom(id_or_name))
134 id = erts_whereis_name_to_id(c_p, id_or_name);
135 else
136 id = id_or_name;
137 return erts_port_lookup(id, invalid_flags);
138 }
139
140 static ERTS_INLINE Port *
sig_lookup_port(Process * c_p,Eterm id_or_name)141 sig_lookup_port(Process *c_p, Eterm id_or_name)
142 {
143 return lookup_port(c_p, id_or_name, ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
144 }
145
146 /* Non-inline copy of sig_lookup_port to be exported */
erts_sig_lookup_port(Process * c_p,Eterm id_or_name)147 Port *erts_sig_lookup_port(Process *c_p, Eterm id_or_name)
148 {
149 return lookup_port(c_p, id_or_name, ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP);
150 }
151
152 static ERTS_INLINE Port *
data_lookup_port(Process * c_p,Eterm id_or_name)153 data_lookup_port(Process *c_p, Eterm id_or_name)
154 {
155 return lookup_port(c_p, id_or_name, ERTS_PORT_SFLGS_INVALID_LOOKUP);
156 }
157
158 /*
159 * erts_internal:port_command/3 is used by the
160 * erlang:port_command/2 and erlang:port_command/3
161 * BIFs.
162 */
163
erts_internal_port_command_3(BIF_ALIST_3)164 BIF_RETTYPE erts_internal_port_command_3(BIF_ALIST_3)
165 {
166 BIF_RETTYPE res;
167 Port *prt;
168 int flags = 0;
169 erts_aint32_t state;
170
171 if (is_not_nil(BIF_ARG_3)) {
172 Eterm l = BIF_ARG_3;
173 while (is_list(l)) {
174 Eterm* cons = list_val(l);
175 Eterm car = CAR(cons);
176 if (car == am_force)
177 flags |= ERTS_PORT_SIG_FLG_FORCE;
178 else if (car == am_nosuspend)
179 flags |= ERTS_PORT_SIG_FLG_NOSUSPEND;
180 else
181 BIF_RET(am_badopt);
182 l = CDR(cons);
183 }
184 if (!is_nil(l))
185 BIF_RET(am_badopt);
186 }
187
188 prt = sig_lookup_port(BIF_P, BIF_ARG_1);
189 if (!prt)
190 ERTS_BIF_PREP_RET(res, am_badarg);
191 else if ((flags & ERTS_PORT_SIG_FLG_FORCE)
192 && !(prt->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY)) {
193 ERTS_BIF_PREP_RET(res, am_notsup);
194 }
195 else {
196 Eterm ref;
197 #ifdef DEBUG
198 ref = NIL;
199 #endif
200
201 switch (erts_port_output(BIF_P, flags, prt, prt->common.id,
202 BIF_ARG_2, &ref)) {
203 case ERTS_PORT_OP_BADARG:
204 case ERTS_PORT_OP_DROPPED:
205 ERTS_BIF_PREP_RET(res, am_badarg);
206 break;
207 case ERTS_PORT_OP_BUSY:
208 ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
209 if (flags & ERTS_PORT_SIG_FLG_NOSUSPEND)
210 ERTS_BIF_PREP_RET(res, am_false);
211 else {
212 erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, prt);
213 ERTS_BIF_YIELD3(BIF_TRAP_EXPORT(BIF_erts_internal_port_command_3),
214 BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
215 }
216 break;
217 case ERTS_PORT_OP_BUSY_SCHEDULED:
218 ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
219 /* Fall through... */
220 case ERTS_PORT_OP_SCHEDULED:
221 ASSERT(is_internal_ordinary_ref(ref));
222 /* Signal order preserved by reply... */
223 BIF_RET(ref);
224 break;
225 case ERTS_PORT_OP_DONE:
226 ERTS_BIF_PREP_RET(res, am_true);
227 break;
228 default:
229 ERTS_INTERNAL_ERROR("Unexpected erts_port_output() result");
230 break;
231 }
232 }
233
234 state = erts_atomic32_read_acqb(&BIF_P->state);
235 if (state & ERTS_PSFLG_EXITING) {
236 KILL_CATCHES(BIF_P); /* Must exit */
237 ERTS_BIF_PREP_ERROR(res, BIF_P, EXC_ERROR);
238 }
239 else {
240 /* Ensure signal order is preserved... */
241 if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))
242 ERTS_BIF_PREP_HANDLE_SIGNALS_RETURN(res, BIF_P, res);
243 }
244
245 return res;
246 }
247
erts_internal_port_call_3(BIF_ALIST_3)248 BIF_RETTYPE erts_internal_port_call_3(BIF_ALIST_3)
249 {
250 Port* prt;
251 Eterm retval;
252 Uint uint_op;
253 erts_aint32_t state;
254
255 prt = sig_lookup_port(BIF_P, BIF_ARG_1);
256 if (!prt)
257 retval = am_badarg;
258 else if (!term_to_Uint(BIF_ARG_2, &uint_op))
259 retval = am_badarg;
260 else if (uint_op > (Uint) UINT_MAX)
261 retval = am_badarg;
262 else {
263 unsigned int op = (unsigned int) uint_op;
264
265 switch (erts_port_call(BIF_P, prt, op, BIF_ARG_3, &retval)) {
266 case ERTS_PORT_OP_DROPPED:
267 case ERTS_PORT_OP_BADARG:
268 retval = am_badarg;
269 break;
270 case ERTS_PORT_OP_SCHEDULED:
271 ASSERT(is_internal_ordinary_ref(retval));
272 /* Signal order preserved by reply... */
273 BIF_RET(retval);
274 break;
275 case ERTS_PORT_OP_DONE:
276 ASSERT(is_not_internal_ref(retval));
277 break;
278 default:
279 ERTS_INTERNAL_ERROR("Unexpected erts_port_call() result");
280 retval = am_internal_error;
281 break;
282 }
283 }
284
285 state = erts_atomic32_read_acqb(&BIF_P->state);
286 if (state & ERTS_PSFLG_EXITING)
287 ERTS_BIF_EXITED(BIF_P);
288 else {
289 /* Ensure signal order is preserved... */
290 if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))
291 ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
292 }
293
294 BIF_RET(retval);
295 }
296
erts_internal_port_control_3(BIF_ALIST_3)297 BIF_RETTYPE erts_internal_port_control_3(BIF_ALIST_3)
298 {
299 Port* prt;
300 Eterm retval;
301 Uint uint_op;
302 erts_aint32_t state;
303
304 prt = sig_lookup_port(BIF_P, BIF_ARG_1);
305 if (!prt)
306 retval = am_badarg;
307 else if (!term_to_Uint(BIF_ARG_2, &uint_op))
308 retval = am_badarg;
309 else if (uint_op > (Uint) UINT_MAX)
310 retval = am_badarg;
311 else {
312 unsigned int op = (unsigned int) uint_op;
313
314 switch (erts_port_control(BIF_P, prt, op, BIF_ARG_3, &retval)) {
315 case ERTS_PORT_OP_BADARG:
316 case ERTS_PORT_OP_DROPPED:
317 retval = am_badarg;
318 break;
319 case ERTS_PORT_OP_SCHEDULED:
320 ASSERT(is_internal_ordinary_ref(retval));
321 /* Signal order preserved by reply... */
322 BIF_RET(retval);
323 case ERTS_PORT_OP_DONE:
324 ASSERT(is_not_internal_ref(retval));
325 break;
326 default:
327 ERTS_INTERNAL_ERROR("Unexpected erts_port_control() result");
328 retval = am_internal_error;
329 break;
330 }
331 }
332
333 state = erts_atomic32_read_acqb(&BIF_P->state);
334 if (state & ERTS_PSFLG_EXITING)
335 ERTS_BIF_EXITED(BIF_P);
336 else {
337 /* Ensure signal order is preserved... */
338 if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))
339 ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
340 }
341
342 BIF_RET(retval);
343 }
344
345 /*
346 * erts_internal:port_close/1 is used by the
347 * erlang:port_close/1 BIF.
348 */
erts_internal_port_close_1(BIF_ALIST_1)349 BIF_RETTYPE erts_internal_port_close_1(BIF_ALIST_1)
350 {
351 Eterm retval;
352 Port *prt;
353
354 prt = sig_lookup_port(BIF_P, BIF_ARG_1);
355 if (!prt)
356 retval = am_badarg;
357 else {
358
359 #ifdef DEBUG
360 retval = NIL;
361 #endif
362
363 switch (erts_port_exit(BIF_P, 0, prt, BIF_P->common.id,
364 am_normal, &retval)) {
365 case ERTS_PORT_OP_BADARG:
366 case ERTS_PORT_OP_DROPPED:
367 retval = am_badarg;
368 break;
369 case ERTS_PORT_OP_SCHEDULED:
370 ASSERT(is_internal_ordinary_ref(retval));
371 /* Signal order preserved by reply... */
372 BIF_RET(retval);
373 break;
374 case ERTS_PORT_OP_DONE:
375 retval = am_true;
376 break;
377 default:
378 ERTS_INTERNAL_ERROR("Unexpected erts_port_exit() result");
379 retval = am_internal_error;
380 break;
381 }
382 }
383
384 /* Ensure signal order is preserved... */
385 if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P))
386 ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
387
388 BIF_RET(retval);
389 }
390
391 /*
392 * erts_internal:port_connect/2 is used by the
393 * erlang:port_connect/2 BIF.
394 */
erts_internal_port_connect_2(BIF_ALIST_2)395 BIF_RETTYPE erts_internal_port_connect_2(BIF_ALIST_2)
396 {
397 Eterm retval;
398 Port* prt;
399
400 prt = sig_lookup_port(BIF_P, BIF_ARG_1);
401 if (!prt)
402 retval = am_badarg;
403 else {
404 #ifdef DEBUG
405 retval = NIL;
406 #endif
407
408 switch (erts_port_connect(BIF_P, 0, prt, BIF_P->common.id,
409 BIF_ARG_2, &retval)) {
410 case ERTS_PORT_OP_BADARG:
411 case ERTS_PORT_OP_DROPPED:
412 retval = am_badarg;
413 break;
414 case ERTS_PORT_OP_SCHEDULED:
415 ASSERT(is_internal_ordinary_ref(retval));
416 /* Signal order preserved by reply... */
417 BIF_RET(retval);
418 case ERTS_PORT_OP_DONE:
419 retval = am_true;
420 break;
421 default:
422 ERTS_INTERNAL_ERROR("Unexpected erts_port_connect() result");
423 retval = am_internal_error;
424 break;
425 }
426 }
427
428 /* Ensure signal order is preserved... */
429 if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P))
430 ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
431
432 BIF_RET(retval);
433 }
434
erts_internal_port_info_1(BIF_ALIST_1)435 BIF_RETTYPE erts_internal_port_info_1(BIF_ALIST_1)
436 {
437 Eterm retval;
438 Port* prt;
439
440 if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
441 prt = sig_lookup_port(BIF_P, BIF_ARG_1);
442 if (!prt)
443 retval = am_undefined;
444 else {
445 switch (erts_port_info(BIF_P, prt, THE_NON_VALUE, &retval)) {
446 case ERTS_PORT_OP_BADARG:
447 retval = am_badarg;
448 break;
449 case ERTS_PORT_OP_DROPPED:
450 retval = am_undefined;
451 break;
452 case ERTS_PORT_OP_SCHEDULED:
453 ASSERT(is_internal_ordinary_ref(retval));
454 /* Signal order preserved by reply... */
455 BIF_RET(retval);
456 case ERTS_PORT_OP_DONE:
457 ASSERT(is_not_internal_ref(retval));
458 break;
459 default:
460 ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
461 retval = am_internal_error;
462 break;
463 }
464 }
465 }
466 else if (is_external_port(BIF_ARG_1)) {
467 if (external_port_dist_entry(BIF_ARG_1) == erts_this_dist_entry)
468 retval = am_undefined;
469 else
470 retval = am_badarg;
471 }
472 else {
473 retval = am_badarg;
474 }
475
476 /* Ensure signal order is preserved... */
477 if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P))
478 ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
479
480 BIF_RET(retval);
481 }
482
483
erts_internal_port_info_2(BIF_ALIST_2)484 BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2)
485 {
486 Eterm retval;
487 Port* prt;
488
489 if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
490 prt = sig_lookup_port(BIF_P, BIF_ARG_1);
491 if (!prt)
492 retval = am_undefined;
493 else {
494 switch (erts_port_info(BIF_P, prt, BIF_ARG_2, &retval)) {
495 case ERTS_PORT_OP_BADARG:
496 retval = am_badarg;
497 break;
498 case ERTS_PORT_OP_DROPPED:
499 retval = am_undefined;
500 break;
501 case ERTS_PORT_OP_SCHEDULED:
502 ASSERT(is_internal_ordinary_ref(retval));
503 /* Signal order preserved by reply... */
504 BIF_RET(retval);
505 case ERTS_PORT_OP_DONE:
506 ASSERT(is_not_internal_ref(retval));
507 break;
508 default:
509 ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
510 retval = am_internal_error;
511 break;
512 }
513 }
514 }
515 else if (is_external_port(BIF_ARG_1)) {
516 if (external_port_dist_entry(BIF_ARG_1) == erts_this_dist_entry)
517 retval = am_undefined;
518 else
519 retval = am_badtype;
520 }
521 else {
522 retval = am_badtype;
523 }
524
525 /* Ensure signal order is preserved... */
526 if (ERTS_PROC_HAS_INCOMING_SIGNALS(BIF_P))
527 ERTS_BIF_HANDLE_SIGNALS_RETURN(BIF_P, retval);
528
529 BIF_RET(retval);
530 }
531
532 /*
533 * The erlang:port_set_data()/erlang:port_get_data() operations should
534 * be viewed as operations on a table (inet_db) with data values
535 * associated with port identifier keys. That is, these operations are
536 * *not* signals to/from ports.
537 */
538
539 #if (TAG_PRIMARY_IMMED1 & 0x3) == 0
540 # error "erlang:port_set_data()/erlang:port_get_data() needs to be rewritten!"
541 #endif
542
543 typedef struct {
544 ErtsThrPrgrLaterOp later_op;
545 Uint hsize;
546 Eterm data;
547 ErlOffHeap off_heap;
548 Eterm heap[1];
549 } ErtsPortDataHeap;
550
551 static void
free_port_data_heap(void * vpdhp)552 free_port_data_heap(void *vpdhp)
553 {
554 erts_cleanup_offheap(&((ErtsPortDataHeap *) vpdhp)->off_heap);
555 erts_free(ERTS_ALC_T_PORT_DATA_HEAP, vpdhp);
556 }
557
558 static ERTS_INLINE void
cleanup_old_port_data(erts_aint_t data)559 cleanup_old_port_data(erts_aint_t data)
560 {
561 if ((data & 0x3) != 0) {
562 ASSERT(is_immed((Eterm) data));
563 }
564 else {
565 ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
566 size_t size;
567 ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER;
568 size = sizeof(ErtsPortDataHeap) + (pdhp->hsize-1)*sizeof(Eterm);
569 erts_schedule_thr_prgr_later_cleanup_op(free_port_data_heap,
570 (void *) pdhp,
571 &pdhp->later_op,
572 size);
573 }
574 }
575
576 void
erts_init_port_data(Port * prt)577 erts_init_port_data(Port *prt)
578 {
579 erts_atomic_init_nob(&prt->data, (erts_aint_t) am_undefined);
580 }
581
582 void
erts_cleanup_port_data(Port * prt)583 erts_cleanup_port_data(Port *prt)
584 {
585 ASSERT(erts_atomic32_read_nob(&prt->state) & ERTS_PORT_SFLGS_INVALID_LOOKUP);
586 cleanup_old_port_data(erts_atomic_xchg_nob(&prt->data,
587 (erts_aint_t) NULL));
588 }
589
590 Uint
erts_port_data_size(Port * prt)591 erts_port_data_size(Port *prt)
592 {
593 erts_aint_t data = erts_atomic_read_ddrb(&prt->data);
594
595 if ((data & 0x3) != 0) {
596 ASSERT(is_immed((Eterm) (UWord) data));
597 return (Uint) 0;
598 }
599 else {
600 ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
601 return (Uint) sizeof(ErtsPortDataHeap) + (pdhp->hsize-1)*sizeof(Eterm);
602 }
603 }
604
605 ErlOffHeap *
erts_port_data_offheap(Port * prt)606 erts_port_data_offheap(Port *prt)
607 {
608 erts_aint_t data = erts_atomic_read_ddrb(&prt->data);
609
610 if ((data & 0x3) != 0) {
611 ASSERT(is_immed((Eterm) (UWord) data));
612 return NULL;
613 }
614 else {
615 ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
616 return &pdhp->off_heap;
617 }
618 }
619
port_set_data_2(BIF_ALIST_2)620 BIF_RETTYPE port_set_data_2(BIF_ALIST_2)
621 {
622 /*
623 * This is not a signal. See comment above.
624 */
625 erts_aint_t data;
626 Port* prt;
627
628 prt = data_lookup_port(BIF_P, BIF_ARG_1);
629 if (!prt)
630 BIF_ERROR(BIF_P, BADARG);
631
632 if (is_immed(BIF_ARG_2)) {
633 data = (erts_aint_t) BIF_ARG_2;
634 ASSERT((data & 0x3) != 0);
635 }
636 else {
637 ErtsPortDataHeap *pdhp;
638 Uint hsize;
639 Eterm *hp;
640
641 hsize = size_object(BIF_ARG_2);
642 pdhp = erts_alloc(ERTS_ALC_T_PORT_DATA_HEAP,
643 sizeof(ErtsPortDataHeap) + (hsize-1)*sizeof(Eterm));
644 hp = &pdhp->heap[0];
645 pdhp->off_heap.first = NULL;
646 pdhp->off_heap.overhead = 0;
647 pdhp->hsize = hsize;
648 pdhp->data = copy_struct(BIF_ARG_2, hsize, &hp, &pdhp->off_heap);
649 data = (erts_aint_t) pdhp;
650 ASSERT((data & 0x3) == 0);
651 }
652
653 data = erts_atomic_xchg_wb(&prt->data, data);
654
655 if (data == (erts_aint_t)NULL) {
656 /* Port terminated by racing thread */
657 data = erts_atomic_xchg_wb(&prt->data, data);
658 ASSERT(data != (erts_aint_t)NULL);
659 cleanup_old_port_data(data);
660 BIF_ERROR(BIF_P, BADARG);
661 }
662 cleanup_old_port_data(data);
663 BIF_RET(am_true);
664 }
665
666
port_get_data_1(BIF_ALIST_1)667 BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
668 {
669 /*
670 * This is not a signal. See comment above.
671 */
672 Eterm res;
673 erts_aint_t data;
674 Port* prt;
675
676 prt = data_lookup_port(BIF_P, BIF_ARG_1);
677 if (!prt)
678 BIF_ERROR(BIF_P, BADARG);
679
680 data = erts_atomic_read_ddrb(&prt->data);
681 if (data == (erts_aint_t)NULL)
682 BIF_ERROR(BIF_P, BADARG); /* Port terminated by racing thread */
683
684 if ((data & 0x3) != 0) {
685 res = (Eterm) (UWord) data;
686 ASSERT(is_immed(res));
687 }
688 else {
689 ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
690 Eterm *hp = HAlloc(BIF_P, pdhp->hsize);
691 res = copy_struct(pdhp->data, pdhp->hsize, &hp, &MSO(BIF_P));
692 }
693
694 BIF_RET(res);
695 }
696
erts_port_data_read(Port * prt)697 Eterm erts_port_data_read(Port* prt)
698 {
699 Eterm res;
700 erts_aint_t data;
701
702 data = erts_atomic_read_ddrb(&prt->data);
703 if (data == (erts_aint_t)NULL)
704 return am_undefined; /* Port terminated by racing thread */
705
706 if ((data & 0x3) != 0) {
707 res = (Eterm) (UWord) data;
708 ASSERT(is_immed(res));
709 }
710 else {
711 ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
712 res = pdhp->data;
713 }
714 return res;
715 }
716
717
718 /*
719 * Open a port. Most of the work is not done here but rather in
720 * the file io.c.
721 * Error returns: -1 or -2 returned from open_driver (-2 implies
722 * that *err_nump contains the error code; -1 means we don't really know what happened),
723 * -3 if argument parsing failed or we are out of ports (*err_nump should contain
724 * either BADARG or SYSTEM_LIMIT),
725 * -4 if port settings were invalid.
726 */
727
728 static Port *
open_port(Process * p,Eterm name,Eterm settings,int * err_typep,int * err_nump)729 open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
730 {
731 int merged_environment = 0;
732 Sint i;
733 Eterm option;
734 Uint arity;
735 Eterm* tp;
736 Uint* nargs;
737 erts_driver_t* driver;
738 char* name_buf = NULL;
739 SysDriverOpts opts;
740 Sint linebuf;
741 Eterm edir = NIL;
742 byte dir[MAXPATHLEN];
743 erts_aint32_t sflgs = 0;
744 Port *port;
745
746 /* These are the defaults */
747 opts.packet_bytes = 0;
748 opts.use_stdio = 1;
749 opts.redir_stderr = 0;
750 opts.read_write = 0;
751 opts.hide_window = 0;
752 opts.wd = NULL;
753 opts.exit_status = 0;
754 opts.overlapped_io = 0;
755 opts.spawn_type = ERTS_SPAWN_ANY;
756 opts.argv = NULL;
757 opts.parallelism = erts_port_parallelism;
758 opts.high_watermark = 8192;
759 opts.low_watermark = opts.high_watermark / 2;
760 opts.port_watermarks_set = 0;
761 opts.msgq_watermarks_set = 0;
762 erts_osenv_init(&opts.envir);
763
764 linebuf = 0;
765
766 *err_nump = 0;
767
768 if (is_not_list(settings) && is_not_nil(settings)) {
769 goto bad_settings;
770 }
771
772 /*
773 * Parse the settings.
774 */
775
776 if (is_not_nil(settings)) {
777 nargs = list_val(settings);
778 while (1) {
779 if (is_tuple_arity(*nargs, 2)) {
780 tp = tuple_val(*nargs);
781 arity = *tp++;
782 option = *tp++;
783 if (option == am_packet) {
784 if (is_not_small(*tp)) {
785 goto bad_settings;
786 }
787 opts.packet_bytes = signed_val(*tp);
788 switch (opts.packet_bytes) {
789 case 1:
790 case 2:
791 case 4:
792 break;
793 default:
794 goto bad_settings;
795 }
796 } else if (option == am_line) {
797 if (is_not_small(*tp)) {
798 goto bad_settings;
799 }
800 linebuf = signed_val(*tp);
801 if (linebuf <= 0) {
802 goto bad_settings;
803 }
804 } else if (option == am_env) {
805 if (merged_environment) {
806 /* Ignore previous env option */
807 erts_osenv_clear(&opts.envir);
808 }
809
810 merged_environment = 1;
811
812 if (merge_global_environment(&opts.envir, *tp)) {
813 goto bad_settings;
814 }
815 } else if (option == am_args) {
816 char **av;
817 char **oav = opts.argv;
818 if ((av = convert_args(*tp)) == NULL) {
819 goto bad_settings;
820 }
821 opts.argv = av;
822 if (oav) {
823 opts.argv[0] = oav[0];
824 oav[0] = erts_default_arg0;
825 free_args(oav);
826 }
827
828 } else if (option == am_arg0) {
829 char *a0;
830
831 if ((a0 = erts_convert_filename_to_native(*tp, NULL, 0, ERTS_ALC_T_TMP, 1, 1, NULL)) == NULL) {
832 goto bad_settings;
833 }
834 if (opts.argv == NULL) {
835 opts.argv = erts_alloc(ERTS_ALC_T_TMP,
836 2 * sizeof(char **));
837 opts.argv[0] = a0;
838 opts.argv[1] = NULL;
839 } else {
840 if (opts.argv[0] != erts_default_arg0) {
841 erts_free(ERTS_ALC_T_TMP, opts.argv[0]);
842 }
843 opts.argv[0] = a0;
844 }
845 } else if (option == am_cd) {
846 edir = *tp;
847 } else if (option == am_parallelism) {
848 if (*tp == am_true)
849 opts.parallelism = 1;
850 else if (*tp == am_false)
851 opts.parallelism = 0;
852 else
853 goto bad_settings;
854 } else if (option == am_busy_limits_port) {
855 Uint high, low;
856 if (*tp == am_disabled)
857 low = high = ERL_DRV_BUSY_MSGQ_DISABLED;
858 else if (!is_tuple_arity(*tp, 2))
859 goto bad_settings;
860 else {
861 Eterm *wtp = tuple_val(*tp);
862 if (!term_to_Uint(wtp[1], &low))
863 goto bad_settings;
864 if (!term_to_Uint(wtp[2], &high))
865 goto bad_settings;
866 if (high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
867 goto bad_settings;
868 if (high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
869 goto bad_settings;
870 if (low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
871 goto bad_settings;
872 if (low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
873 goto bad_settings;
874 if (high == ~((Uint) 0) || low == ~((Uint) 0))
875 goto bad_settings;
876 if (low > high)
877 low = high;
878 }
879 opts.low_watermark = low;
880 opts.high_watermark = high;
881 opts.port_watermarks_set = !0;
882 } else if (option == am_busy_limits_msgq) {
883 Uint high, low;
884 if (*tp == am_disabled)
885 low = high = ERL_DRV_BUSY_MSGQ_DISABLED;
886 else if (!is_tuple_arity(*tp, 2))
887 goto bad_settings;
888 else {
889 Eterm *wtp = tuple_val(*tp);
890 if (!term_to_Uint(wtp[1], &low))
891 goto bad_settings;
892 if (!term_to_Uint(wtp[2], &high))
893 goto bad_settings;
894 if (high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
895 goto bad_settings;
896 if (high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
897 goto bad_settings;
898 if (low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
899 goto bad_settings;
900 if (low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
901 goto bad_settings;
902 if (high == ~((Uint) 0) || low == ~((Uint) 0))
903 goto bad_settings;
904 if (low > high)
905 low = high;
906 }
907 opts.low_msgq_watermark = low;
908 opts.high_msgq_watermark = high;
909 opts.msgq_watermarks_set = !0;
910 } else {
911 goto bad_settings;
912 }
913 } else if (*nargs == am_stream) {
914 opts.packet_bytes = 0;
915 } else if (*nargs == am_use_stdio) {
916 opts.use_stdio = 1;
917 } else if (*nargs == am_stderr_to_stdout) {
918 opts.redir_stderr = 1;
919 } else if (*nargs == am_line) {
920 linebuf = 512;
921 } else if (*nargs == am_nouse_stdio) {
922 opts.use_stdio = 0;
923 } else if (*nargs == am_binary) {
924 sflgs |= ERTS_PORT_SFLG_BINARY_IO;
925 } else if (*nargs == am_in) {
926 opts.read_write |= DO_READ;
927 } else if (*nargs == am_out) {
928 opts.read_write |= DO_WRITE;
929 } else if (*nargs == am_eof) {
930 sflgs |= ERTS_PORT_SFLG_SOFT_EOF;
931 } else if (*nargs == am_hide) {
932 opts.hide_window = 1;
933 } else if (*nargs == am_exit_status) {
934 opts.exit_status = 1;
935 } else if (*nargs == am_overlapped_io) {
936 opts.overlapped_io = 1;
937 } else {
938 goto bad_settings;
939 }
940 if (is_nil(*++nargs))
941 break;
942 if (is_not_list(*nargs)) {
943 goto bad_settings;
944 }
945 nargs = list_val(*nargs);
946 }
947 }
948
949 if (opts.read_write == 0) /* implement default */
950 opts.read_write = DO_READ|DO_WRITE;
951
952 /* Mutually exclusive arguments. */
953 if((linebuf && opts.packet_bytes) ||
954 (opts.redir_stderr && !opts.use_stdio)) {
955 goto bad_settings;
956 }
957
958 /* If we lacked an env option, fill in the global environment without
959 * changes. */
960 if (!merged_environment) {
961 merge_global_environment(&opts.envir, NIL);
962 }
963
964 /*
965 * Parse the first argument and start the appropriate driver.
966 */
967
968 if (is_atom(name) || (i = is_string(name))) {
969 /* a vanilla port */
970 if (is_atom(name)) {
971 name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP,
972 atom_tab(atom_val(name))->len+1);
973 sys_memcpy((void *) name_buf,
974 (void *) atom_tab(atom_val(name))->name,
975 atom_tab(atom_val(name))->len);
976 name_buf[atom_tab(atom_val(name))->len] = '\0';
977 } else {
978 name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1);
979 if (intlist_to_buf(name, name_buf, i) != i)
980 erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__);
981 name_buf[i] = '\0';
982 }
983 driver = &vanilla_driver;
984 } else {
985 if (is_not_tuple(name)) {
986 goto badarg; /* Not a process or fd port */
987 }
988 tp = tuple_val(name);
989 arity = *tp++;
990
991 if (arity == make_arityval(0)) {
992 goto badarg;
993 }
994
995 if (*tp == am_spawn || *tp == am_spawn_driver || *tp == am_spawn_executable) { /* A process port */
996 int encoding;
997 if (arity != make_arityval(2)) {
998 goto badarg;
999 }
1000 name = tp[1];
1001 encoding = erts_get_native_filename_encoding();
1002 /* Do not convert the command to utf-16le yet, do that in win32 specific code */
1003 /* since the cmd is used for comparsion with drivers names and copied to port info */
1004 if (encoding == ERL_FILENAME_WIN_WCHAR) {
1005 encoding = ERL_FILENAME_UTF8;
1006 }
1007 if ((name_buf = erts_convert_filename_to_encoding(name, NULL, 0, ERTS_ALC_T_TMP,0,1, encoding, NULL, 0))
1008 == NULL) {
1009 goto badarg;
1010 }
1011
1012 if (*tp == am_spawn_driver) {
1013 opts.spawn_type = ERTS_SPAWN_DRIVER;
1014 } else if (*tp == am_spawn_executable) {
1015 opts.spawn_type = ERTS_SPAWN_EXECUTABLE;
1016 }
1017
1018 driver = &spawn_driver;
1019 } else if (*tp == am_fd) { /* An fd port */
1020 if (arity != make_arityval(3)) {
1021 goto badarg;
1022 }
1023 if (is_not_small(tp[1]) || is_not_small(tp[2])) {
1024 goto badarg;
1025 }
1026 opts.ifd = unsigned_val(tp[1]);
1027 opts.ofd = unsigned_val(tp[2]);
1028
1029 /* Syntesize name from input and output descriptor. */
1030 name_buf = erts_alloc(ERTS_ALC_T_TMP, 256);
1031 erts_snprintf(name_buf, 256, "%i/%i", opts.ifd, opts.ofd);
1032
1033 driver = &fd_driver;
1034 } else {
1035 goto badarg;
1036 }
1037 }
1038
1039 if ((driver != &spawn_driver && opts.argv != NULL) ||
1040 (driver == &spawn_driver &&
1041 opts.spawn_type != ERTS_SPAWN_EXECUTABLE &&
1042 opts.argv != NULL)) {
1043 /* Argument vector only if explicit spawn_executable */
1044 goto badarg;
1045 }
1046
1047 if (edir != NIL) {
1048 if ((opts.wd = erts_convert_filename_to_native(edir, NULL, 0, ERTS_ALC_T_TMP,0,1,NULL)) == NULL) {
1049 goto badarg;
1050 }
1051 }
1052
1053 if (driver != &spawn_driver && opts.exit_status) {
1054 goto badarg;
1055 }
1056
1057 if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
1058 trace_sched(p, ERTS_PROC_LOCK_MAIN, am_out);
1059 }
1060
1061
1062 erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
1063
1064 port = erts_open_driver(driver, p->common.id, name_buf, &opts, err_typep, err_nump);
1065 #ifdef USE_VM_PROBES
1066 if (port && DTRACE_ENABLED(port_open)) {
1067 DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
1068 DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);
1069
1070 dtrace_proc_str(p, process_str);
1071 erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), "%T", port->common.id);
1072 DTRACE3(port_open, process_str, name_buf, port_str);
1073 }
1074 #endif
1075
1076 if (port && IS_TRACED_FL(port, F_TRACE_PORTS))
1077 trace_port(port, am_getting_linked, p->common.id);
1078
1079 erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
1080
1081 if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
1082 trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in);
1083 }
1084
1085 if (!port) {
1086 DEBUGF(("open_driver returned (%d:%d)\n",
1087 err_typep ? *err_typep : 4711,
1088 err_nump ? *err_nump : 4711));
1089 goto do_return;
1090 }
1091
1092 if (linebuf && port->linebuf == NULL){
1093 port->linebuf = allocate_linebuf(linebuf);
1094 sflgs |= ERTS_PORT_SFLG_LINEBUF_IO;
1095 }
1096
1097 if (sflgs)
1098 erts_atomic32_read_bor_relb(&port->state, sflgs);
1099
1100 do_return:
1101 erts_osenv_clear(&opts.envir);
1102 if (name_buf)
1103 erts_free(ERTS_ALC_T_TMP, (void *) name_buf);
1104 if (opts.argv) {
1105 free_args(opts.argv);
1106 }
1107 if (opts.wd && opts.wd != ((char *)dir)) {
1108 erts_free(ERTS_ALC_T_TMP, (void *) opts.wd);
1109 }
1110 return port;
1111
1112 bad_settings:
1113 if (err_typep)
1114 *err_typep = -4;
1115 port = NULL;
1116 goto do_return;
1117
1118 badarg:
1119 if (err_typep)
1120 *err_typep = -3;
1121 if (err_nump)
1122 *err_nump = BADARG;
1123 port = NULL;
1124 goto do_return;
1125 }
1126
1127 /* Merges the the global environment and the given {Key, Value} list into env,
1128 * unsetting all keys whose value is either 'false' or NIL. The behavior on
1129 * NIL is undocumented and perhaps surprising, but the previous implementation
1130 * worked in this manner. */
merge_global_environment(erts_osenv_t * env,Eterm key_value_pairs)1131 static int merge_global_environment(erts_osenv_t *env, Eterm key_value_pairs) {
1132 const erts_osenv_t *global_env = erts_sys_rlock_global_osenv();
1133 erts_osenv_merge(env, global_env, 0);
1134 erts_sys_runlock_global_osenv();
1135
1136 while (is_list(key_value_pairs)) {
1137 Eterm *cell, *tuple;
1138
1139 cell = list_val(key_value_pairs);
1140
1141 if(!is_tuple_arity(CAR(cell), 2)) {
1142 return -1;
1143 }
1144
1145 tuple = tuple_val(CAR(cell));
1146 key_value_pairs = CDR(cell);
1147
1148 if(is_nil(tuple[2]) || tuple[2] == am_false) {
1149 if(erts_osenv_unset_term(env, tuple[1]) < 0) {
1150 return -1;
1151 }
1152 } else {
1153 if(erts_osenv_put_term(env, tuple[1], tuple[2]) < 0) {
1154 return -1;
1155 }
1156 }
1157 }
1158
1159 if(!is_nil(key_value_pairs)) {
1160 return -1;
1161 }
1162
1163 return 0;
1164 }
1165
1166 /* Arguments can be given i unicode and as raw binaries, convert filename is used to convert */
convert_args(Eterm l)1167 static char **convert_args(Eterm l)
1168 {
1169 char **pp;
1170 char *b;
1171 Sint n;
1172 Sint i = 0;
1173 Eterm str;
1174 if (is_not_list(l) && is_not_nil(l)) {
1175 return NULL;
1176 }
1177
1178 n = erts_list_length(l);
1179 if (n < 0)
1180 return NULL;
1181 /* We require at least one element in argv[0] + NULL at end */
1182 pp = erts_alloc(ERTS_ALC_T_TMP, (n + 2) * sizeof(char **));
1183 pp[i++] = erts_default_arg0;
1184 while (is_list(l)) {
1185 str = CAR(list_val(l));
1186 if ((b = erts_convert_filename_to_native(str,NULL,0,ERTS_ALC_T_TMP,1,1,NULL)) == NULL) {
1187 int j;
1188 for (j = 1; j < i; ++j)
1189 erts_free(ERTS_ALC_T_TMP, pp[j]);
1190 erts_free(ERTS_ALC_T_TMP, pp);
1191 return NULL;
1192 }
1193 pp[i++] = b;
1194 l = CDR(list_val(l));
1195 }
1196 pp[i] = NULL;
1197 return pp;
1198 }
1199
free_args(char ** av)1200 static void free_args(char **av)
1201 {
1202 int i;
1203 if (av == NULL)
1204 return;
1205 for (i = 0; av[i] != NULL; ++i) {
1206 if (av[i] != erts_default_arg0) {
1207 erts_free(ERTS_ALC_T_TMP, av[i]);
1208 }
1209 }
1210 erts_free(ERTS_ALC_T_TMP, av);
1211 }
1212
1213 /* ------------ decode_packet() and friends: */
1214
1215 struct packet_callback_args
1216 {
1217 Process* p; /* In */
1218 Eterm res; /* Out */
1219 int string_as_bin; /* return strings as binaries (http_bin): */
1220 byte* aligned_ptr;
1221 Uint bin_sz;
1222 Eterm orig;
1223 Uint bin_offs;
1224 byte bin_bitoffs;
1225 };
1226
1227 #define in_area(ptr,start,nbytes) \
1228 ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes))
1229
1230 static Eterm
http_bld_string(struct packet_callback_args * pca,Uint ** hpp,Uint * szp,const char * str,Sint len)1231 http_bld_string(struct packet_callback_args* pca, Uint **hpp, Uint *szp,
1232 const char *str, Sint len)
1233 {
1234 Eterm res = THE_NON_VALUE;
1235 Uint size;
1236 int make_subbin;
1237
1238 if (pca->string_as_bin) {
1239 size = heap_bin_size(len);
1240 make_subbin = (size > ERL_SUB_BIN_SIZE
1241 && in_area(str, pca->aligned_ptr, pca->bin_sz));
1242 if (szp) {
1243 *szp += make_subbin ? ERL_SUB_BIN_SIZE : size;
1244 }
1245 if (hpp) {
1246 res = make_binary(*hpp);
1247 if (make_subbin) {
1248 ErlSubBin* bin = (ErlSubBin*) *hpp;
1249 bin->thing_word = HEADER_SUB_BIN;
1250 bin->size = len;
1251 bin->offs = pca->bin_offs + ((byte*)str - pca->aligned_ptr);
1252 bin->orig = pca->orig;
1253 bin->bitoffs = pca->bin_bitoffs;
1254 bin->bitsize = 0;
1255 bin->is_writable = 0;
1256 *hpp += ERL_SUB_BIN_SIZE;
1257 }
1258 else {
1259 ErlHeapBin* bin = (ErlHeapBin*) *hpp;
1260 bin->thing_word = header_heap_bin(len);
1261 bin->size = len;
1262 sys_memcpy(bin->data, str, len);
1263 *hpp += size;
1264 }
1265 }
1266 }
1267 else {
1268 res = erts_bld_string_n(hpp, szp, str, len);
1269 }
1270 return res;
1271 }
1272
http_response_erl(void * arg,int major,int minor,int status,const char * phrase,int phrase_len)1273 static int http_response_erl(void *arg, int major, int minor,
1274 int status, const char* phrase, int phrase_len)
1275 {
1276 /* {http_response,{Major,Minor},Status,"Phrase"} */
1277 struct packet_callback_args* pca = (struct packet_callback_args*) arg;
1278 Eterm phrase_term, ver;
1279 Uint hsize = 3 + 5;
1280 Eterm* hp;
1281 #ifdef DEBUG
1282 Eterm* hend;
1283 #endif
1284
1285 http_bld_string(pca, NULL, &hsize, phrase, phrase_len);
1286 hp = HAlloc(pca->p, hsize);
1287 #ifdef DEBUG
1288 hend = hp + hsize;
1289 #endif
1290 phrase_term = http_bld_string(pca, &hp, NULL, phrase, phrase_len);
1291 ver = TUPLE2(hp, make_small(major), make_small(minor));
1292 hp += 3;
1293 pca->res = TUPLE4(hp, am_http_response, ver, make_small(status), phrase_term);
1294 ASSERT(hp+5==hend);
1295 return 1;
1296 }
1297
http_bld_uri(struct packet_callback_args * pca,Eterm ** hpp,Uint * szp,const PacketHttpURI * uri)1298 static Eterm http_bld_uri(struct packet_callback_args* pca,
1299 Eterm** hpp, Uint* szp, const PacketHttpURI* uri)
1300 {
1301 Eterm s1, s2;
1302 if (uri->type == URI_STAR) {
1303 return am_Times; /* '*' */
1304 }
1305
1306 s1 = http_bld_string(pca, hpp, szp, uri->s1_ptr, uri->s1_len);
1307
1308 switch (uri->type) {
1309 case URI_ABS_PATH:
1310 return erts_bld_tuple(hpp, szp, 2, am_abs_path, s1);
1311 case URI_HTTP:
1312 case URI_HTTPS:
1313 s2 = http_bld_string(pca, hpp, szp, uri->s2_ptr, uri->s2_len);
1314 return erts_bld_tuple
1315 (hpp, szp, 5, am_absoluteURI,
1316 ((uri->type==URI_HTTP) ? am_http : am_https),
1317 s1,
1318 ((uri->port==0) ? am_undefined : make_small(uri->port)),
1319 s2);
1320
1321 case URI_STRING:
1322 return s1;
1323 case URI_SCHEME:
1324 s2 = http_bld_string(pca, hpp, szp, uri->s2_ptr, uri->s2_len);
1325 return erts_bld_tuple(hpp, szp, 3, am_scheme, s1, s2);
1326
1327 default:
1328 erts_exit(ERTS_ERROR_EXIT, "%s, line %d: type=%u\n", __FILE__, __LINE__, uri->type);
1329 }
1330 }
1331
http_request_erl(void * arg,const http_atom_t * meth,const char * meth_ptr,int meth_len,const PacketHttpURI * uri,int major,int minor)1332 static int http_request_erl(void* arg, const http_atom_t* meth,
1333 const char* meth_ptr, int meth_len,
1334 const PacketHttpURI* uri, int major, int minor)
1335 {
1336 struct packet_callback_args* pca = (struct packet_callback_args*) arg;
1337 Eterm meth_term, uri_term, ver_term;
1338 Uint sz = 0;
1339 Uint* szp = &sz;
1340 Eterm* hp;
1341 Eterm** hpp = NULL;
1342
1343 /* {http_request,Meth,Uri,Version} */
1344
1345 for (;;) {
1346 meth_term = (meth!=NULL) ? meth->atom :
1347 http_bld_string(pca, hpp, szp, meth_ptr, meth_len);
1348 uri_term = http_bld_uri(pca, hpp, szp, uri);
1349 ver_term = erts_bld_tuple(hpp, szp, 2,
1350 make_small(major), make_small(minor));
1351 pca->res = erts_bld_tuple(hpp, szp, 4, am_http_request, meth_term,
1352 uri_term, ver_term);
1353 if (hpp != NULL) break;
1354 hpp = &hp;
1355 hp = HAlloc(pca->p, sz);
1356 szp = NULL;
1357 }
1358 return 1;
1359 }
1360
1361 static int
http_header_erl(void * arg,const http_atom_t * name,const char * name_ptr,int name_len,const char * oname_ptr,int oname_len,const char * value_ptr,int value_len)1362 http_header_erl(void* arg, const http_atom_t* name,
1363 const char* name_ptr, int name_len,
1364 const char* oname_ptr, int oname_len,
1365 const char* value_ptr, int value_len)
1366 {
1367 struct packet_callback_args* pca = (struct packet_callback_args*) arg;
1368 Eterm bit_term, name_term, oname_term, val_term;
1369 Uint sz = 6;
1370 Eterm* hp;
1371 #ifdef DEBUG
1372 Eterm* hend;
1373 #endif
1374
1375 /* {http_header,Bit,Name,Oname,Value} */
1376
1377 if (name == NULL) {
1378 http_bld_string(pca, NULL, &sz, name_ptr, name_len);
1379 }
1380 http_bld_string(pca, NULL, &sz, oname_ptr, oname_len);
1381 http_bld_string(pca, NULL, &sz, value_ptr, value_len);
1382
1383 hp = HAlloc(pca->p, sz);
1384 #ifdef DEBUG
1385 hend = hp + sz;
1386 #endif
1387
1388 if (name != NULL) {
1389 bit_term = make_small(name->index+1);
1390 name_term = name->atom;
1391 }
1392 else {
1393 bit_term = make_small(0);
1394 name_term = http_bld_string(pca, &hp,NULL,name_ptr,name_len);
1395 }
1396
1397 oname_term = http_bld_string(pca, &hp, NULL, oname_ptr, oname_len);
1398 val_term = http_bld_string(pca, &hp, NULL, value_ptr, value_len);
1399 pca->res = TUPLE5(hp, am_http_header, bit_term, name_term, oname_term, val_term);
1400 ASSERT(hp+6==hend);
1401 return 1;
1402 }
1403
http_eoh_erl(void * arg)1404 static int http_eoh_erl(void* arg)
1405 {
1406 /* http_eoh */
1407 struct packet_callback_args* pca = (struct packet_callback_args*) arg;
1408 pca->res = am_http_eoh;
1409 return 1;
1410 }
1411
http_error_erl(void * arg,const char * buf,int len)1412 static int http_error_erl(void* arg, const char* buf, int len)
1413 {
1414 /* {http_error,Line} */
1415 struct packet_callback_args* pca = (struct packet_callback_args*) arg;
1416 Uint sz = 3;
1417 Eterm* hp;
1418 #ifdef DEBUG
1419 Eterm* hend;
1420 #endif
1421
1422 http_bld_string(pca, NULL, &sz, buf, len);
1423
1424 hp = HAlloc(pca->p, sz);
1425 #ifdef DEBUG
1426 hend = hp + sz;
1427 #endif
1428 pca->res = erts_bld_tuple(&hp, NULL, 2, am_http_error,
1429 http_bld_string(pca, &hp, NULL, buf, len));
1430 ASSERT(hp==hend);
1431 return 1;
1432 }
1433
1434 static
ssl_tls_erl(void * arg,unsigned type,unsigned major,unsigned minor,const char * buf,int len,const char * prefix,int plen)1435 int ssl_tls_erl(void* arg, unsigned type, unsigned major, unsigned minor,
1436 const char* buf, int len, const char* prefix, int plen)
1437 {
1438 struct packet_callback_args* pca = (struct packet_callback_args*) arg;
1439 Eterm* hp;
1440 Eterm ver;
1441 Eterm bin = new_binary(pca->p, NULL, plen+len);
1442 byte* bin_ptr = binary_bytes(bin);
1443
1444 sys_memcpy(bin_ptr+plen, buf, len);
1445 if (plen) {
1446 sys_memcpy(bin_ptr, prefix, plen);
1447 }
1448
1449 /* {ssl_tls,NIL,ContentType,{Major,Minor},Bin} */
1450 hp = HAlloc(pca->p, 3+6);
1451 ver = TUPLE2(hp, make_small(major), make_small(minor));
1452 hp += 3;
1453 pca->res = TUPLE5(hp, am_ssl_tls, NIL, make_small(type), ver, bin);
1454 return 1;
1455 }
1456
1457
1458 PacketCallbacks packet_callbacks_erl = {
1459 http_response_erl,
1460 http_request_erl,
1461 http_eoh_erl,
1462 http_header_erl,
1463 http_error_erl,
1464 ssl_tls_erl
1465 };
1466
1467 /*
1468 decode_packet(Type,Bin,Options)
1469 Returns:
1470 {ok, PacketBodyBin, RestBin}
1471 {more, PacketSz | undefined}
1472 {error, invalid}
1473 */
decode_packet_3(BIF_ALIST_3)1474 BIF_RETTYPE decode_packet_3(BIF_ALIST_3)
1475 {
1476 unsigned max_plen = 0; /* Packet max length, 0=no limit */
1477 unsigned trunc_len = 0; /* Truncate lines if longer, 0=no limit */
1478 int http_state = 0; /* 0=request/response 1=header */
1479 int packet_sz; /*-------Binaries involved: ------------------*/
1480 byte* bin_ptr; /*| orig: original binary */
1481 byte bin_bitsz; /*| bin: BIF_ARG_2, may be sub-binary of orig */
1482 /*| packet: prefix of bin */
1483 char* body_ptr; /*| body: part of packet to return */
1484 int body_sz; /*| rest: bin without packet */
1485 struct packet_callback_args pca;
1486 enum PacketParseType type;
1487 Eterm* hp;
1488 Eterm* hend;
1489 ErlSubBin* rest;
1490 Eterm res;
1491 Eterm options;
1492 int code;
1493 char delimiter = '\n';
1494
1495 switch (BIF_ARG_1) {
1496 case make_small(0): case am_raw: type = TCP_PB_RAW; break;
1497 case make_small(1): type = TCP_PB_1; break;
1498 case make_small(2): type = TCP_PB_2; break;
1499 case make_small(4): type = TCP_PB_4; break;
1500 case am_asn1: type = TCP_PB_ASN1; break;
1501 case am_sunrm: type = TCP_PB_RM; break;
1502 case am_cdr: type = TCP_PB_CDR; break;
1503 case am_fcgi: type = TCP_PB_FCGI; break;
1504 case am_line: type = TCP_PB_LINE_LF; break;
1505 case am_tpkt: type = TCP_PB_TPKT; break;
1506 case am_http: type = TCP_PB_HTTP; break;
1507 case am_httph: type = TCP_PB_HTTPH; break;
1508 case am_http_bin: type = TCP_PB_HTTP_BIN; break;
1509 case am_httph_bin: type = TCP_PB_HTTPH_BIN; break;
1510 case am_ssl_tls: type = TCP_PB_SSL_TLS; break;
1511 default:
1512 BIF_P->fvalue = am_badopt;
1513 BIF_ERROR(BIF_P, BADARG | EXF_HAS_EXT_INFO);
1514 }
1515
1516 if (!is_binary(BIF_ARG_2) ||
1517 (!is_list(BIF_ARG_3) && !is_nil(BIF_ARG_3))) {
1518 BIF_ERROR(BIF_P, BADARG);
1519 }
1520
1521 options = BIF_ARG_3;
1522 while (!is_nil(options)) {
1523 Eterm* cons = list_val(options);
1524 if (is_tuple(CAR(cons))) {
1525 Eterm* tpl = tuple_val(CAR(cons));
1526 Uint val;
1527 if (tpl[0] == make_arityval(2) &&
1528 term_to_Uint(tpl[2],&val) && val <= UINT_MAX) {
1529 switch (tpl[1]) {
1530 case am_packet_size:
1531 max_plen = val;
1532 goto next_option;
1533 case am_line_length:
1534 trunc_len = val;
1535 goto next_option;
1536 case am_line_delimiter:
1537 if (type == TCP_PB_LINE_LF && val <= 255) {
1538 delimiter = (char)val;
1539 goto next_option;
1540 }
1541 }
1542 }
1543 }
1544 BIF_ERROR(BIF_P, BADARG);
1545
1546 next_option:
1547 options = CDR(cons);
1548 }
1549
1550
1551 pca.bin_sz = binary_size(BIF_ARG_2);
1552 ERTS_GET_BINARY_BYTES(BIF_ARG_2, bin_ptr, pca.bin_bitoffs, bin_bitsz);
1553 if (pca.bin_bitoffs != 0) {
1554 pca.aligned_ptr = erts_alloc(ERTS_ALC_T_TMP, pca.bin_sz);
1555 erts_copy_bits(bin_ptr, pca.bin_bitoffs, 1, pca.aligned_ptr, 0, 1, pca.bin_sz*8);
1556 }
1557 else {
1558 pca.aligned_ptr = bin_ptr;
1559 }
1560 packet_sz = packet_get_length(type, (char*)pca.aligned_ptr, pca.bin_sz,
1561 max_plen, trunc_len, delimiter, &http_state);
1562 if (!(packet_sz > 0 && packet_sz <= pca.bin_sz)) {
1563 if (packet_sz < 0) {
1564 goto error;
1565 }
1566 else { /* not enough data */
1567 Eterm plen = (packet_sz==0) ? am_undefined :
1568 erts_make_integer(packet_sz, BIF_P);
1569 Eterm* hp = HAlloc(BIF_P,3);
1570 res = TUPLE2(hp, am_more, plen);
1571 goto done;
1572 }
1573 }
1574 /* We got a whole packet */
1575
1576 body_ptr = (char*) pca.aligned_ptr;
1577 body_sz = packet_sz;
1578 packet_get_body(type, (const char**) &body_ptr, &body_sz);
1579
1580 ERTS_GET_REAL_BIN(BIF_ARG_2, pca.orig, pca.bin_offs, pca.bin_bitoffs, bin_bitsz);
1581 pca.p = BIF_P;
1582 pca.res = THE_NON_VALUE;
1583 pca.string_as_bin = (type == TCP_PB_HTTP_BIN || type == TCP_PB_HTTPH_BIN);
1584 code = packet_parse(type, (char*)pca.aligned_ptr, packet_sz, &http_state,
1585 &packet_callbacks_erl, &pca);
1586 if (code == 0) { /* no special packet parsing, make plain binary */
1587 ErlSubBin* body;
1588 Uint hsz = 2*ERL_SUB_BIN_SIZE + 4;
1589 hp = HAlloc(BIF_P, hsz);
1590 hend = hp + hsz;
1591
1592 body = (ErlSubBin *) hp;
1593 body->thing_word = HEADER_SUB_BIN;
1594 body->size = body_sz;
1595 body->offs = pca.bin_offs + (body_ptr - (char*)pca.aligned_ptr);
1596 body->orig = pca.orig;
1597 body->bitoffs = pca.bin_bitoffs;
1598 body->bitsize = 0;
1599 body->is_writable = 0;
1600 hp += ERL_SUB_BIN_SIZE;
1601 pca.res = make_binary(body);
1602 }
1603 else if (code > 0) {
1604 Uint hsz = ERL_SUB_BIN_SIZE + 4;
1605 ASSERT(pca.res != THE_NON_VALUE);
1606 hp = HAlloc(BIF_P, hsz);
1607 hend = hp + hsz;
1608 }
1609 else {
1610 error:
1611 hp = HAlloc(BIF_P,3);
1612 res = TUPLE2(hp, am_error, am_invalid);
1613 goto done;
1614 }
1615
1616 rest = (ErlSubBin *) hp;
1617 rest->thing_word = HEADER_SUB_BIN;
1618 rest->size = pca.bin_sz - packet_sz;
1619 rest->offs = pca.bin_offs + packet_sz;
1620 rest->orig = pca.orig;
1621 rest->bitoffs = pca.bin_bitoffs;
1622 rest->bitsize = bin_bitsz; /* The extra bits go into the rest. */
1623 rest->is_writable = 0;
1624 hp += ERL_SUB_BIN_SIZE;
1625 res = TUPLE3(hp, am_ok, pca.res, make_binary(rest));
1626 hp += 4;
1627 ASSERT(hp==hend); (void)hend;
1628
1629 done:
1630 if (pca.aligned_ptr != bin_ptr) {
1631 erts_free(ERTS_ALC_T_TMP, pca.aligned_ptr);
1632 }
1633 BIF_RET(res);
1634 }
1635
1636