VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp@ 78273

Last change on this file since 78273 was 77993, checked in by vboxsync, 6 years ago

Main/HostDnsService: Some more cleanup and renaming.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.5 KB
Line 
1/* $Id: HostDnsServiceLinux.cpp 77993 2019-04-03 15:11:36Z vboxsync $ */
2/** @file
3 * Linux specific DNS information fetching.
4 */
5
6/*
7 * Copyright (C) 2013-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <iprt/assert.h>
19#include <iprt/errcore.h>
20#include <iprt/initterm.h>
21#include <iprt/file.h>
22#include <iprt/log.h>
23#include <iprt/stream.h>
24#include <iprt/string.h>
25#include <iprt/semaphore.h>
26#include <iprt/thread.h>
27
28#include <errno.h>
29#include <poll.h>
30#include <string.h>
31#include <unistd.h>
32
33#include <fcntl.h>
34
35#include <linux/limits.h>
36
37/* Workaround for <sys/cdef.h> defining __flexarr to [] which beats us in
38 * struct inotify_event (char name __flexarr). */
39#include <sys/cdefs.h>
40#undef __flexarr
41#define __flexarr [0]
42#include <sys/inotify.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45
46#include <string>
47#include <vector>
48#include "../HostDnsService.h"
49
50
51static int g_DnsMonitorStop[2];
52
53static const std::string g_EtcFolder = "/etc";
54static const std::string g_ResolvConf = "resolv.conf";
55static const std::string g_ResolvConfFullPath = "/etc/resolv.conf";
56
57class FileDescriptor
58{
59 public:
60 FileDescriptor(int d = -1):fd(d){}
61
62 virtual ~FileDescriptor() {
63 if (fd != -1)
64 close(fd);
65 }
66
67 int fileDescriptor() const {return fd;}
68
69 protected:
70 int fd;
71};
72
73
74class AutoNotify:public FileDescriptor
75{
76 public:
77 AutoNotify()
78 {
79 FileDescriptor::fd = inotify_init();
80 AssertReturnVoid(FileDescriptor::fd != -1);
81 }
82};
83
84struct InotifyEventWithName
85{
86 struct inotify_event e;
87 char name[NAME_MAX];
88};
89
90HostDnsServiceLinux::~HostDnsServiceLinux()
91{
92}
93
94HRESULT HostDnsServiceLinux::init(HostDnsMonitorProxy *pProxy)
95{
96 return HostDnsServiceResolvConf::init(pProxy, "/etc/resolv.conf");
97}
98
99int HostDnsServiceLinux::monitorThreadShutdown(RTMSINTERVAL uTimeoutMs)
100{
101 RT_NOREF(uTimeoutMs);
102
103 send(g_DnsMonitorStop[0], "", 1, 0);
104
105 /** @todo r=andy Do we have to wait for something here? Can this fail? */
106 return VINF_SUCCESS;
107}
108
109int HostDnsServiceLinux::monitorThreadProc(void)
110{
111 AutoNotify a;
112
113 int rc = socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_DnsMonitorStop);
114 AssertMsgReturn(rc == 0, ("socketpair: failed (%d: %s)\n", errno, strerror(errno)), E_FAIL);
115
116 FileDescriptor stopper0(g_DnsMonitorStop[0]);
117 FileDescriptor stopper1(g_DnsMonitorStop[1]);
118
119 pollfd polls[2];
120 RT_ZERO(polls);
121
122 polls[0].fd = a.fileDescriptor();
123 polls[0].events = POLLIN;
124
125 polls[1].fd = g_DnsMonitorStop[1];
126 polls[1].events = POLLIN;
127
128 onMonitorThreadInitDone();
129
130 int wd[2];
131 wd[0] = wd[1] = -1;
132 /* inotify inialization */
133 wd[0] = inotify_add_watch(a.fileDescriptor(),
134 g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE|IN_DELETE_SELF);
135
136 /**
137 * If /etc/resolv.conf exists we want to listen for movements: because
138 * # mv /etc/resolv.conf ...
139 * won't arm IN_DELETE_SELF on wd[0] instead it will fire IN_MOVE_FROM on wd[1].
140 *
141 * Because on some distributions /etc/resolv.conf is link, wd[0] can't detect deletion,
142 * it's recognizible on directory level (wd[1]) only.
143 */
144 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
145 wd[0] == -1 ? IN_MOVED_TO|IN_CREATE : IN_MOVED_FROM|IN_DELETE);
146
147 struct InotifyEventWithName combo;
148 while(true)
149 {
150 rc = poll(polls, 2, -1);
151 if (rc == -1)
152 continue;
153
154 AssertMsgReturn( ((polls[0].revents & (POLLERR|POLLNVAL)) == 0)
155 && ((polls[1].revents & (POLLERR|POLLNVAL)) == 0),
156 ("Debug Me"), VERR_INTERNAL_ERROR);
157
158 if (polls[1].revents & POLLIN)
159 return VINF_SUCCESS; /* time to shutdown */
160
161 if (polls[0].revents & POLLIN)
162 {
163 RT_ZERO(combo);
164 ssize_t r = read(polls[0].fd, static_cast<void *>(&combo), sizeof(combo));
165 RT_NOREF(r);
166
167 if (combo.e.wd == wd[0])
168 {
169 if (combo.e.mask & IN_CLOSE_WRITE)
170 {
171 readResolvConf();
172 }
173 else if (combo.e.mask & IN_DELETE_SELF)
174 {
175 inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */
176 inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
177 IN_MOVED_TO|IN_CREATE); /* alter folder watcher */
178 }
179 else if (combo.e.mask & IN_IGNORED)
180 {
181 wd[0] = -1; /* we want receive any events on this watch */
182 }
183 else
184 {
185 /**
186 * It shouldn't happen, in release we will just ignore in debug
187 * we will have to chance to look at into inotify_event
188 */
189 AssertMsgFailed(("Debug Me!!!"));
190 }
191 }
192 else if (combo.e.wd == wd[1])
193 {
194 if ( combo.e.mask & IN_MOVED_FROM
195 || combo.e.mask & IN_DELETE)
196 {
197 if (g_ResolvConf == combo.e.name)
198 {
199 /**
200 * Our file has been moved so we should change watching mode.
201 */
202 inotify_rm_watch(a.fileDescriptor(), wd[0]);
203 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
204 IN_MOVED_TO|IN_CREATE);
205 AssertMsg(wd[1] != -1,
206 ("It shouldn't happen, further investigation is needed\n"));
207 }
208 }
209 else
210 {
211 AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE),
212 ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n",
213 combo.e.mask));
214 if (g_ResolvConf == combo.e.name)
215 {
216 AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n"));
217
218 /* alter folder watcher*/
219 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
220 IN_MOVED_FROM|IN_DELETE);
221 AssertMsg(wd[1] != -1, ("It shouldn't happen.\n"));
222
223 wd[0] = inotify_add_watch(a.fileDescriptor(),
224 g_ResolvConfFullPath.c_str(),
225 IN_CLOSE_WRITE | IN_DELETE_SELF);
226 AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n",
227 g_ResolvConfFullPath.c_str()));
228
229 /* Notify our listeners */
230 readResolvConf();
231 }
232 }
233 }
234 else
235 {
236 /* It shouldn't happen */
237 AssertMsgFailed(("Shouldn't happen! Please debug me!"));
238 }
239 }
240 }
241}
242
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette