Skip to content

Commit 0719ae6

Browse files
authored
Merge pull request #5703 from grondo/pty-fix
enable encode of pty data as base64 and make `flux alloc vi` test more reliable
2 parents 13311a9 + e1d6216 commit 0719ae6

File tree

5 files changed

+169
-18
lines changed

5 files changed

+169
-18
lines changed

src/common/libterminus/client.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "src/common/libczmqcontainers/czmq_containers.h"
2727
#include "src/common/libutil/fdutils.h"
2828
#include "src/common/libutil/llog.h"
29+
#include "src/common/libutil/errno_safe.h"
2930
#include "ccan/str/str.h"
3031

3132
#include "pty.h"
@@ -257,11 +258,17 @@ static void pty_client_attached (struct flux_pty_client *c)
257258

258259
static void pty_client_data (struct flux_pty_client *c, flux_future_t *f)
259260
{
260-
const char *data;
261+
const flux_msg_t *msg;
262+
char *data;
261263
size_t len;
264+
flux_error_t error;
262265

263-
if (flux_rpc_get_unpack (f, "{s:s%}", "data", &data, &len) < 0) {
264-
llog_error (c, "unpack: %s", future_strerror (f, errno));
266+
if (flux_future_get (f, (const void **)&msg) < 0) {
267+
llog_error (c, "data response: %s", future_strerror (f, errno));
268+
return;
269+
}
270+
if (pty_data_unpack (msg, &error, &data, &len) < 0) {
271+
llog_error (c, "unpack: %s", error.text);
265272
return;
266273
}
267274
if (write (STDIN_FILENO, data, len) < 0) {
@@ -407,14 +414,18 @@ flux_future_t *flux_pty_client_write (struct flux_pty_client *c,
407414
const void *buf,
408415
ssize_t len)
409416
{
417+
flux_future_t *f;
418+
json_t *o = NULL;
419+
410420
if (!c || !buf || len < 0) {
411421
errno = EINVAL;
412422
return NULL;
413423
}
414-
return flux_rpc_pack (c->h, c->service, c->rank, 0,
415-
"{s:s s:s%}",
416-
"type", "data",
417-
"data", buf, len);
424+
if (!(o = pty_data_encode (buf, len)) )
425+
return NULL;
426+
f = flux_rpc_pack (c->h, c->service, c->rank, 0, "O", o);
427+
ERRNO_SAFE_WRAP (json_decref, o);
428+
return f;
418429
}
419430

420431
static void pty_read_cb (flux_reactor_t *r,

src/common/libterminus/pty.c

Lines changed: 127 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@
5656
#include "src/common/libutil/fdutils.h"
5757
#include "src/common/libutil/errno_safe.h"
5858
#include "src/common/libutil/aux.h"
59+
#include "src/common/libutil/errprintf.h"
5960
#include "ccan/str/str.h"
61+
#include "ccan/base64/base64.h"
6062

6163
#define LLOG_SUBSYSTEM "pty"
6264
#include "src/common/libutil/llog.h"
@@ -405,6 +407,55 @@ int flux_pty_attach (struct flux_pty *pty)
405407
return 0;
406408
}
407409

410+
static int encode_base64 (const char *data, int len, char **destp, int *lenp)
411+
{
412+
ssize_t n;
413+
char *dest = NULL;
414+
size_t destlen = base64_encoded_length (len) + 1;
415+
416+
if (!(dest = malloc (destlen))
417+
|| ((n = base64_encode (dest, destlen, data, len)) < 0))
418+
return -1;
419+
*destp = dest;
420+
*lenp = n;
421+
return 0;
422+
}
423+
424+
static json_t *pty_data_encode_base64 (const void *data, int len)
425+
{
426+
json_t *o = NULL;
427+
char *b64data = NULL;
428+
int b64len = 0;
429+
430+
if (encode_base64 (data, len, &b64data, &b64len) < 0)
431+
return NULL;
432+
433+
o = json_pack ("{s:s s:s s:s#}",
434+
"type", "data",
435+
"encoding", "base64",
436+
"data", b64data, b64len);
437+
438+
ERRNO_SAFE_WRAP (free, b64data);
439+
return o;
440+
}
441+
442+
json_t *pty_data_encode (const void *data, int len)
443+
{
444+
json_t *o;
445+
446+
if (!(o = json_pack ("{s:s s:s#}",
447+
"type", "data",
448+
"data", (char *) data, len))) {
449+
/*
450+
* json_pack() may fail if there are bytes that cannot be encoded
451+
* as UTF-8, e.g. U+0000 is specifically not allowed in jansson.
452+
* Try encoding as base64 instead.
453+
*/
454+
o = pty_data_encode_base64 (data, len);
455+
}
456+
return o;
457+
}
458+
408459
void pty_client_send_data (struct flux_pty *pty, void *data, int len)
409460
{
410461
struct pty_client *c = zlist_first (pty->clients);
@@ -414,12 +465,10 @@ void pty_client_send_data (struct flux_pty *pty, void *data, int len)
414465

415466
while (c) {
416467
if (c->read_enabled) {
417-
if (flux_respond_pack (pty->h,
418-
c->req,
419-
"{s:s s:s#}",
420-
"type", "data",
421-
"data", (char *) data, len) < 0)
468+
json_t *o = pty_data_encode (data, len);
469+
if (!o || flux_respond_pack (pty->h, c->req, "O", o) < 0)
422470
llog_error (pty, "send data: %s", strerror (errno));
471+
json_decref (o);
423472
}
424473
c = zlist_next (pty->clients);
425474
}
@@ -570,12 +619,82 @@ static int pty_attach (struct flux_pty *pty, const flux_msg_t *msg)
570619
return -1;
571620
}
572621

622+
static int decode_base64 (char *src,
623+
size_t srclen,
624+
char **datap,
625+
size_t *lenp)
626+
{
627+
ssize_t rc;
628+
char *data;
629+
size_t size = base64_decoded_length (srclen) + 1;
630+
631+
if (!(data = malloc (size)))
632+
return -1;
633+
if ((rc = base64_decode (data, size, src, srclen)) < 0) {
634+
ERRNO_SAFE_WRAP (free, data);
635+
return -1;
636+
}
637+
*lenp = rc;
638+
*datap = data;
639+
return 0;
640+
}
641+
642+
int pty_data_unpack (const flux_msg_t *msg,
643+
flux_error_t *errp,
644+
char **datap,
645+
size_t *lenp)
646+
{
647+
const char *encoding = NULL;
648+
void *data;
649+
int len;
650+
651+
if (flux_msg_unpack (msg,
652+
"{s:s s?s}",
653+
"data", &data,
654+
"encoding", &encoding) < 0)
655+
return errprintf (errp,
656+
"failed to unpack data msg: %s",
657+
strerror (errno));
658+
len = strlen (data);
659+
660+
if (encoding) {
661+
if (streq (encoding, "base64")) {
662+
char *b64data = NULL;
663+
size_t b64len;
664+
if (decode_base64 (data, len, &b64data, &b64len) < 0) {
665+
return errprintf (errp,
666+
"failed to decode %d bytes of base64",
667+
len);
668+
}
669+
if (flux_msg_aux_set (msg, NULL, b64data, free) < 0) {
670+
ERRNO_SAFE_WRAP (free, b64data);
671+
return errprintf (errp,
672+
"flux_msg_aux_set: %s",
673+
strerror (errno));
674+
}
675+
data = b64data;
676+
len = b64len;
677+
}
678+
else {
679+
errno = EPROTO;
680+
return errprintf (errp,
681+
"invalid pty data encoding: %s",
682+
encoding);
683+
}
684+
}
685+
*datap = data;
686+
*lenp = len;
687+
return 0;
688+
}
689+
573690
static int pty_write (struct flux_pty *pty, const flux_msg_t *msg)
574691
{
575-
const char *data;
692+
char *data;
576693
size_t len;
577-
if (flux_msg_unpack (msg, "{s:s%}", "data", &data, &len) < 0) {
578-
llog_error (pty, "msg_unpack failed");
694+
flux_error_t error;
695+
696+
if (pty_data_unpack (msg, &error, &data, &len) < 0) {
697+
llog_error (pty, "%s", error.text);
579698
return -1;
580699
}
581700
if (write (pty->leader, data, len) < 0) {

src/common/libterminus/pty.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef FLUX_PTY_H
1414
#define FLUX_PTY_H
1515

16+
#include <jansson.h>
1617
#include <flux/core.h>
1718

1819
typedef void (*pty_log_f) (void *arg,
@@ -201,10 +202,23 @@ int flux_pty_aux_set (struct flux_pty *pty,
201202

202203
void * flux_pty_aux_get (struct flux_pty *pty, const char *name);
203204

205+
204206
/* Function exported for testing only
205207
*/
206208
void pty_client_send_data (struct flux_pty *pty, void *data, int len);
207209

210+
211+
/* Common function for unpacking pty data msg.
212+
*/
213+
int pty_data_unpack (const flux_msg_t *msg,
214+
flux_error_t *errp,
215+
char **datap,
216+
size_t *lenp);
217+
218+
/* Common function for encoding pty data msg.
219+
*/
220+
json_t *pty_data_encode (const void *data, int len);
221+
208222
#endif /* !FLUX_PTY_H */
209223

210224
/*

src/common/libterminus/test/pty.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,14 @@ static void test_client (void)
433433
rc == 0 ? "Success" : strerror (errno));
434434
flux_future_destroy (f);
435435

436+
f = flux_pty_client_write (c, "bar\0\r\n", 6);
437+
ok (f != NULL,
438+
"flux_pty_client_write with U+0000");
439+
ok (rc == 0,
440+
"flux_pty_client_write: %s",
441+
rc == 0 ? "Success" : strerror (errno));
442+
flux_future_destroy (f);
443+
436444
ok (flux_pty_client_detach (c) == 0,
437445
"flux_pty_client_detach");
438446

t/t2712-python-cli-alloc.t

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,12 @@ test_expect_success 'flux alloc: resource.norestrict works in subinstance' '
173173
'
174174
test_expect_success 'flux alloc: flux alloc vi works' '
175175
cat <<-'EOF' >input.json &&
176-
[{"expect":"test\\\.txt", "send":":q!\n", "timeout":30}]
176+
[{"expect":"test text file", "send":":q!\n", "timeout":30}]
177177
EOF
178178
cat <<-EOF >test.txt &&
179179
test text file
180180
EOF
181-
$runpty -o vi.out --expect=input.json flux alloc -n1 vi test.txt &&
182-
grep "test text file" vi.out
181+
$runpty -o vi.out --expect=input.json flux alloc -n1 vi test.txt
183182
'
184183
test_expect_success 'flux alloc: flux alloc flux alloc works' '
185184
cat <<-'EOF' >input2.json &&

0 commit comments

Comments
 (0)