Merging upstream version 3.5.5 (Closes: #1098233).
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c86ae7dcba
commit
6af28b7e8e
144 changed files with 43534 additions and 11497 deletions
403
src/io.c
403
src/io.c
|
@ -1,9 +1,11 @@
|
|||
/**
|
||||
* \file io.c
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 - input/output functions
|
||||
* @file io.c
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 - input/output functions
|
||||
*
|
||||
* Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2024 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
|
@ -13,27 +15,30 @@
|
|||
*/
|
||||
|
||||
#define _GNU_SOURCE /* asprintf, signals */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <poll.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
# include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "libnetconf.h"
|
||||
#include "config.h"
|
||||
#include "log_p.h"
|
||||
#include "messages_p.h"
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
#include "session_p.h"
|
||||
#include "session_wrapper.h"
|
||||
|
||||
const char *nc_msgtype2str[] = {
|
||||
"error",
|
||||
|
@ -49,49 +54,13 @@ const char *nc_msgtype2str[] = {
|
|||
|
||||
#define BUFFERSIZE 512
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
static char *
|
||||
nc_ssl_error_get_reasons(void)
|
||||
{
|
||||
unsigned int e;
|
||||
int reason_size, reason_len;
|
||||
char *reasons = NULL;
|
||||
|
||||
reason_size = 1;
|
||||
reason_len = 0;
|
||||
while ((e = ERR_get_error())) {
|
||||
if (reason_len) {
|
||||
/* add "; " */
|
||||
reason_size += 2;
|
||||
reasons = nc_realloc(reasons, reason_size);
|
||||
if (!reasons) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
reason_len += sprintf(reasons + reason_len, "; ");
|
||||
}
|
||||
reason_size += strlen(ERR_reason_error_string(e));
|
||||
reasons = nc_realloc(reasons, reason_size);
|
||||
if (!reasons) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
reason_len += sprintf(reasons + reason_len, "%s", ERR_reason_error_string(e));
|
||||
}
|
||||
|
||||
return reasons;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static ssize_t
|
||||
nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_timeout, struct timespec *ts_act_timeout)
|
||||
nc_read(struct nc_session *session, char *buf, uint32_t count, uint32_t inact_timeout, struct timespec *ts_act_timeout)
|
||||
{
|
||||
size_t readd = 0;
|
||||
uint32_t readd = 0;
|
||||
ssize_t r = -1;
|
||||
int fd, interrupted;
|
||||
struct timespec ts_cur, ts_inact_timeout;
|
||||
struct timespec ts_inact_timeout;
|
||||
|
||||
assert(session);
|
||||
assert(buf);
|
||||
|
@ -104,8 +73,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
return 0;
|
||||
}
|
||||
|
||||
nc_gettimespec_mono(&ts_inact_timeout);
|
||||
nc_addtimespec(&ts_inact_timeout, inact_timeout);
|
||||
nc_timeouttime_get(&ts_inact_timeout, inact_timeout);
|
||||
do {
|
||||
interrupted = 0;
|
||||
switch (session->ti_type) {
|
||||
|
@ -139,8 +107,8 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
}
|
||||
break;
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
case NC_TI_LIBSSH:
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
case NC_TI_SSH:
|
||||
/* read via libssh */
|
||||
r = ssh_channel_read(session->ti.libssh.channel, buf + readd, count - readd, 0);
|
||||
if (r == SSH_AGAIN) {
|
||||
|
@ -161,48 +129,15 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
case NC_TI_OPENSSL:
|
||||
/* read via OpenSSL */
|
||||
ERR_clear_error();
|
||||
r = SSL_read(session->ti.tls, buf + readd, count - readd);
|
||||
if (r <= 0) {
|
||||
int e;
|
||||
char *reasons;
|
||||
|
||||
switch (e = SSL_get_error(session->ti.tls, r)) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
r = 0;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
ERR(session, "Communication socket unexpectedly closed (OpenSSL).");
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_DROPPED;
|
||||
return -1;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
ERR(session, "SSL socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
return -1;
|
||||
case SSL_ERROR_SSL:
|
||||
reasons = nc_ssl_error_get_reasons();
|
||||
ERR(session, "SSL error (%s).", reasons);
|
||||
free(reasons);
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
return -1;
|
||||
default:
|
||||
ERR(session, "Unknown SSL error occured (err code %d).", e);
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
return -1;
|
||||
}
|
||||
case NC_TI_TLS:
|
||||
r = nc_tls_read_wrap(session, (unsigned char *)buf + readd, count - readd);
|
||||
if (r < 0) {
|
||||
/* non-recoverable error */
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
|
@ -210,9 +145,8 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
if (!interrupted) {
|
||||
usleep(NC_TIMEOUT_STEP);
|
||||
}
|
||||
nc_gettimespec_mono(&ts_cur);
|
||||
if ((nc_difftimespec(&ts_cur, &ts_inact_timeout) < 1) || (nc_difftimespec(&ts_cur, ts_act_timeout) < 1)) {
|
||||
if (nc_difftimespec(&ts_cur, &ts_inact_timeout) < 1) {
|
||||
if ((nc_timeouttime_cur_diff(&ts_inact_timeout) < 1) || (nc_timeouttime_cur_diff(ts_act_timeout) < 1)) {
|
||||
if (nc_timeouttime_cur_diff(&ts_inact_timeout) < 1) {
|
||||
ERR(session, "Inactive read timeout elapsed.");
|
||||
} else {
|
||||
ERR(session, "Active read timeout elapsed.");
|
||||
|
@ -226,8 +160,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
readd += r;
|
||||
|
||||
/* reset inactive timeout */
|
||||
nc_gettimespec_mono(&ts_inact_timeout);
|
||||
nc_addtimespec(&ts_inact_timeout, inact_timeout);
|
||||
nc_timeouttime_get(&ts_inact_timeout, inact_timeout);
|
||||
}
|
||||
|
||||
} while (readd < count);
|
||||
|
@ -249,10 +182,7 @@ nc_read_chunk(struct nc_session *session, size_t len, uint32_t inact_timeout, st
|
|||
}
|
||||
|
||||
*chunk = malloc((len + 1) * sizeof **chunk);
|
||||
if (!*chunk) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!*chunk, -1);
|
||||
|
||||
r = nc_read(session, *chunk, len, inact_timeout, ts_act_timeout);
|
||||
if (r <= 0) {
|
||||
|
@ -282,10 +212,7 @@ nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint
|
|||
size = BUFFERSIZE;
|
||||
}
|
||||
chunk = malloc((size + 1) * sizeof *chunk);
|
||||
if (!chunk) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!chunk, -1);
|
||||
|
||||
len = strlen(endtag);
|
||||
while (1) {
|
||||
|
@ -301,10 +228,7 @@ nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint
|
|||
/* get more memory */
|
||||
size = size + BUFFERSIZE;
|
||||
chunk = nc_realloc(chunk, (size + 1) * sizeof *chunk);
|
||||
if (!chunk) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!chunk, -1);
|
||||
}
|
||||
|
||||
/* get another character */
|
||||
|
@ -362,8 +286,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
nc_gettimespec_mono(&ts_act_timeout);
|
||||
nc_addtimespec(&ts_act_timeout, NC_READ_ACT_TIMEOUT * 1000);
|
||||
nc_timeouttime_get(&ts_act_timeout, NC_READ_ACT_TIMEOUT * 1000);
|
||||
|
||||
if (!io_locked) {
|
||||
/* SESSION IO LOCK */
|
||||
|
@ -428,11 +351,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
|
|||
|
||||
/* realloc message buffer, remember to count terminating null byte */
|
||||
data = nc_realloc(data, len + chunk_len + 1);
|
||||
if (!data) {
|
||||
ERRMEM;
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
NC_CHECK_ERRMEM_GOTO(!data, ret = -1, cleanup);
|
||||
memcpy(data + len, chunk, chunk_len);
|
||||
len += chunk_len;
|
||||
data[len] = '\0';
|
||||
|
@ -469,7 +388,6 @@ cleanup:
|
|||
static int
|
||||
nc_read_poll(struct nc_session *session, int io_timeout)
|
||||
{
|
||||
sigset_t sigmask, origmask;
|
||||
int ret = -2;
|
||||
struct pollfd fds;
|
||||
|
||||
|
@ -479,8 +397,13 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
|||
}
|
||||
|
||||
switch (session->ti_type) {
|
||||
#ifdef NC_ENABLED_SSH
|
||||
case NC_TI_LIBSSH:
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
case NC_TI_SSH:
|
||||
if (io_timeout == -1) {
|
||||
/* BUG libssh 0.11.0 replaces timeout -1 with 0 for non-blocking sessions */
|
||||
io_timeout = INT_MAX;
|
||||
}
|
||||
|
||||
/* EINTR is handled, it resumes waiting */
|
||||
ret = ssh_channel_poll_timeout(session->ti.libssh.channel, io_timeout, 0);
|
||||
if (ret == SSH_ERROR) {
|
||||
|
@ -501,10 +424,8 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
|||
fds.revents = 0;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
case NC_TI_OPENSSL:
|
||||
ret = SSL_pending(session->ti.tls);
|
||||
case NC_TI_TLS:
|
||||
ret = nc_tls_get_num_pending_bytes_wrap(session->ti.tls.session);
|
||||
if (ret) {
|
||||
/* some buffered TLS data available */
|
||||
ret = 1;
|
||||
|
@ -512,8 +433,8 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
|||
break;
|
||||
}
|
||||
|
||||
fds.fd = SSL_get_fd(session->ti.tls);
|
||||
#endif
|
||||
fds.fd = nc_tls_get_fd_wrap(session);
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
/* fallthrough */
|
||||
case NC_TI_FD:
|
||||
case NC_TI_UNIX:
|
||||
|
@ -526,11 +447,7 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
|||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
|
||||
sigfillset(&sigmask);
|
||||
pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
|
||||
ret = poll(&fds, 1, io_timeout);
|
||||
pthread_sigmask(SIG_SETMASK, &origmask, NULL);
|
||||
|
||||
ret = nc_poll(&fds, 1, io_timeout);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -600,7 +517,7 @@ nc_read_msg_poll_io(struct nc_session *session, int io_timeout, struct ly_in **m
|
|||
|
||||
/* does not really log, only fatal errors */
|
||||
int
|
||||
nc_session_is_connected(struct nc_session *session)
|
||||
nc_session_is_connected(const struct nc_session *session)
|
||||
{
|
||||
int ret;
|
||||
struct pollfd fds;
|
||||
|
@ -612,15 +529,13 @@ nc_session_is_connected(struct nc_session *session)
|
|||
case NC_TI_UNIX:
|
||||
fds.fd = session->ti.unixsock.sock;
|
||||
break;
|
||||
#ifdef NC_ENABLED_SSH
|
||||
case NC_TI_LIBSSH:
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
case NC_TI_SSH:
|
||||
return ssh_is_connected(session->ti.libssh.session);
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
case NC_TI_OPENSSL:
|
||||
fds.fd = SSL_get_fd(session->ti.tls);
|
||||
case NC_TI_TLS:
|
||||
fds.fd = nc_tls_get_fd_wrap(session);
|
||||
break;
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -632,11 +547,8 @@ nc_session_is_connected(struct nc_session *session)
|
|||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
|
||||
errno = 0;
|
||||
while (((ret = poll(&fds, 1, 0)) == -1) && (errno == EINTR)) {}
|
||||
|
||||
ret = nc_poll(&fds, 1, 0);
|
||||
if (ret == -1) {
|
||||
ERR(session, "poll failed (%s).", strerror(errno));
|
||||
return 0;
|
||||
} else if ((ret > 0) && (fds.revents & (POLLHUP | POLLERR))) {
|
||||
return 0;
|
||||
|
@ -646,21 +558,26 @@ nc_session_is_connected(struct nc_session *session)
|
|||
}
|
||||
|
||||
#define WRITE_BUFSIZE (2 * BUFFERSIZE)
|
||||
struct wclb_arg {
|
||||
struct nc_wclb_arg {
|
||||
struct nc_session *session;
|
||||
char buf[WRITE_BUFSIZE];
|
||||
size_t len;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Write to a NETCONF session.
|
||||
*
|
||||
* @param[in] session Session to write to.
|
||||
* @param[in] buf Buffer to write.
|
||||
* @param[in] count Count of bytes from @p buf to write.
|
||||
* @return Number of bytes written.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_write(struct nc_session *session, const void *buf, size_t count)
|
||||
nc_write(struct nc_session *session, const void *buf, uint32_t count)
|
||||
{
|
||||
int c, fd, interrupted;
|
||||
size_t written = 0;
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
unsigned long e;
|
||||
#endif
|
||||
uint32_t written = 0;
|
||||
|
||||
if ((session->status != NC_STATUS_RUNNING) && (session->status != NC_STATUS_STARTING)) {
|
||||
return -1;
|
||||
|
@ -674,7 +591,7 @@ nc_write(struct nc_session *session, const void *buf, size_t count)
|
|||
return -1;
|
||||
}
|
||||
|
||||
DBG(session, "Sending message:\n%.*s\n", count, buf);
|
||||
DBG(session, "Sending message:\n%.*s\n", (int)count, buf);
|
||||
|
||||
do {
|
||||
interrupted = 0;
|
||||
|
@ -689,13 +606,13 @@ nc_write(struct nc_session *session, const void *buf, size_t count)
|
|||
c = 0;
|
||||
interrupted = 1;
|
||||
} else if (c < 0) {
|
||||
ERR(session, "socket error (%s).", strerror(errno));
|
||||
ERR(session, "Socket error (%s).", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
case NC_TI_LIBSSH:
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
case NC_TI_SSH:
|
||||
if (ssh_channel_is_closed(session->ti.libssh.channel) || ssh_channel_is_eof(session->ti.libssh.channel)) {
|
||||
if (ssh_channel_is_closed(session->ti.libssh.channel)) {
|
||||
ERR(session, "SSH channel unexpectedly closed.");
|
||||
|
@ -712,36 +629,14 @@ nc_write(struct nc_session *session, const void *buf, size_t count)
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
case NC_TI_OPENSSL:
|
||||
c = SSL_write(session->ti.tls, (char *)(buf + written), count - written);
|
||||
if (c < 1) {
|
||||
char *reasons;
|
||||
|
||||
switch ((e = SSL_get_error(session->ti.tls, c))) {
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
ERR(session, "SSL connection was properly closed.");
|
||||
return -1;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
case SSL_ERROR_WANT_READ:
|
||||
c = 0;
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
ERR(session, "SSL socket error (%s).", strerror(errno));
|
||||
return -1;
|
||||
case SSL_ERROR_SSL:
|
||||
reasons = nc_ssl_error_get_reasons();
|
||||
ERR(session, "SSL error (%s).", reasons);
|
||||
free(reasons);
|
||||
return -1;
|
||||
default:
|
||||
ERR(session, "Unknown SSL error occured (err code %d).", e);
|
||||
return -1;
|
||||
}
|
||||
case NC_TI_TLS:
|
||||
c = nc_tls_write_wrap(session, (const unsigned char *)(buf + written), count - written);
|
||||
if (c < 0) {
|
||||
/* possible client dc, or some socket/TLS communication error */
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
default:
|
||||
ERRINT;
|
||||
return -1;
|
||||
|
@ -758,30 +653,47 @@ nc_write(struct nc_session *session, const void *buf, size_t count)
|
|||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the start tag and the message part of a chunked-framing NETCONF message.
|
||||
*
|
||||
* @param[in] session Session to write to.
|
||||
* @param[in] buf Message buffer to write.
|
||||
* @param[in] count Count of bytes from @p buf to write.
|
||||
* @return Number of bytes written.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_write_starttag_and_msg(struct nc_session *session, const void *buf, size_t count)
|
||||
nc_write_starttag_and_msg(struct nc_session *session, const void *buf, uint32_t count)
|
||||
{
|
||||
int ret = 0, c;
|
||||
int ret = 0, r;
|
||||
char chunksize[24];
|
||||
|
||||
// warning: ‘%zu’ directive writing between 4 and 20 bytes into a region of size 18 [-Wformat-overflow=]
|
||||
if (session->version == NC_VERSION_11) {
|
||||
sprintf(chunksize, "\n#%zu\n", count);
|
||||
ret = nc_write(session, chunksize, strlen(chunksize));
|
||||
if (ret == -1) {
|
||||
r = sprintf(chunksize, "\n#%" PRIu32 "\n", count);
|
||||
|
||||
r = nc_write(session, chunksize, r);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
ret += r;
|
||||
}
|
||||
|
||||
c = nc_write(session, buf, count);
|
||||
if (c == -1) {
|
||||
r = nc_write(session, buf, count);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
ret += c;
|
||||
ret += r;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the end tag part of a chunked-framing NETCONF message.
|
||||
*
|
||||
* @param[in] session Session to write to.
|
||||
* @return Number of bytes written.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_write_endtag(struct nc_session *session)
|
||||
{
|
||||
|
@ -796,8 +708,15 @@ nc_write_endtag(struct nc_session *session)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Flush all the data buffered for writing.
|
||||
*
|
||||
* @param[in] warg Write callback structure to flush.
|
||||
* @return Number of written bytes.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_write_clb_flush(struct wclb_arg *warg)
|
||||
nc_write_clb_flush(struct nc_wclb_arg *warg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -810,12 +729,22 @@ nc_write_clb_flush(struct wclb_arg *warg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write callback buffering the data in a write structure.
|
||||
*
|
||||
* @param[in] arg Write structure used for buffering.
|
||||
* @param[in] buf Buffer to write.
|
||||
* @param[in] count Count of bytes to write from @p buf.
|
||||
* @param[in] xmlcontent Whether the data are actually printed as part of an XML in which case they need to be encoded.
|
||||
* @return Number of written bytes.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static ssize_t
|
||||
nc_write_clb(void *arg, const void *buf, size_t count, int xmlcontent)
|
||||
nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
|
||||
{
|
||||
int ret = 0, c;
|
||||
size_t l;
|
||||
struct wclb_arg *warg = (struct wclb_arg *)arg;
|
||||
ssize_t ret = 0, c;
|
||||
uint32_t l;
|
||||
struct nc_wclb_arg *warg = arg;
|
||||
|
||||
if (!buf) {
|
||||
c = nc_write_clb_flush(warg);
|
||||
|
@ -895,6 +824,9 @@ nc_write_clb(void *arg, const void *buf, size_t count, int xmlcontent)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write print callback used by libyang.
|
||||
*/
|
||||
static ssize_t
|
||||
nc_write_xmlclb(void *arg, const void *buf, size_t count)
|
||||
{
|
||||
|
@ -921,7 +853,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
struct nc_server_notif *notif;
|
||||
struct nc_server_reply *reply;
|
||||
char *buf;
|
||||
struct wclb_arg arg;
|
||||
struct nc_wclb_arg arg;
|
||||
const char **capabilities;
|
||||
uint32_t *sid = NULL, i, wd = 0;
|
||||
LY_ERR lyrc;
|
||||
|
@ -954,11 +886,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
/* <rpc> open */
|
||||
count = asprintf(&buf, "<rpc xmlns=\"%s\" message-id=\"%" PRIu64 "\"%s>",
|
||||
NC_NS_BASE, session->opts.client.msgid + 1, attrs ? attrs : "");
|
||||
if (count == -1) {
|
||||
ERRMEM;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup);
|
||||
nc_write_clb((void *)&arg, buf, count, 0);
|
||||
free(buf);
|
||||
|
||||
|
@ -969,7 +897,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
}
|
||||
|
||||
/* rpc data */
|
||||
if (lyd_print_clb(nc_write_xmlclb, (void *)&arg, op, LYD_XML, LYD_PRINT_SHRINK)) {
|
||||
if (lyd_print_clb(nc_write_xmlclb, (void *)&arg, op, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_KEEPEMPTYCONT)) {
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -991,27 +919,21 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
rpc_envp = va_arg(ap, struct lyd_node_opaq *);
|
||||
reply = va_arg(ap, struct nc_server_reply *);
|
||||
|
||||
if (!rpc_envp) {
|
||||
/* can be NULL if replying with a malformed-message error */
|
||||
nc_write_clb((void *)&arg, "<rpc-reply xmlns=\"" NC_NS_BASE "\">", 18 + strlen(NC_NS_BASE) + 2, 0);
|
||||
|
||||
assert(reply->type == NC_RPL_ERROR);
|
||||
if (lyd_print_clb(nc_write_xmlclb, (void *)&arg, ((struct nc_server_reply_error *)reply)->err, LYD_XML,
|
||||
LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS)) {
|
||||
/* build a rpc-reply opaque node that can be simply printed */
|
||||
if (rpc_envp) {
|
||||
if (lyd_new_opaq2(NULL, session->ctx, "rpc-reply", NULL, rpc_envp->name.prefix, rpc_envp->name.module_ns,
|
||||
&reply_envp)) {
|
||||
ERRINT;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
if (lyd_new_opaq2(NULL, session->ctx, "rpc-reply", NULL, NULL, NC_NS_BASE,
|
||||
&reply_envp)) {
|
||||
ERRINT;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
nc_write_clb((void *)&arg, "</rpc-reply>", 12, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* build a rpc-reply opaque node that can be simply printed */
|
||||
if (lyd_new_opaq2(NULL, session->ctx, "rpc-reply", NULL, rpc_envp->name.prefix, rpc_envp->name.module_ns,
|
||||
&reply_envp)) {
|
||||
ERRINT;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
switch (reply->type) {
|
||||
|
@ -1060,7 +982,9 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
}
|
||||
|
||||
/* temporary */
|
||||
((struct lyd_node_opaq *)reply_envp)->attr = rpc_envp->attr;
|
||||
if (rpc_envp) {
|
||||
((struct lyd_node_opaq *)reply_envp)->attr = rpc_envp->attr;
|
||||
}
|
||||
|
||||
/* print */
|
||||
lyrc = lyd_print_clb(nc_write_xmlclb, (void *)&arg, reply_envp, LYD_XML, LYD_PRINT_SHRINK | wd);
|
||||
|
@ -1117,11 +1041,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
sid = va_arg(ap, uint32_t *);
|
||||
|
||||
count = asprintf(&buf, "<hello xmlns=\"%s\"><capabilities>", NC_NS_BASE);
|
||||
if (count == -1) {
|
||||
ERRMEM;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup);
|
||||
nc_write_clb((void *)&arg, buf, count, 0);
|
||||
free(buf);
|
||||
for (i = 0; capabilities[i]; i++) {
|
||||
|
@ -1130,12 +1050,8 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
nc_write_clb((void *)&arg, "</capability>", 13, 0);
|
||||
}
|
||||
if (sid) {
|
||||
count = asprintf(&buf, "</capabilities><session-id>%u</session-id></hello>", *sid);
|
||||
if (count == -1) {
|
||||
ERRMEM;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
count = asprintf(&buf, "</capabilities><session-id>%" PRIu32 "</session-id></hello>", *sid);
|
||||
NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup);
|
||||
nc_write_clb((void *)&arg, buf, count, 0);
|
||||
free(buf);
|
||||
} else {
|
||||
|
@ -1179,7 +1095,7 @@ nc_realloc(void *ptr, size_t size)
|
|||
}
|
||||
|
||||
struct passwd *
|
||||
nc_getpwuid(uid_t uid, struct passwd *pwd_buf, char **buf, size_t *buf_size)
|
||||
nc_getpw(uid_t uid, const char *username, struct passwd *pwd_buf, char **buf, size_t *buf_size)
|
||||
{
|
||||
struct passwd *pwd = NULL;
|
||||
long sys_size;
|
||||
|
@ -1197,16 +1113,21 @@ nc_getpwuid(uid_t uid, struct passwd *pwd_buf, char **buf, size_t *buf_size)
|
|||
|
||||
/* allocate some buffer */
|
||||
*buf = nc_realloc(*buf, *buf_size);
|
||||
if (!*buf) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!*buf, NULL);
|
||||
|
||||
ret = getpwuid_r(uid, pwd_buf, *buf, *buf_size, &pwd);
|
||||
if (username) {
|
||||
ret = getpwnam_r(username, pwd_buf, *buf, *buf_size, &pwd);
|
||||
} else {
|
||||
ret = getpwuid_r(uid, pwd_buf, *buf, *buf_size, &pwd);
|
||||
}
|
||||
} while (ret && (ret == ERANGE));
|
||||
|
||||
if (ret) {
|
||||
ERR(NULL, "Retrieving UID \"%lu\" passwd entry failed (%s).", (unsigned long int)uid, strerror(ret));
|
||||
if (username) {
|
||||
ERR(NULL, "Retrieving username \"%s\" passwd entry failed (%s).", username, strerror(ret));
|
||||
} else {
|
||||
ERR(NULL, "Retrieving UID \"%lu\" passwd entry failed (%s).", (unsigned long)uid, strerror(ret));
|
||||
}
|
||||
}
|
||||
return pwd;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue