libnm: buffer reads in nm_vpn_service_plugin_read_vpn_details()

It seems very ugly to read one byte at a time. Use a naive buffered
reader, so that we can read multiple bytes at a time, and return them
one by one.

Also, this now keeps state of any error/EOF. Once we reach EOF, we won't
read again. The previous code did that too, but I think this code is
easier to read.
This commit is contained in:
Thomas Haller
2021-05-25 14:23:10 +02:00
parent 1338a2ef96
commit 4a9fcb0fc3

View File

@@ -729,6 +729,54 @@ nm_vpn_service_plugin_secrets_required(NMVpnServicePlugin *plugin,
/*****************************************************************************/
typedef struct {
char *buf;
gsize n_buf;
int fd;
bool eof : 1;
char buf_full[1024];
} ReadFdBuf;
static inline gboolean
_read_fd_buf_c(ReadFdBuf *read_buf, char *ch)
{
gssize n_read;
if (read_buf->n_buf > 0)
goto out_data;
if (read_buf->eof)
return FALSE;
again:
n_read = read(read_buf->fd, read_buf->buf_full, sizeof(read_buf->buf_full));
if (n_read <= 0) {
if (n_read < 0 && errno == EAGAIN) {
struct pollfd pfd;
int r;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = read_buf->fd;
pfd.events = POLLIN;
r = poll(&pfd, 1, -1);
if (r > 0)
goto again;
/* error or timeout. Fall through and set EOF. */
}
read_buf->eof = TRUE;
return FALSE;
}
read_buf->buf = read_buf->buf_full;
read_buf->n_buf = n_read;
out_data:
read_buf->n_buf--;
*ch = read_buf->buf[0];
read_buf->buf++;
return TRUE;
}
#define DATA_KEY_TAG "DATA_KEY="
#define DATA_VAL_TAG "DATA_VAL="
#define SECRET_KEY_TAG "SECRET_KEY="
@@ -759,8 +807,8 @@ nm_vpn_service_plugin_read_vpn_details(int fd, GHashTable **out_data, GHashTable
nm_auto_free_gstring GString *key = NULL;
nm_auto_free_gstring GString *val = NULL;
nm_auto_free_gstring GString *line = NULL;
char c;
GString * str = NULL;
GString * str = NULL;
ReadFdBuf read_buf;
if (out_data)
g_return_val_if_fail(*out_data == NULL, FALSE);
@@ -771,31 +819,21 @@ nm_vpn_service_plugin_read_vpn_details(int fd, GHashTable **out_data, GHashTable
secrets =
g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, (GDestroyNotify) nm_free_secret);
read_buf.buf = NULL;
read_buf.n_buf = 0;
read_buf.fd = fd;
read_buf.eof = FALSE;
line = g_string_new(NULL);
/* Read stdin for data and secret items until we get a DONE */
while (1) {
ssize_t nr;
gboolean eof;
char c;
nr = read(fd, &c, 1);
if (nr < 0) {
if (errno == EAGAIN) {
struct pollfd pfd;
int r;
eof = !_read_fd_buf_c(&read_buf, &c);
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fd;
pfd.events = POLLIN;
r = poll(&pfd, 1, -1);
if (r > 0)
continue;
/* error or timeout. Fall through and break. */
}
break;
}
if (nr > 0 && c != '\n') {
if (!eof && c != '\n') {
g_string_append_c(line, c);
continue;
}
@@ -841,7 +879,7 @@ nm_vpn_service_plugin_read_vpn_details(int fd, GHashTable **out_data, GHashTable
g_string_truncate(line, 0);
if (nr == 0)
if (eof)
break;
}