|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
<html>
|
|
Packit |
5756e2 |
<head>
|
|
Packit |
5756e2 |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
Packit |
5756e2 |
<title>Using libnm: libnm Reference Manual</title>
|
|
Packit |
5756e2 |
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
|
|
Packit |
5756e2 |
<link rel="home" href="index.html" title="libnm Reference Manual">
|
|
Packit |
5756e2 |
<link rel="up" href="ref-overview.html" title="Overview">
|
|
Packit |
5756e2 |
<link rel="prev" href="ref-overview.html" title="Overview">
|
|
Packit |
5756e2 |
<link rel="next" href="ch02.html" title="Client Object API Reference">
|
|
Packit Service |
018b0a |
<meta name="generator" content="GTK-Doc V1.33.0 (XML mode)">
|
|
Packit |
5756e2 |
<link rel="stylesheet" href="style.css" type="text/css">
|
|
Packit |
5756e2 |
</head>
|
|
Packit |
5756e2 |
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Using libnm
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
When to use libnm
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
libnm is fairly simple to use from C. It's based on glib and GObject.
|
|
Packit |
5756e2 |
If your project uses these already you'll find integration libnm with your
|
|
Packit |
5756e2 |
project rather convenient. In fact, the nmcli tool shipped
|
|
Packit |
5756e2 |
with NetworkManager is based on libnm.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
libnm should be also the way to go if your project does something non-trivial
|
|
Packit |
5756e2 |
with NetworkManager, such as manipulating the connection profiles.
|
|
Packit |
5756e2 |
That is, if you're writing a specialized networking control tool or a desktop
|
|
Packit |
5756e2 |
environment, libnm is probably the right choice. The popular desktop
|
|
Packit |
5756e2 |
environments in fact all use libnm directly or with nm-applet and
|
|
Packit |
5756e2 |
nm-connection-editor that are all based on libnm.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
An alternative to use of libnm is the use of the
|
|
Packit |
5756e2 |
D-Bus API
|
|
Packit |
5756e2 |
directly. This gives you larger flexibility and reduces the overhead of linking
|
|
Packit |
5756e2 |
with the libnm library. This makes sense if your task is simple and you have a good
|
|
Packit |
5756e2 |
D-Bus library at your disposal. Activating a particular connection profile
|
|
Packit |
5756e2 |
from a Python script is a good example of a task that is perfectly simple
|
|
Packit |
5756e2 |
without using libnm.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
How to use libnm
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
You can use the libnm's C API directly. To do so, all libnm programs need to
|
|
Packit |
5756e2 |
include NetworkManager.h that provides necessary definitions.
|
|
Packit |
5756e2 |
The rest of the API is documented in the reference manual.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
1
|
|
Packit |
5756e2 |
2
|
|
Packit |
5756e2 |
3
|
|
Packit |
5756e2 |
4
|
|
Packit |
5756e2 |
5
|
|
Packit |
5756e2 |
6
|
|
Packit |
5756e2 |
7
|
|
Packit |
5756e2 |
8
|
|
Packit |
5756e2 |
9
|
|
Packit |
5756e2 |
10
|
|
Packit |
5756e2 |
11
|
|
Packit |
5756e2 |
12
|
|
Packit |
5756e2 |
#include <glib.h>
|
|
Packit |
5756e2 |
#include <NetworkManager.h>
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
int
|
|
Packit |
5756e2 |
main (int argc, char *argv[])
|
|
Packit |
5756e2 |
{
|
|
Packit |
5756e2 |
NMClient *client;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
client = nm_client_new (NULL, NULL);
|
|
Packit |
5756e2 |
if (client)
|
|
Packit |
5756e2 |
g_print ("NetworkManager version: %s\n", nm_client_get_version (client));
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Use pkg-config for libnm to discover the necessary
|
|
Packit |
5756e2 |
compiler flags.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
$ cc $(pkg-config --libs --cflags libnm) -o hello-nm hello-nm.c
|
|
Packit |
5756e2 |
$ ./hello-nm
|
|
Packit Service |
018b0a |
NetworkManager version: 1.29.10
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
$
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Utilize the PKG_CHECK_MODULES macro to integrate with an
|
|
Packit |
5756e2 |
autoconf-based build system. It's also recommended to use
|
|
Packit |
5756e2 |
NM_VERSION_MIN_REQUIRED and NM_VERSION_MAX_ALLOWED
|
|
Packit |
5756e2 |
macros to tell libnm headers which API version does your application need to work with.
|
|
Packit |
5756e2 |
If you use them, the compiler will warn you when you use functionality that is not
|
|
Packit |
5756e2 |
available in the versions you specified.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
1
|
|
Packit |
5756e2 |
2
|
|
Packit |
5756e2 |
3
|
|
Packit |
5756e2 |
PKG_CHECK_MODULES(LIBNM, libnm >= 1.8)
|
|
Packit |
5756e2 |
LIBNM_CFLAGS="$LIBNM_CFLAGS -DNM_VERSION_MIN_REQUIRED=NM_VERSION_1_8"
|
|
Packit |
5756e2 |
LIBNM_CFLAGS="$LIBNM_CFLAGS -DNM_VERSION_MAX_ALLOWED=NM_VERSION_1_8"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
You can use libnm from other languages than C with the use of GObject introspection.
|
|
Packit |
5756e2 |
This includes Perl, Python, Javascript, Lua, Ruby and more. The example below shows what the
|
|
Packit |
5756e2 |
typical libnm use in Python would look like.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
1
|
|
Packit |
5756e2 |
2
|
|
Packit |
5756e2 |
3
|
|
Packit |
5756e2 |
4
|
|
Packit |
5756e2 |
5
|
|
Packit |
5756e2 |
6
|
|
Packit |
5756e2 |
import gi
|
|
Packit |
5756e2 |
gi.require_version('NM', '1.0')
|
|
Packit |
5756e2 |
from gi.repository import NM
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
client = NM.Client.new(None)
|
|
Packit |
5756e2 |
print ("NetworkManager version " + client.get_version())
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
There's NM-1.0 Python API Reference
|
|
Packit |
5756e2 |
maintained a third party that is generated from the introspection metadata.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
In general, the C API documentation applies to the use GObject introspection
|
|
Packit |
5756e2 |
from other languages, with the calling convention respecting the language's
|
|
Packit |
5756e2 |
customs. Consult the source tree for
|
|
Packit |
5756e2 |
some examples.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Synchronous API in libnm
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Libnm contains some synchronous API. This API basically makes a blocking
|
|
Packit |
5756e2 |
D-Bus call (g_dbus_connection_call_sync()) and is now deprecated.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Note that D-Bus is fundamentally asynchronous. Doing blocking calls
|
|
Packit |
5756e2 |
on top of D-Bus is odd, especially for libnm's NMClient. That is because
|
|
Packit |
5756e2 |
NMClient essentially is a client-side cache of the objects of the D-Bus
|
|
Packit |
5756e2 |
interface. This cache should be filled exclusively by (asynchronous) D-Bus
|
|
Packit |
5756e2 |
events. So, making a blocking D-Bus call means to wait for a response and
|
|
Packit |
5756e2 |
return it, while queuing everything that happens in between. Basically,
|
|
Packit |
5756e2 |
there are three options how a synchronous API on NMClient could behave:
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
The call basically calls g_dbus_connection_call_sync(). This means
|
|
Packit |
5756e2 |
that libnm sends a D-Bus request via GDBusConnection, and blockingly
|
|
Packit |
5756e2 |
waits for the response. All D-Bus messages that get received in the
|
|
Packit |
5756e2 |
meantime are queued in the GMainContext that belongs to NMClient.
|
|
Packit |
5756e2 |
That means, none of these D-Bus events are processed until we
|
|
Packit |
5756e2 |
iterate the GMainContext after the call returns. The effect is,
|
|
Packit |
5756e2 |
that NMClient (and all cached objects in there) are unaffected by
|
|
Packit |
5756e2 |
the D-Bus request.
|
|
Packit |
5756e2 |
Most of the synchronous API calls in libnm are of this kind.
|
|
Packit |
5756e2 |
The problem is that the strict ordering of D-Bus events gets
|
|
Packit |
5756e2 |
violated.
|
|
Packit |
5756e2 |
For some API this is not an immediate problem. Take for example
|
|
Packit |
5756e2 |
nm_device_wifi_request_scan(). The call merely blockingly tells
|
|
Packit |
5756e2 |
NetworkManager to start scanning, but since NetworkManager's D-Bus
|
|
Packit |
5756e2 |
API does not directly expose any state that tells whether we are
|
|
Packit |
5756e2 |
currently scanning, this out of order processing of the D-Bus
|
|
Packit |
5756e2 |
request is a small issue.
|
|
Packit |
5756e2 |
The problem is more obvious for nm_client_networking_set_enabled().
|
|
Packit |
5756e2 |
After calling it, NM_CLIENT_NETWORKING_ENABLED is still unaffected
|
|
Packit |
5756e2 |
and unchanged, because the PropertiesChanged signal from D-Bus
|
|
Packit |
5756e2 |
is not yet processed.
|
|
Packit |
5756e2 |
This means, while you make such a blocking call, NMClient's state
|
|
Packit |
5756e2 |
does not change. But usually you perform the synchronous call
|
|
Packit |
5756e2 |
to change some state. In this form, the blocking call is not useful,
|
|
Packit |
5756e2 |
because NMClient only changes the state after iterating the GMainContext,
|
|
Packit |
5756e2 |
and not after the blocking call returns.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Like 1), but after making the blocking g_dbus_connection_call_sync(),
|
|
Packit |
5756e2 |
update the NMClient cache artificially. This is what
|
|
Packit |
5756e2 |
nm_manager_check_connectivity() does, to "fix" bgo#784629.
|
|
Packit |
5756e2 |
This also has the problem of out-of-order events, but it kinda
|
|
Packit |
5756e2 |
solves the problem of not changing the state during the blocking
|
|
Packit |
5756e2 |
call. But it does so by hacking the state of the cache. I think
|
|
Packit |
5756e2 |
this is really wrong because the state should only be updated from
|
|
Packit |
5756e2 |
the ordered stream of D-Bus messages. When libnm decides to modify
|
|
Packit |
5756e2 |
the state, there are already D-Bus messages queued that affect this
|
|
Packit |
5756e2 |
very state.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Instead of calling g_dbus_connection_call_sync(), use the
|
|
Packit |
5756e2 |
asynchronous g_dbus_connection_call(). If we would use a separate
|
|
Packit |
5756e2 |
GMainContext for all D-Bus related calls, we could ensure that
|
|
Packit |
5756e2 |
while we block for the response, we iterate the internal main context.
|
|
Packit |
5756e2 |
This might be nice, because all events are processed in order and
|
|
Packit |
5756e2 |
after the blocking call returns, the NMClient state is up to date.
|
|
Packit |
5756e2 |
The are problems however: current blocking API does not do this,
|
|
Packit |
5756e2 |
so it's a significant change in behavior. Also, it might be
|
|
Packit |
5756e2 |
unexpected to the user that during the blocking call the entire
|
|
Packit |
5756e2 |
content of NMClient's cache might change and all pointers to the
|
|
Packit |
5756e2 |
cache might be invalidated. Also, of course NMClient would invoke
|
|
Packit |
5756e2 |
signals for all the changes that happen.
|
|
Packit |
5756e2 |
Another problem is that this would be more effort to implement
|
|
Packit |
5756e2 |
and it involves a small performance overhead for all D-Bus related
|
|
Packit |
5756e2 |
calls (because we have to serialize all events in an internal
|
|
Packit |
5756e2 |
GMainContext first and then invoke them on the caller's context).
|
|
Packit |
5756e2 |
Also, if the users wants this, they could implement it themself
|
|
Packit |
5756e2 |
using their own extra GMainContext and the asynchronous API.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
See also this blog
|
|
Packit |
5756e2 |
for why blocking calls are wrong.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
All possible behaviors for synchronous API have severe behavioural
|
|
Packit |
5756e2 |
issues and thus such API is deprecated. Note that "deprecated" here does not
|
|
Packit |
5756e2 |
mean that the API is going to be removed. Libnm does not break API. The
|
|
Packit |
5756e2 |
user may:
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Continue to use this API. It's deprecated, awkward and discouraged,
|
|
Packit |
5756e2 |
but if it works for you, that's fine.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Use asynchronous API. That's the only sensible way to use D-Bus.
|
|
Packit |
5756e2 |
If libnm lacks a certain asynchronous counterpart, it should be
|
|
Packit |
5756e2 |
added.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
Use GDBusConnection directly. There really isn't anything wrong
|
|
Packit |
5756e2 |
with D-Bus or GDBusConnection. This deprecated API is just a wrapper
|
|
Packit |
5756e2 |
around g_dbus_connection_call_sync(). You may call it directly
|
|
Packit |
5756e2 |
without feeling dirty.
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
|
|
Packit Service |
018b0a |
Generated by GTK-Doc V1.33.0
|
|
Packit |
5756e2 |
</body>
|
|
Packit |
5756e2 |
</html>
|