mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-24 13:40:10 +01:00
ovs: merge branch 'th/ovsdb'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1593
This commit is contained in:
commit
fba38266bc
12 changed files with 303 additions and 187 deletions
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "libnm-glib-aux/nm-jansson.h"
|
||||
#include "libnm-glib-aux/nm-str-buf.h"
|
||||
#include "libnm-glib-aux/nm-io-utils.h"
|
||||
#include "nm-core-utils.h"
|
||||
#include "libnm-core-intern/nm-core-internal.h"
|
||||
#include "devices/nm-device.h"
|
||||
|
|
@ -134,14 +135,18 @@ enum {
|
|||
static guint signals[LAST_SIGNAL] = {0};
|
||||
|
||||
typedef struct {
|
||||
NMPlatform *platform;
|
||||
GSocketConnection *conn;
|
||||
GCancellable *conn_cancellable;
|
||||
char buf[4096]; /* Input buffer */
|
||||
size_t bufp; /* Last decoded byte in the input buffer. */
|
||||
GString *input; /* JSON stream waiting for decoding. */
|
||||
GString *output; /* JSON stream to be sent. */
|
||||
guint64 call_id_counter;
|
||||
NMPlatform *platform;
|
||||
int conn_fd;
|
||||
GSource *conn_fd_in_source;
|
||||
GSource *conn_fd_out_source;
|
||||
GCancellable *conn_cancellable;
|
||||
|
||||
NMStrBuf input_buf;
|
||||
NMStrBuf output_buf;
|
||||
|
||||
GSource *input_timeout_source;
|
||||
|
||||
guint64 call_id_counter;
|
||||
|
||||
CList calls_lst_head;
|
||||
|
||||
|
|
@ -177,12 +182,13 @@ NM_DEFINE_SINGLETON_GETTER(NMOvsdb, nm_ovsdb_get, NM_TYPE_OVSDB);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void ovsdb_try_connect(NMOvsdb *self);
|
||||
static void ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing);
|
||||
static void ovsdb_read(NMOvsdb *self);
|
||||
static void ovsdb_write(NMOvsdb *self);
|
||||
static void ovsdb_next_command(NMOvsdb *self);
|
||||
static void cleanup_check_ready(NMOvsdb *self);
|
||||
static void ovsdb_try_connect(NMOvsdb *self);
|
||||
static void ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing);
|
||||
static void ovsdb_read(NMOvsdb *self);
|
||||
static void ovsdb_write_try(NMOvsdb *self);
|
||||
static gboolean ovsdb_write_cb(int fd, GIOCondition condition, gpointer user_data);
|
||||
static void ovsdb_next_command(NMOvsdb *self);
|
||||
static void cleanup_check_ready(NMOvsdb *self);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -1446,10 +1452,10 @@ ovsdb_next_command(NMOvsdb *self)
|
|||
{
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
OvsdbMethodCall *call;
|
||||
char *cmd;
|
||||
nm_auto_free char *cmd = NULL;
|
||||
nm_auto_decref_json json_t *msg = NULL;
|
||||
|
||||
if (!priv->conn)
|
||||
if (priv->conn_fd < 0)
|
||||
return;
|
||||
|
||||
if (c_list_is_empty(&priv->calls_lst_head))
|
||||
|
|
@ -1586,10 +1592,9 @@ ovsdb_next_command(NMOvsdb *self)
|
|||
|
||||
cmd = json_dumps(msg, 0);
|
||||
_LOGT_call(call, "send: call-id=%" G_GUINT64_FORMAT ", %s", call->call_id, cmd);
|
||||
g_string_append(priv->output, cmd);
|
||||
free(cmd);
|
||||
nm_str_buf_append(&priv->output_buf, cmd);
|
||||
|
||||
ovsdb_write(self);
|
||||
ovsdb_write_try(self);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2188,20 +2193,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
|
|||
static void
|
||||
ovsdb_got_echo(NMOvsdb *self, json_int_t id, json_t *data)
|
||||
{
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
nm_auto_decref_json json_t *msg = NULL;
|
||||
char *reply;
|
||||
gboolean output_was_empty;
|
||||
|
||||
output_was_empty = priv->output->len == 0;
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
nm_auto_decref_json json_t *msg = NULL;
|
||||
nm_auto_free char *reply = NULL;
|
||||
|
||||
msg = json_pack("{s:I, s:O}", "id", id, "result", data);
|
||||
reply = json_dumps(msg, 0);
|
||||
g_string_append(priv->output, reply);
|
||||
free(reply);
|
||||
|
||||
if (output_was_empty)
|
||||
ovsdb_write(self);
|
||||
_LOGT("send: echo: %s", reply);
|
||||
|
||||
nm_str_buf_append(&priv->output_buf, reply);
|
||||
|
||||
ovsdb_write_try(self);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2274,13 +2277,13 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg)
|
|||
|
||||
/* This is a response to a method call. */
|
||||
if (c_list_is_empty(&priv->calls_lst_head)) {
|
||||
_LOGE("there are no queued calls expecting response %" G_GUINT64_FORMAT, (guint64) id);
|
||||
_LOGW("there are no queued calls expecting response %" G_GUINT64_FORMAT, (guint64) id);
|
||||
ovsdb_disconnect(self, FALSE, FALSE);
|
||||
return;
|
||||
}
|
||||
call = c_list_first_entry(&priv->calls_lst_head, OvsdbMethodCall, calls_lst);
|
||||
if (call->call_id != id) {
|
||||
_LOGE("expected a response to call %" G_GUINT64_FORMAT ", not %" G_GUINT64_FORMAT,
|
||||
_LOGW("expected a response to call %" G_GUINT64_FORMAT ", not %" G_GUINT64_FORMAT,
|
||||
call->call_id,
|
||||
(guint64) id);
|
||||
ovsdb_disconnect(self, FALSE, FALSE);
|
||||
|
|
@ -2305,7 +2308,7 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg)
|
|||
|
||||
/* Don't progress further commands in case the callback hit an error
|
||||
* and disconnected us. */
|
||||
if (!priv->conn)
|
||||
if (priv->conn_fd < 0)
|
||||
return;
|
||||
|
||||
/* Now we're free to serialize and send the next command, if any. */
|
||||
|
|
@ -2320,138 +2323,197 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
gsize bufp;
|
||||
NMStrBuf *input;
|
||||
} JsonReadMsgData;
|
||||
|
||||
/* Lower level marshalling and demarshalling of the JSON-RPC traffic on the
|
||||
* ovsdb socket. */
|
||||
|
||||
static size_t
|
||||
_json_callback(void *buffer, size_t buflen, void *user_data)
|
||||
_json_read_msg_cb(void *buffer, size_t buflen, void *user_data)
|
||||
{
|
||||
NMOvsdb *self = NM_OVSDB(user_data);
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
JsonReadMsgData *data = user_data;
|
||||
|
||||
if (priv->bufp == priv->input->len) {
|
||||
nm_assert(buffer);
|
||||
nm_assert(buflen > 0);
|
||||
|
||||
if (data->bufp == data->input->len) {
|
||||
/* No more bytes buffered for decoding. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pass one more byte to the JSON decoder. */
|
||||
*(char *) buffer = priv->input->str[priv->bufp];
|
||||
priv->bufp++;
|
||||
|
||||
return (size_t) 1;
|
||||
*(char *) buffer = nm_str_buf_get_char(data->input, data->bufp);
|
||||
data->bufp++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ovsdb_read_cb:
|
||||
*
|
||||
* Read out the data available from the ovsdb socket and try to deserialize
|
||||
* the JSON. If we see a complete object, pass it upwards to ovsdb_got_msg().
|
||||
*/
|
||||
static void
|
||||
ovsdb_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
static json_t *
|
||||
_json_read_msg(NMOvsdb *self, NMStrBuf *input)
|
||||
{
|
||||
NMOvsdb *self = NM_OVSDB(user_data);
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
GInputStream *stream = G_INPUT_STREAM(source_object);
|
||||
GError *error = NULL;
|
||||
gssize size;
|
||||
json_t *msg;
|
||||
json_error_t json_error = {
|
||||
gs_free char *ss = NULL;
|
||||
JsonReadMsgData data = {
|
||||
.bufp = 0,
|
||||
.input = input,
|
||||
};
|
||||
json_error_t json_error = {
|
||||
0,
|
||||
};
|
||||
json_t *msg;
|
||||
|
||||
size = g_input_stream_read_finish(stream, res, &error);
|
||||
if (size == -1) {
|
||||
/* ovsdb-server was possibly restarted */
|
||||
_LOGW("short read from ovsdb: %s", error->message);
|
||||
priv->num_failures++;
|
||||
g_clear_error(&error);
|
||||
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
||||
return;
|
||||
}
|
||||
/* The callback always eats up only up to a single byte. This makes it
|
||||
* possible for us to identify complete JSON objects in spite of us not
|
||||
* knowing the length in advance. */
|
||||
msg = json_load_callback(_json_read_msg_cb, &data, JSON_DISABLE_EOF_CHECK, &json_error);
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
g_string_append_len(priv->input, priv->buf, size);
|
||||
do {
|
||||
priv->bufp = 0;
|
||||
/* The callback always eats up only up to a single byte. This makes
|
||||
* it possible for us to identify complete JSON objects in spite of
|
||||
* us not knowing the length in advance. */
|
||||
msg = json_load_callback(_json_callback, self, JSON_DISABLE_EOF_CHECK, &json_error);
|
||||
if (msg) {
|
||||
ovsdb_got_msg(self, msg);
|
||||
g_string_erase(priv->input, 0, priv->bufp);
|
||||
}
|
||||
json_decref(msg);
|
||||
} while (msg);
|
||||
nm_assert(data.bufp > 0);
|
||||
|
||||
if (!priv->conn)
|
||||
return;
|
||||
_LOGT("json: parse %zu bytes: \"%s\"",
|
||||
data.bufp,
|
||||
(ss = g_strndup(nm_str_buf_get_str_at_unsafe(input, 0), data.bufp)));
|
||||
|
||||
if (size)
|
||||
ovsdb_read(self);
|
||||
nm_str_buf_erase(input, 0, data.bufp, FALSE);
|
||||
return msg;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_ovsdb_read_input_timeout_cb(gpointer user_data)
|
||||
{
|
||||
NMOvsdb *self = user_data;
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
|
||||
_LOGW("invalid/incomplete data in receive buffer. Reset");
|
||||
priv->num_failures++;
|
||||
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ovsdb_read(NMOvsdb *self)
|
||||
{
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
|
||||
g_input_stream_read_async(g_io_stream_get_input_stream(G_IO_STREAM(priv->conn)),
|
||||
priv->buf,
|
||||
sizeof(priv->buf),
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
ovsdb_read_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
static void
|
||||
ovsdb_write_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
GOutputStream *stream = G_OUTPUT_STREAM(source_object);
|
||||
NMOvsdb *self = NM_OVSDB(user_data);
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
GError *error = NULL;
|
||||
gssize size;
|
||||
|
||||
size = g_output_stream_write_finish(stream, res, &error);
|
||||
if (size == -1) {
|
||||
again:
|
||||
size = nm_utils_fd_read(priv->conn_fd, &priv->input_buf);
|
||||
|
||||
if (size <= 0) {
|
||||
if (size == -EAGAIN) {
|
||||
if (priv->input_buf.len == 0)
|
||||
nm_clear_g_source_inst(&priv->input_timeout_source);
|
||||
else if (!priv->input_timeout_source) {
|
||||
/* We have data in the buffer but nothing further to read. Schedule a timer,
|
||||
* if we don't get the rest within timeout, it means that the buffer
|
||||
* content is broken (_json_read_msg() cannot extract any data) and
|
||||
* we disconnect. */
|
||||
priv->input_timeout_source =
|
||||
nm_g_timeout_add_seconds_source(5, _ovsdb_read_input_timeout_cb, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* ovsdb-server was possibly restarted */
|
||||
_LOGW("short write to ovsdb: %s", error->message);
|
||||
_LOGW("short read from ovsdb: %s", nm_strerror_native(-size));
|
||||
priv->num_failures++;
|
||||
g_clear_error(&error);
|
||||
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!priv->conn)
|
||||
return;
|
||||
nm_assert(priv->input_buf.len > 0);
|
||||
|
||||
g_string_erase(priv->output, 0, size);
|
||||
while (TRUE) {
|
||||
nm_auto_decref_json json_t *msg = NULL;
|
||||
|
||||
ovsdb_write(self);
|
||||
msg = _json_read_msg(self, &priv->input_buf);
|
||||
if (!msg)
|
||||
break;
|
||||
|
||||
nm_clear_g_source_inst(&priv->input_timeout_source);
|
||||
ovsdb_got_msg(self, msg);
|
||||
|
||||
if (priv->input_buf.len == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (priv->input_buf.len > 0) {
|
||||
if (priv->input_buf.len > 50 * 1024 * 1024) {
|
||||
_LOGW("received too much data from ovsdb that is not valid JSON");
|
||||
priv->num_failures++;
|
||||
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
||||
return;
|
||||
}
|
||||
/* We have an incomplete message in the message buffer. Don't wait for another round
|
||||
* of "poll", instead try to read it again. */
|
||||
goto again;
|
||||
}
|
||||
|
||||
nm_clear_g_source_inst(&priv->input_timeout_source);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ovsdb_read_cb(int fd, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
ovsdb_read(user_data);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ovsdb_write(NMOvsdb *self)
|
||||
{
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
GOutputStream *stream;
|
||||
gssize n;
|
||||
|
||||
if (!priv->output->len)
|
||||
again:
|
||||
if (priv->output_buf.len == 0) {
|
||||
nm_clear_g_source_inst(&priv->conn_fd_out_source);
|
||||
return;
|
||||
}
|
||||
|
||||
stream = g_io_stream_get_output_stream(G_IO_STREAM(priv->conn));
|
||||
if (g_output_stream_has_pending(stream))
|
||||
n = write(priv->conn_fd,
|
||||
nm_str_buf_get_str_at_unsafe(&priv->output_buf, 0),
|
||||
priv->output_buf.len);
|
||||
|
||||
if (n < 0)
|
||||
n = -NM_ERRNO_NATIVE(errno);
|
||||
|
||||
if (n == -EAGAIN) {
|
||||
if (!priv->conn_fd_out_source) {
|
||||
priv->conn_fd_out_source =
|
||||
nm_g_unix_fd_add_source(priv->conn_fd, G_IO_OUT, ovsdb_write_cb, self);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
g_output_stream_write_async(stream,
|
||||
priv->output->str,
|
||||
priv->output->len,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
ovsdb_write_cb,
|
||||
self);
|
||||
if (n <= 0) {
|
||||
/* ovsdb-server was possibly restarted */
|
||||
_LOGW("short write to ovsdb: %s", nm_strerror_native(-n));
|
||||
priv->num_failures++;
|
||||
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
nm_str_buf_erase(&priv->output_buf, 0, n, FALSE);
|
||||
goto again;
|
||||
}
|
||||
|
||||
static void
|
||||
ovsdb_write_try(NMOvsdb *self)
|
||||
{
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
|
||||
if (priv->conn_fd >= 0 && !priv->conn_fd_out_source)
|
||||
ovsdb_write(self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ovsdb_write_cb(int fd, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
ovsdb_write(user_data);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -2474,7 +2536,7 @@ ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing)
|
|||
|
||||
nm_assert(!retry || !is_disposing);
|
||||
|
||||
if (!priv->conn && !priv->conn_cancellable)
|
||||
if (priv->conn_fd < 0 && !priv->conn_cancellable)
|
||||
return;
|
||||
|
||||
_LOGD("disconnecting from ovsdb, retry %d", retry);
|
||||
|
|
@ -2498,10 +2560,12 @@ ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing)
|
|||
_call_complete(call, NULL, error);
|
||||
}
|
||||
|
||||
priv->bufp = 0;
|
||||
g_string_truncate(priv->input, 0);
|
||||
g_string_truncate(priv->output, 0);
|
||||
g_clear_object(&priv->conn);
|
||||
nm_str_buf_reset(&priv->input_buf);
|
||||
nm_str_buf_reset(&priv->output_buf);
|
||||
nm_clear_fd(&priv->conn_fd);
|
||||
nm_clear_g_source_inst(&priv->conn_fd_in_source);
|
||||
nm_clear_g_source_inst(&priv->conn_fd_out_source);
|
||||
nm_clear_g_source_inst(&priv->input_timeout_source);
|
||||
nm_clear_g_free(&priv->db_uuid);
|
||||
nm_clear_g_cancellable(&priv->conn_cancellable);
|
||||
|
||||
|
|
@ -2702,15 +2766,12 @@ _ovsdb_connect_complete_with_fd(NMOvsdb *self, int fd_take)
|
|||
gs_unref_object GSocket *socket = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
socket = g_socket_new_from_fd(nm_steal_fd(&fd_take), &error);
|
||||
if (!socket) {
|
||||
_LOGT("connect: failure to open socket for new FD: %s", error->message);
|
||||
ovsdb_disconnect(self, FALSE, FALSE);
|
||||
return;
|
||||
}
|
||||
nm_clear_g_cancellable(&priv->conn_cancellable);
|
||||
|
||||
priv->conn = g_socket_connection_factory_create_connection(socket);
|
||||
g_clear_object(&priv->conn_cancellable);
|
||||
nm_io_fcntl_setfl_update_nonblock(fd_take);
|
||||
|
||||
priv->conn_fd = nm_steal_fd(&fd_take);
|
||||
priv->conn_fd_in_source = nm_g_unix_fd_add_source(priv->conn_fd, G_IO_IN, ovsdb_read_cb, self);
|
||||
|
||||
ovsdb_read(self);
|
||||
ovsdb_next_command(self);
|
||||
|
|
@ -2784,7 +2845,7 @@ ovsdb_try_connect(NMOvsdb *self)
|
|||
{
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
|
||||
if (priv->conn || priv->conn_cancellable)
|
||||
if (priv->conn_fd >= 0 || priv->conn_cancellable)
|
||||
return;
|
||||
|
||||
_LOGT("connect: start connecting socket %s on idle", NM_OVSDB_SOCKET);
|
||||
|
|
@ -2964,11 +3025,15 @@ nm_ovsdb_init(NMOvsdb *self)
|
|||
{
|
||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||
|
||||
priv->conn_fd = -1;
|
||||
|
||||
priv->input_buf = NM_STR_BUF_INIT(0, FALSE);
|
||||
priv->output_buf = NM_STR_BUF_INIT(0, FALSE);
|
||||
|
||||
c_list_init(&priv->calls_lst_head);
|
||||
|
||||
priv->platform = g_object_ref(NM_PLATFORM_GET);
|
||||
priv->input = g_string_new(NULL);
|
||||
priv->output = g_string_new(NULL);
|
||||
|
||||
priv->bridges =
|
||||
g_hash_table_new_full(nm_pstr_hash, nm_pstr_equal, (GDestroyNotify) _free_bridge, NULL);
|
||||
priv->ports =
|
||||
|
|
@ -2989,14 +3054,8 @@ dispose(GObject *object)
|
|||
|
||||
nm_assert(c_list_is_empty(&priv->calls_lst_head));
|
||||
|
||||
if (priv->input) {
|
||||
g_string_free(priv->input, TRUE);
|
||||
priv->input = NULL;
|
||||
}
|
||||
if (priv->output) {
|
||||
g_string_free(priv->output, TRUE);
|
||||
priv->output = NULL;
|
||||
}
|
||||
nm_str_buf_destroy(&priv->input_buf);
|
||||
nm_str_buf_destroy(&priv->output_buf);
|
||||
|
||||
g_clear_object(&priv->platform);
|
||||
nm_clear_pointer(&priv->bridges, g_hash_table_destroy);
|
||||
|
|
|
|||
|
|
@ -647,7 +647,7 @@ run_netconfig(NMDnsManager *self, GError **error, int *stdin_fd)
|
|||
if (!g_spawn_async_with_pipes(NULL,
|
||||
argv,
|
||||
NULL,
|
||||
G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
NULL,
|
||||
NULL,
|
||||
&pid,
|
||||
|
|
|
|||
|
|
@ -5090,7 +5090,6 @@ nm_utils_spawn_helper(const char *const *args,
|
|||
gs_free_error GError *error = NULL;
|
||||
gs_free char *commands = NULL;
|
||||
HelperInfo *info;
|
||||
int fd_flags;
|
||||
const char *const *arg;
|
||||
GMainContext *context;
|
||||
gsize n;
|
||||
|
|
@ -5099,16 +5098,13 @@ nm_utils_spawn_helper(const char *const *args,
|
|||
|
||||
info = g_new(HelperInfo, 1);
|
||||
*info = (HelperInfo){
|
||||
.task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data),
|
||||
.child_stdin = -1,
|
||||
.child_stdout = -1,
|
||||
.pid = -1,
|
||||
.task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data),
|
||||
};
|
||||
|
||||
if (!g_spawn_async_with_pipes("/",
|
||||
(char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"),
|
||||
(char **) NM_MAKE_STRV(),
|
||||
G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
NULL,
|
||||
NULL,
|
||||
&info->pid,
|
||||
|
|
@ -5162,13 +5158,9 @@ nm_utils_spawn_helper(const char *const *args,
|
|||
nm_g_timeout_source_new_seconds(20, G_PRIORITY_DEFAULT, helper_timeout, info, NULL);
|
||||
g_source_attach(info->timeout_source, context);
|
||||
|
||||
/* Set file descriptors as non-blocking */
|
||||
fd_flags = fcntl(info->child_stdin, F_GETFD, 0);
|
||||
fcntl(info->child_stdin, F_SETFL, fd_flags | O_NONBLOCK);
|
||||
fd_flags = fcntl(info->child_stdout, F_GETFD, 0);
|
||||
fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
|
||||
fd_flags = fcntl(info->child_stderr, F_GETFD, 0);
|
||||
fcntl(info->child_stderr, F_SETFL, fd_flags | O_NONBLOCK);
|
||||
nm_io_fcntl_setfl_update_nonblock(info->child_stdin);
|
||||
nm_io_fcntl_setfl_update_nonblock(info->child_stdout);
|
||||
nm_io_fcntl_setfl_update_nonblock(info->child_stderr);
|
||||
|
||||
/* Watch process stdin */
|
||||
for (n = 1, arg = args; *arg; arg++)
|
||||
|
|
|
|||
|
|
@ -3021,7 +3021,7 @@ _rfkill_update_system(NMManager *self, NMRfkillType rtype, gboolean enabled)
|
|||
|
||||
nm_assert(NM_IN_SET(rtype, NM_RFKILL_TYPE_WLAN, NM_RFKILL_TYPE_WWAN));
|
||||
|
||||
fd = open("/dev/rfkill", O_RDWR | O_CLOEXEC);
|
||||
fd = open("/dev/rfkill", O_RDWR | O_NONBLOCK | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
if (errno == EACCES)
|
||||
_LOGW(LOGD_RFKILL,
|
||||
|
|
@ -3030,14 +3030,6 @@ _rfkill_update_system(NMManager *self, NMRfkillType rtype, gboolean enabled)
|
|||
return;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
_LOGW(LOGD_RFKILL,
|
||||
"rfkill: (%s): failed to set killswitch device for "
|
||||
"non-blocking operation",
|
||||
nm_rfkill_type_to_string(rtype));
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.op = KERN_RFKILL_OP_CHANGE_ALL;
|
||||
switch (rtype) {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,8 @@ nmtstc_service_init(void)
|
|||
g_spawn_async_with_pipes(NULL,
|
||||
(char **) args,
|
||||
NULL,
|
||||
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_SEARCH_PATH
|
||||
| G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
NULL,
|
||||
NULL,
|
||||
&info->pid,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,86 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
nm_io_fcntl_getfl(int fd)
|
||||
{
|
||||
int f;
|
||||
|
||||
nm_assert(fd >= 0);
|
||||
|
||||
f = fcntl(fd, F_GETFL, 0);
|
||||
|
||||
/* The caller really must provide a valid FD. For a valid FD, there is not
|
||||
* reason why this call could fail (or how we could handle the failure).
|
||||
*
|
||||
* Unlike plain fcntl(), nm_io_fcntl_getfl() cannot fail. */
|
||||
nm_assert(f != -1);
|
||||
|
||||
/* We not only assert that the return value is "!= -1", but that it's not
|
||||
* negative. Negative flags would be very odd, and not something we would
|
||||
* expect for a successful call. */
|
||||
nm_assert(f >= 0);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
int
|
||||
nm_io_fcntl_setfl(int fd, int flags)
|
||||
{
|
||||
int f;
|
||||
int errsv;
|
||||
|
||||
nm_assert(fd >= 0);
|
||||
nm_assert(flags >= 0);
|
||||
|
||||
f = fcntl(fd, F_SETFL, flags);
|
||||
if (f != 0) {
|
||||
errsv = errno;
|
||||
|
||||
nm_assert(errsv != EBADF);
|
||||
|
||||
return -NM_ERRNO_NATIVE(errsv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nm_io_fcntl_setfl_update(int fd, int flags_mask, int flags_value)
|
||||
{
|
||||
int flags_current;
|
||||
|
||||
nm_assert(fd >= 0);
|
||||
nm_assert(flags_mask > 0);
|
||||
nm_assert(flags_value >= 0);
|
||||
nm_assert(((~flags_mask) & flags_value) == 0);
|
||||
|
||||
flags_current = nm_io_fcntl_getfl(fd);
|
||||
return nm_io_fcntl_setfl(fd, (flags_current & ~flags_mask) | (flags_mask & flags_value));
|
||||
}
|
||||
|
||||
void
|
||||
nm_io_fcntl_setfl_update_nonblock(int fd)
|
||||
{
|
||||
int r;
|
||||
|
||||
nm_assert(fd >= 0);
|
||||
|
||||
r = nm_io_fcntl_setfl_update(fd, O_NONBLOCK, O_NONBLOCK);
|
||||
|
||||
/* nm_io_fcntl_setfl_update() already asserts that it cannot fail with
|
||||
* EBADF.
|
||||
*
|
||||
* In nm_io_fcntl_setfl_update_nonblock() only sts O_NONBLOCK, where we
|
||||
* don't expect any other error. Kernel should never reject setting this
|
||||
* flags, and if it did, we have to find out how to handle that. Currently
|
||||
* we don't handle it and assert against failure. */
|
||||
|
||||
nm_assert(r == 0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
_nm_printf(4, 5) static int _get_contents_error(GError **error,
|
||||
int errsv,
|
||||
int *out_errsv,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,16 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int nm_io_fcntl_getfl(int fd);
|
||||
|
||||
int nm_io_fcntl_setfl(int fd, int flags);
|
||||
|
||||
int nm_io_fcntl_setfl_update(int fd, int flags_mask, int flags_value);
|
||||
|
||||
void nm_io_fcntl_setfl_update_nonblock(int fd);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* NMUtilsFileGetContentsFlags:
|
||||
* @NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE: no flag
|
||||
|
|
|
|||
|
|
@ -1036,17 +1036,6 @@ nlmsg_get_dst(struct nl_msg *msg)
|
|||
return &msg->nm_dst;
|
||||
}
|
||||
|
||||
int
|
||||
nl_socket_set_nonblocking(const struct nl_sock *sk)
|
||||
{
|
||||
nm_assert_sk(sk);
|
||||
|
||||
if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
|
||||
return -nm_errno_from_native(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -605,8 +605,6 @@ int nl_socket_set_passcred(struct nl_sock *sk, int state);
|
|||
|
||||
int nl_socket_set_pktinfo(struct nl_sock *sk, int state);
|
||||
|
||||
int nl_socket_set_nonblocking(const struct nl_sock *sk);
|
||||
|
||||
uint32_t nl_socket_get_local_port(const struct nl_sock *sk);
|
||||
|
||||
int nl_socket_add_memberships(struct nl_sock *sk, int group, ...);
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ test_use_symbols(void)
|
|||
(void (*)(void)) nl_socket_set_passcred,
|
||||
(void (*)(void)) nl_socket_set_msg_buf_size,
|
||||
(void (*)(void)) nlmsg_get_dst,
|
||||
(void (*)(void)) nl_socket_set_nonblocking,
|
||||
(void (*)(void)) nl_socket_set_buffer_size,
|
||||
(void (*)(void)) nl_socket_add_memberships,
|
||||
(void (*)(void)) nl_wait_for_ack,
|
||||
|
|
|
|||
|
|
@ -499,7 +499,6 @@ out:
|
|||
static void
|
||||
begin_authentication(AuthRequest *request)
|
||||
{
|
||||
int fd_flags;
|
||||
const char *helper_argv[] = {
|
||||
POLKIT_AGENT_HELPER_1_PATH,
|
||||
request->username,
|
||||
|
|
@ -514,7 +513,7 @@ begin_authentication(AuthRequest *request)
|
|||
if (!g_spawn_async_with_pipes(NULL,
|
||||
(char **) helper_argv,
|
||||
NULL,
|
||||
G_SPAWN_STDERR_TO_DEV_NULL,
|
||||
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_STDERR_TO_DEV_NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
@ -534,11 +533,8 @@ begin_authentication(AuthRequest *request)
|
|||
return;
|
||||
}
|
||||
|
||||
fd_flags = fcntl(request->child_stdin, F_GETFD, 0);
|
||||
fcntl(request->child_stdin, F_SETFL, fd_flags | O_NONBLOCK);
|
||||
|
||||
fd_flags = fcntl(request->child_stdout, F_GETFD, 0);
|
||||
fcntl(request->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
|
||||
nm_io_fcntl_setfl_update_nonblock(request->child_stdin);
|
||||
nm_io_fcntl_setfl_update_nonblock(request->child_stdout);
|
||||
|
||||
request->child_stdout_watch_source = nm_g_unix_fd_source_new(request->child_stdout,
|
||||
G_IO_IN | G_IO_ERR | G_IO_HUP,
|
||||
|
|
|
|||
|
|
@ -787,7 +787,7 @@ try_spawn_vpn_auth_helper(RequestData *request, GPtrArray *secrets)
|
|||
if (!g_spawn_async_with_pipes(NULL,
|
||||
(char **) auth_dialog_argv->pdata,
|
||||
NULL,
|
||||
G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
NULL,
|
||||
NULL,
|
||||
&auth_dialog_pid,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue