24
24
25
25
#include < platform/internal/CHIPDeviceLayerInternal.h>
26
26
27
+ #include < arpa/inet.h>
28
+ #include < dirent.h>
29
+ #include < errno.h>
30
+ #include < linux/netlink.h>
31
+ #include < linux/rtnetlink.h>
32
+ #include < net/if.h>
33
+ #include < netinet/in.h>
34
+ #include < unistd.h>
35
+
36
+ #include < mutex>
37
+
27
38
#include < app-common/zap-generated/enums.h>
28
39
#include < app-common/zap-generated/ids/Events.h>
29
40
#include < lib/support/CHIPMem.h>
35
46
#include < platform/PlatformManager.h>
36
47
#include < platform/internal/GenericPlatformManagerImpl_POSIX.ipp>
37
48
38
- #include < thread>
39
-
40
- #include < arpa/inet.h>
41
- #include < dirent.h>
42
- #include < errno.h>
43
- #include < linux/netlink.h>
44
- #include < linux/rtnetlink.h>
45
- #include < net/if.h>
46
- #include < netinet/in.h>
47
- #include < unistd.h>
48
-
49
- #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
50
- #include < sys/syscall.h>
51
- #define gettid () syscall(SYS_gettid)
52
- #endif
53
-
54
49
using namespace ::chip::app::Clusters;
55
50
56
51
namespace chip {
@@ -60,41 +55,32 @@ PlatformManagerImpl PlatformManagerImpl::sInstance;
60
55
61
56
namespace {
62
57
63
- #if CHIP_WITH_GIO
64
- void GDBus_Thread ( )
58
+ #if CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
59
+ void * GLibMainLoopThread ( void * loop )
65
60
{
66
- GMainLoop * loop = g_main_loop_new (nullptr , false );
67
-
68
- g_main_loop_run (loop);
69
- g_main_loop_unref (loop);
61
+ g_main_loop_run (static_cast <GMainLoop *>(loop));
62
+ return nullptr ;
70
63
}
71
64
#endif
72
- } // namespace
73
65
74
66
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
75
- void PlatformManagerImpl::WiFIIPChangeListener ()
67
+
68
+ gboolean WiFiIPChangeListener (GIOChannel * ch, GIOCondition /* condition */ , void * /* userData */ )
76
69
{
77
- int sock;
78
- if ((sock = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1 )
79
- {
80
- ChipLogError (DeviceLayer, " Failed to init netlink socket for ip addresses." );
81
- return ;
82
- }
83
70
84
- struct sockaddr_nl addr;
85
- memset (&addr, 0 , sizeof (addr));
86
- addr.nl_family = AF_NETLINK;
87
- addr.nl_groups = RTMGRP_IPV4_IFADDR;
71
+ char buffer[4096 ];
72
+ auto * header = reinterpret_cast <struct nlmsghdr *>(buffer);
73
+ ssize_t len;
88
74
89
- if (bind (sock, ( struct sockaddr *) &addr , sizeof (addr )) == -1 )
75
+ if ((len = recv ( g_io_channel_unix_get_fd (ch), buffer , sizeof (buffer), 0 )) == -1 )
90
76
{
91
- ChipLogError (DeviceLayer, " Failed to bind netlink socket for ip addresses." );
92
- return ;
77
+ if (errno == EINTR || errno == EAGAIN)
78
+ return G_SOURCE_CONTINUE;
79
+ ChipLogError (DeviceLayer, " Error reading from netlink socket: %d" , errno);
80
+ return G_SOURCE_CONTINUE;
93
81
}
94
82
95
- ssize_t len;
96
- char buffer[4096 ];
97
- for (struct nlmsghdr * header = reinterpret_cast <struct nlmsghdr *>(buffer); (len = recv (sock, header, sizeof (buffer), 0 )) > 0 ;)
83
+ if (len > 0 )
98
84
{
99
85
for (struct nlmsghdr * messageHeader = header;
100
86
(NLMSG_OK (messageHeader, static_cast <uint32_t >(len))) && (messageHeader->nlmsg_type != NLMSG_DONE);
@@ -154,23 +140,70 @@ void PlatformManagerImpl::WiFIIPChangeListener()
154
140
}
155
141
}
156
142
}
143
+ else
144
+ {
145
+ ChipLogError (DeviceLayer, " EOF on netlink socket" );
146
+ return G_SOURCE_REMOVE;
147
+ }
148
+
149
+ return G_SOURCE_CONTINUE;
157
150
}
151
+
152
+ // The temporary hack for getting IP address change on linux for network provisioning in the rendezvous session.
153
+ // This should be removed or find a better place once we deprecate the rendezvous session.
154
+ CHIP_ERROR RunWiFiIPChangeListener ()
155
+ {
156
+ int sock;
157
+ if ((sock = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1 )
158
+ {
159
+ ChipLogError (DeviceLayer, " Failed to init netlink socket for IP addresses: %d" , errno);
160
+ return CHIP_ERROR_INTERNAL;
161
+ }
162
+
163
+ struct sockaddr_nl addr;
164
+ memset (&addr, 0 , sizeof (addr));
165
+ addr.nl_family = AF_NETLINK;
166
+ addr.nl_groups = RTMGRP_IPV4_IFADDR;
167
+
168
+ if (bind (sock, (struct sockaddr *) &addr, sizeof (addr)) == -1 )
169
+ {
170
+ ChipLogError (DeviceLayer, " Failed to bind netlink socket for IP addresses: %d" , errno);
171
+ close (sock);
172
+ return CHIP_ERROR_INTERNAL;
173
+ }
174
+
175
+ GIOChannel * ch = g_io_channel_unix_new (sock);
176
+ g_io_add_watch_full (ch, G_PRIORITY_DEFAULT, G_IO_IN, WiFiIPChangeListener, nullptr , nullptr );
177
+
178
+ g_io_channel_set_close_on_unref (ch, TRUE );
179
+ g_io_channel_set_encoding (ch, nullptr , nullptr );
180
+ g_io_channel_unref (ch);
181
+
182
+ return CHIP_NO_ERROR;
183
+ }
184
+
158
185
#endif // #if CHIP_DEVICE_CONFIG_ENABLE_WIFI
159
186
187
+ } // namespace
188
+
160
189
CHIP_ERROR PlatformManagerImpl::_InitChipStack ()
161
190
{
162
- #if CHIP_WITH_GIO
163
- GError * error = nullptr ;
191
+ #if CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
164
192
165
- this ->mpGDBusConnection = UniqueGDBusConnection (g_bus_get_sync (G_BUS_TYPE_SYSTEM, nullptr , &error));
193
+ mGLibMainLoop = g_main_loop_new (nullptr , FALSE );
194
+ mGLibMainLoopThread = g_thread_new (" gmain-matter" , GLibMainLoopThread, mGLibMainLoop );
195
+
196
+ {
197
+ std::unique_lock<std::mutex> lock (mGLibMainLoopCallbackIndirectionMutex );
198
+ CallbackIndirection startedInd ([](void *) { return G_SOURCE_REMOVE; }, nullptr );
199
+ g_idle_add (G_SOURCE_FUNC (&CallbackIndirection::Callback), &startedInd);
200
+ startedInd.Wait (lock);
201
+ }
166
202
167
- std::thread gdbusThread (GDBus_Thread);
168
- gdbusThread.detach ();
169
203
#endif
170
204
171
205
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
172
- std::thread wifiIPThread (WiFIIPChangeListener);
173
- wifiIPThread.detach ();
206
+ ReturnErrorOnFailure (RunWiFiIPChangeListener ());
174
207
#endif
175
208
176
209
// Initialize the configuration system.
@@ -212,14 +245,64 @@ void PlatformManagerImpl::_Shutdown()
212
245
}
213
246
214
247
Internal::GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>::_Shutdown ();
248
+
249
+ #if CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
250
+ g_main_loop_quit (mGLibMainLoop );
251
+ g_main_loop_unref (mGLibMainLoop );
252
+ g_thread_join (mGLibMainLoopThread );
253
+ #endif
215
254
}
216
255
217
- #if CHIP_WITH_GIO
218
- GDBusConnection * PlatformManagerImpl::GetGDBusConnection ()
256
+ #if CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
257
+
258
+ void PlatformManagerImpl::CallbackIndirection::Wait (std::unique_lock<std::mutex> & lock)
219
259
{
220
- return this -> mpGDBusConnection . get ( );
260
+ mDoneCond . wait (lock, [ this ]() { return mDone ; } );
221
261
}
222
- #endif
262
+
263
+ gboolean PlatformManagerImpl::CallbackIndirection::Callback (CallbackIndirection * self)
264
+ {
265
+ // We can not access "self" before acquiring the lock, because TSAN will complain that
266
+ // there is a race condition between the thread that created the object and the thread
267
+ // that is executing the callback.
268
+ std::unique_lock<std::mutex> lock (PlatformMgrImpl ().mGLibMainLoopCallbackIndirectionMutex );
269
+
270
+ auto callback = self->mCallback ;
271
+ auto userData = self->mUserData ;
272
+
273
+ lock.unlock ();
274
+ auto result = callback (userData);
275
+ lock.lock ();
276
+
277
+ self->mDone = true ;
278
+ self->mDoneCond .notify_all ();
279
+
280
+ return result;
281
+ }
282
+
283
+ #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
284
+ CHIP_ERROR PlatformManagerImpl::RunOnGLibMainLoopThread (GSourceFunc callback, void * userData, bool wait)
285
+ {
286
+
287
+ GMainContext * context = g_main_loop_get_context (mGLibMainLoop );
288
+ VerifyOrReturnError (context != nullptr ,
289
+ (ChipLogDetail (DeviceLayer, " Failed to get GLib main loop context" ), CHIP_ERROR_INTERNAL));
290
+
291
+ if (wait )
292
+ {
293
+ std::unique_lock<std::mutex> lock (mGLibMainLoopCallbackIndirectionMutex );
294
+ CallbackIndirection indirection (callback, userData);
295
+ g_main_context_invoke (context, G_SOURCE_FUNC (&CallbackIndirection::Callback), &indirection);
296
+ indirection.Wait (lock);
297
+ return CHIP_NO_ERROR;
298
+ }
299
+
300
+ g_main_context_invoke (context, callback, userData);
301
+ return CHIP_NO_ERROR;
302
+ }
303
+ #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
304
+
305
+ #endif // CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
223
306
224
307
} // namespace DeviceLayer
225
308
} // namespace chip
0 commit comments