mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-08 17:08:08 +02: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-jansson.h"
|
||||||
#include "libnm-glib-aux/nm-str-buf.h"
|
#include "libnm-glib-aux/nm-str-buf.h"
|
||||||
|
#include "libnm-glib-aux/nm-io-utils.h"
|
||||||
#include "nm-core-utils.h"
|
#include "nm-core-utils.h"
|
||||||
#include "libnm-core-intern/nm-core-internal.h"
|
#include "libnm-core-intern/nm-core-internal.h"
|
||||||
#include "devices/nm-device.h"
|
#include "devices/nm-device.h"
|
||||||
|
|
@ -134,14 +135,18 @@ enum {
|
||||||
static guint signals[LAST_SIGNAL] = {0};
|
static guint signals[LAST_SIGNAL] = {0};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NMPlatform *platform;
|
NMPlatform *platform;
|
||||||
GSocketConnection *conn;
|
int conn_fd;
|
||||||
GCancellable *conn_cancellable;
|
GSource *conn_fd_in_source;
|
||||||
char buf[4096]; /* Input buffer */
|
GSource *conn_fd_out_source;
|
||||||
size_t bufp; /* Last decoded byte in the input buffer. */
|
GCancellable *conn_cancellable;
|
||||||
GString *input; /* JSON stream waiting for decoding. */
|
|
||||||
GString *output; /* JSON stream to be sent. */
|
NMStrBuf input_buf;
|
||||||
guint64 call_id_counter;
|
NMStrBuf output_buf;
|
||||||
|
|
||||||
|
GSource *input_timeout_source;
|
||||||
|
|
||||||
|
guint64 call_id_counter;
|
||||||
|
|
||||||
CList calls_lst_head;
|
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_try_connect(NMOvsdb *self);
|
||||||
static void ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing);
|
static void ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing);
|
||||||
static void ovsdb_read(NMOvsdb *self);
|
static void ovsdb_read(NMOvsdb *self);
|
||||||
static void ovsdb_write(NMOvsdb *self);
|
static void ovsdb_write_try(NMOvsdb *self);
|
||||||
static void ovsdb_next_command(NMOvsdb *self);
|
static gboolean ovsdb_write_cb(int fd, GIOCondition condition, gpointer user_data);
|
||||||
static void cleanup_check_ready(NMOvsdb *self);
|
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);
|
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||||
OvsdbMethodCall *call;
|
OvsdbMethodCall *call;
|
||||||
char *cmd;
|
nm_auto_free char *cmd = NULL;
|
||||||
nm_auto_decref_json json_t *msg = NULL;
|
nm_auto_decref_json json_t *msg = NULL;
|
||||||
|
|
||||||
if (!priv->conn)
|
if (priv->conn_fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (c_list_is_empty(&priv->calls_lst_head))
|
if (c_list_is_empty(&priv->calls_lst_head))
|
||||||
|
|
@ -1586,10 +1592,9 @@ ovsdb_next_command(NMOvsdb *self)
|
||||||
|
|
||||||
cmd = json_dumps(msg, 0);
|
cmd = json_dumps(msg, 0);
|
||||||
_LOGT_call(call, "send: call-id=%" G_GUINT64_FORMAT ", %s", call->call_id, cmd);
|
_LOGT_call(call, "send: call-id=%" G_GUINT64_FORMAT ", %s", call->call_id, cmd);
|
||||||
g_string_append(priv->output, cmd);
|
nm_str_buf_append(&priv->output_buf, cmd);
|
||||||
free(cmd);
|
|
||||||
|
|
||||||
ovsdb_write(self);
|
ovsdb_write_try(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2188,20 +2193,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg)
|
||||||
static void
|
static void
|
||||||
ovsdb_got_echo(NMOvsdb *self, json_int_t id, json_t *data)
|
ovsdb_got_echo(NMOvsdb *self, json_int_t id, json_t *data)
|
||||||
{
|
{
|
||||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||||
nm_auto_decref_json json_t *msg = NULL;
|
nm_auto_decref_json json_t *msg = NULL;
|
||||||
char *reply;
|
nm_auto_free char *reply = NULL;
|
||||||
gboolean output_was_empty;
|
|
||||||
|
|
||||||
output_was_empty = priv->output->len == 0;
|
|
||||||
|
|
||||||
msg = json_pack("{s:I, s:O}", "id", id, "result", data);
|
msg = json_pack("{s:I, s:O}", "id", id, "result", data);
|
||||||
reply = json_dumps(msg, 0);
|
reply = json_dumps(msg, 0);
|
||||||
g_string_append(priv->output, reply);
|
|
||||||
free(reply);
|
|
||||||
|
|
||||||
if (output_was_empty)
|
_LOGT("send: echo: %s", reply);
|
||||||
ovsdb_write(self);
|
|
||||||
|
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. */
|
/* This is a response to a method call. */
|
||||||
if (c_list_is_empty(&priv->calls_lst_head)) {
|
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);
|
ovsdb_disconnect(self, FALSE, FALSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
call = c_list_first_entry(&priv->calls_lst_head, OvsdbMethodCall, calls_lst);
|
call = c_list_first_entry(&priv->calls_lst_head, OvsdbMethodCall, calls_lst);
|
||||||
if (call->call_id != id) {
|
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,
|
call->call_id,
|
||||||
(guint64) id);
|
(guint64) id);
|
||||||
ovsdb_disconnect(self, FALSE, FALSE);
|
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
|
/* Don't progress further commands in case the callback hit an error
|
||||||
* and disconnected us. */
|
* and disconnected us. */
|
||||||
if (!priv->conn)
|
if (priv->conn_fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Now we're free to serialize and send the next command, if any. */
|
/* 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
|
/* Lower level marshalling and demarshalling of the JSON-RPC traffic on the
|
||||||
* ovsdb socket. */
|
* ovsdb socket. */
|
||||||
|
|
||||||
static size_t
|
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);
|
JsonReadMsgData *data = user_data;
|
||||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
|
||||||
|
|
||||||
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. */
|
/* No more bytes buffered for decoding. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pass one more byte to the JSON decoder. */
|
/* Pass one more byte to the JSON decoder. */
|
||||||
*(char *) buffer = priv->input->str[priv->bufp];
|
*(char *) buffer = nm_str_buf_get_char(data->input, data->bufp);
|
||||||
priv->bufp++;
|
data->bufp++;
|
||||||
|
return 1;
|
||||||
return (size_t) 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static json_t *
|
||||||
* ovsdb_read_cb:
|
_json_read_msg(NMOvsdb *self, NMStrBuf *input)
|
||||||
*
|
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
NMOvsdb *self = NM_OVSDB(user_data);
|
gs_free char *ss = NULL;
|
||||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
JsonReadMsgData data = {
|
||||||
GInputStream *stream = G_INPUT_STREAM(source_object);
|
.bufp = 0,
|
||||||
GError *error = NULL;
|
.input = input,
|
||||||
gssize size;
|
};
|
||||||
json_t *msg;
|
json_error_t json_error = {
|
||||||
json_error_t json_error = {
|
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
json_t *msg;
|
||||||
|
|
||||||
size = g_input_stream_read_finish(stream, res, &error);
|
/* The callback always eats up only up to a single byte. This makes it
|
||||||
if (size == -1) {
|
* possible for us to identify complete JSON objects in spite of us not
|
||||||
/* ovsdb-server was possibly restarted */
|
* knowing the length in advance. */
|
||||||
_LOGW("short read from ovsdb: %s", error->message);
|
msg = json_load_callback(_json_read_msg_cb, &data, JSON_DISABLE_EOF_CHECK, &json_error);
|
||||||
priv->num_failures++;
|
if (!msg)
|
||||||
g_clear_error(&error);
|
return NULL;
|
||||||
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_string_append_len(priv->input, priv->buf, size);
|
nm_assert(data.bufp > 0);
|
||||||
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);
|
|
||||||
|
|
||||||
if (!priv->conn)
|
_LOGT("json: parse %zu bytes: \"%s\"",
|
||||||
return;
|
data.bufp,
|
||||||
|
(ss = g_strndup(nm_str_buf_get_str_at_unsafe(input, 0), data.bufp)));
|
||||||
|
|
||||||
if (size)
|
nm_str_buf_erase(input, 0, data.bufp, FALSE);
|
||||||
ovsdb_read(self);
|
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
|
static void
|
||||||
ovsdb_read(NMOvsdb *self)
|
ovsdb_read(NMOvsdb *self)
|
||||||
{
|
{
|
||||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(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;
|
gssize size;
|
||||||
|
|
||||||
size = g_output_stream_write_finish(stream, res, &error);
|
again:
|
||||||
if (size == -1) {
|
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 */
|
/* 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++;
|
priv->num_failures++;
|
||||||
g_clear_error(&error);
|
|
||||||
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!priv->conn)
|
nm_assert(priv->input_buf.len > 0);
|
||||||
return;
|
|
||||||
|
|
||||||
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
|
static void
|
||||||
ovsdb_write(NMOvsdb *self)
|
ovsdb_write(NMOvsdb *self)
|
||||||
{
|
{
|
||||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
stream = g_io_stream_get_output_stream(G_IO_STREAM(priv->conn));
|
n = write(priv->conn_fd,
|
||||||
if (g_output_stream_has_pending(stream))
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
g_output_stream_write_async(stream,
|
if (n <= 0) {
|
||||||
priv->output->str,
|
/* ovsdb-server was possibly restarted */
|
||||||
priv->output->len,
|
_LOGW("short write to ovsdb: %s", nm_strerror_native(-n));
|
||||||
G_PRIORITY_DEFAULT,
|
priv->num_failures++;
|
||||||
NULL,
|
ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
|
||||||
ovsdb_write_cb,
|
return;
|
||||||
self);
|
}
|
||||||
|
|
||||||
|
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);
|
nm_assert(!retry || !is_disposing);
|
||||||
|
|
||||||
if (!priv->conn && !priv->conn_cancellable)
|
if (priv->conn_fd < 0 && !priv->conn_cancellable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_LOGD("disconnecting from ovsdb, retry %d", retry);
|
_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);
|
_call_complete(call, NULL, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->bufp = 0;
|
nm_str_buf_reset(&priv->input_buf);
|
||||||
g_string_truncate(priv->input, 0);
|
nm_str_buf_reset(&priv->output_buf);
|
||||||
g_string_truncate(priv->output, 0);
|
nm_clear_fd(&priv->conn_fd);
|
||||||
g_clear_object(&priv->conn);
|
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_free(&priv->db_uuid);
|
||||||
nm_clear_g_cancellable(&priv->conn_cancellable);
|
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_unref_object GSocket *socket = NULL;
|
||||||
gs_free_error GError *error = NULL;
|
gs_free_error GError *error = NULL;
|
||||||
|
|
||||||
socket = g_socket_new_from_fd(nm_steal_fd(&fd_take), &error);
|
nm_clear_g_cancellable(&priv->conn_cancellable);
|
||||||
if (!socket) {
|
|
||||||
_LOGT("connect: failure to open socket for new FD: %s", error->message);
|
|
||||||
ovsdb_disconnect(self, FALSE, FALSE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->conn = g_socket_connection_factory_create_connection(socket);
|
nm_io_fcntl_setfl_update_nonblock(fd_take);
|
||||||
g_clear_object(&priv->conn_cancellable);
|
|
||||||
|
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_read(self);
|
||||||
ovsdb_next_command(self);
|
ovsdb_next_command(self);
|
||||||
|
|
@ -2784,7 +2845,7 @@ ovsdb_try_connect(NMOvsdb *self)
|
||||||
{
|
{
|
||||||
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
|
||||||
|
|
||||||
if (priv->conn || priv->conn_cancellable)
|
if (priv->conn_fd >= 0 || priv->conn_cancellable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_LOGT("connect: start connecting socket %s on idle", NM_OVSDB_SOCKET);
|
_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);
|
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);
|
c_list_init(&priv->calls_lst_head);
|
||||||
|
|
||||||
priv->platform = g_object_ref(NM_PLATFORM_GET);
|
priv->platform = g_object_ref(NM_PLATFORM_GET);
|
||||||
priv->input = g_string_new(NULL);
|
|
||||||
priv->output = g_string_new(NULL);
|
|
||||||
priv->bridges =
|
priv->bridges =
|
||||||
g_hash_table_new_full(nm_pstr_hash, nm_pstr_equal, (GDestroyNotify) _free_bridge, NULL);
|
g_hash_table_new_full(nm_pstr_hash, nm_pstr_equal, (GDestroyNotify) _free_bridge, NULL);
|
||||||
priv->ports =
|
priv->ports =
|
||||||
|
|
@ -2989,14 +3054,8 @@ dispose(GObject *object)
|
||||||
|
|
||||||
nm_assert(c_list_is_empty(&priv->calls_lst_head));
|
nm_assert(c_list_is_empty(&priv->calls_lst_head));
|
||||||
|
|
||||||
if (priv->input) {
|
nm_str_buf_destroy(&priv->input_buf);
|
||||||
g_string_free(priv->input, TRUE);
|
nm_str_buf_destroy(&priv->output_buf);
|
||||||
priv->input = NULL;
|
|
||||||
}
|
|
||||||
if (priv->output) {
|
|
||||||
g_string_free(priv->output, TRUE);
|
|
||||||
priv->output = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_clear_object(&priv->platform);
|
g_clear_object(&priv->platform);
|
||||||
nm_clear_pointer(&priv->bridges, g_hash_table_destroy);
|
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,
|
if (!g_spawn_async_with_pipes(NULL,
|
||||||
argv,
|
argv,
|
||||||
NULL,
|
NULL,
|
||||||
G_SPAWN_DO_NOT_REAP_CHILD,
|
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
&pid,
|
&pid,
|
||||||
|
|
|
||||||
|
|
@ -5090,7 +5090,6 @@ nm_utils_spawn_helper(const char *const *args,
|
||||||
gs_free_error GError *error = NULL;
|
gs_free_error GError *error = NULL;
|
||||||
gs_free char *commands = NULL;
|
gs_free char *commands = NULL;
|
||||||
HelperInfo *info;
|
HelperInfo *info;
|
||||||
int fd_flags;
|
|
||||||
const char *const *arg;
|
const char *const *arg;
|
||||||
GMainContext *context;
|
GMainContext *context;
|
||||||
gsize n;
|
gsize n;
|
||||||
|
|
@ -5099,16 +5098,13 @@ nm_utils_spawn_helper(const char *const *args,
|
||||||
|
|
||||||
info = g_new(HelperInfo, 1);
|
info = g_new(HelperInfo, 1);
|
||||||
*info = (HelperInfo){
|
*info = (HelperInfo){
|
||||||
.task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data),
|
.task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data),
|
||||||
.child_stdin = -1,
|
|
||||||
.child_stdout = -1,
|
|
||||||
.pid = -1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!g_spawn_async_with_pipes("/",
|
if (!g_spawn_async_with_pipes("/",
|
||||||
(char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"),
|
(char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"),
|
||||||
(char **) NM_MAKE_STRV(),
|
(char **) NM_MAKE_STRV(),
|
||||||
G_SPAWN_DO_NOT_REAP_CHILD,
|
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
&info->pid,
|
&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);
|
nm_g_timeout_source_new_seconds(20, G_PRIORITY_DEFAULT, helper_timeout, info, NULL);
|
||||||
g_source_attach(info->timeout_source, context);
|
g_source_attach(info->timeout_source, context);
|
||||||
|
|
||||||
/* Set file descriptors as non-blocking */
|
nm_io_fcntl_setfl_update_nonblock(info->child_stdin);
|
||||||
fd_flags = fcntl(info->child_stdin, F_GETFD, 0);
|
nm_io_fcntl_setfl_update_nonblock(info->child_stdout);
|
||||||
fcntl(info->child_stdin, F_SETFL, fd_flags | O_NONBLOCK);
|
nm_io_fcntl_setfl_update_nonblock(info->child_stderr);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Watch process stdin */
|
/* Watch process stdin */
|
||||||
for (n = 1, arg = args; *arg; arg++)
|
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));
|
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 (fd < 0) {
|
||||||
if (errno == EACCES)
|
if (errno == EACCES)
|
||||||
_LOGW(LOGD_RFKILL,
|
_LOGW(LOGD_RFKILL,
|
||||||
|
|
@ -3030,14 +3030,6 @@ _rfkill_update_system(NMManager *self, NMRfkillType rtype, gboolean enabled)
|
||||||
return;
|
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));
|
memset(&event, 0, sizeof(event));
|
||||||
event.op = KERN_RFKILL_OP_CHANGE_ALL;
|
event.op = KERN_RFKILL_OP_CHANGE_ALL;
|
||||||
switch (rtype) {
|
switch (rtype) {
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,8 @@ nmtstc_service_init(void)
|
||||||
g_spawn_async_with_pipes(NULL,
|
g_spawn_async_with_pipes(NULL,
|
||||||
(char **) args,
|
(char **) args,
|
||||||
NULL,
|
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,
|
||||||
NULL,
|
NULL,
|
||||||
&info->pid,
|
&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,
|
_nm_printf(4, 5) static int _get_contents_error(GError **error,
|
||||||
int errsv,
|
int errsv,
|
||||||
int *out_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:
|
* NMUtilsFileGetContentsFlags:
|
||||||
* @NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE: no flag
|
* @NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE: no flag
|
||||||
|
|
|
||||||
|
|
@ -1036,17 +1036,6 @@ nlmsg_get_dst(struct nl_msg *msg)
|
||||||
return &msg->nm_dst;
|
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
|
int
|
||||||
nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
|
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_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);
|
uint32_t nl_socket_get_local_port(const struct nl_sock *sk);
|
||||||
|
|
||||||
int nl_socket_add_memberships(struct nl_sock *sk, int group, ...);
|
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_passcred,
|
||||||
(void (*)(void)) nl_socket_set_msg_buf_size,
|
(void (*)(void)) nl_socket_set_msg_buf_size,
|
||||||
(void (*)(void)) nlmsg_get_dst,
|
(void (*)(void)) nlmsg_get_dst,
|
||||||
(void (*)(void)) nl_socket_set_nonblocking,
|
|
||||||
(void (*)(void)) nl_socket_set_buffer_size,
|
(void (*)(void)) nl_socket_set_buffer_size,
|
||||||
(void (*)(void)) nl_socket_add_memberships,
|
(void (*)(void)) nl_socket_add_memberships,
|
||||||
(void (*)(void)) nl_wait_for_ack,
|
(void (*)(void)) nl_wait_for_ack,
|
||||||
|
|
|
||||||
|
|
@ -499,7 +499,6 @@ out:
|
||||||
static void
|
static void
|
||||||
begin_authentication(AuthRequest *request)
|
begin_authentication(AuthRequest *request)
|
||||||
{
|
{
|
||||||
int fd_flags;
|
|
||||||
const char *helper_argv[] = {
|
const char *helper_argv[] = {
|
||||||
POLKIT_AGENT_HELPER_1_PATH,
|
POLKIT_AGENT_HELPER_1_PATH,
|
||||||
request->username,
|
request->username,
|
||||||
|
|
@ -514,7 +513,7 @@ begin_authentication(AuthRequest *request)
|
||||||
if (!g_spawn_async_with_pipes(NULL,
|
if (!g_spawn_async_with_pipes(NULL,
|
||||||
(char **) helper_argv,
|
(char **) helper_argv,
|
||||||
NULL,
|
NULL,
|
||||||
G_SPAWN_STDERR_TO_DEV_NULL,
|
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_STDERR_TO_DEV_NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
@ -534,11 +533,8 @@ begin_authentication(AuthRequest *request)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_flags = fcntl(request->child_stdin, F_GETFD, 0);
|
nm_io_fcntl_setfl_update_nonblock(request->child_stdin);
|
||||||
fcntl(request->child_stdin, F_SETFL, fd_flags | O_NONBLOCK);
|
nm_io_fcntl_setfl_update_nonblock(request->child_stdout);
|
||||||
|
|
||||||
fd_flags = fcntl(request->child_stdout, F_GETFD, 0);
|
|
||||||
fcntl(request->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
|
|
||||||
|
|
||||||
request->child_stdout_watch_source = nm_g_unix_fd_source_new(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,
|
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,
|
if (!g_spawn_async_with_pipes(NULL,
|
||||||
(char **) auth_dialog_argv->pdata,
|
(char **) auth_dialog_argv->pdata,
|
||||||
NULL,
|
NULL,
|
||||||
G_SPAWN_DO_NOT_REAP_CHILD,
|
G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
&auth_dialog_pid,
|
&auth_dialog_pid,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue