VirtualBox

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

Last change on this file since 71007 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.2 KB
Line 
1/* $Id: HostDnsServiceLinux.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 * Linux specific DNS information fetching.
4 */
5
6/*
7 * Copyright (C) 2013-2017 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/err.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 monitorThreadShutdown();
93}
94
95
96int HostDnsServiceLinux::monitorWorker()
97{
98
99 AutoNotify a;
100
101 int rc = socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_DnsMonitorStop);
102 AssertMsgReturn(rc == 0, ("socketpair: failed (%d: %s)\n", errno, strerror(errno)), E_FAIL);
103
104 FileDescriptor stopper0(g_DnsMonitorStop[0]);
105 FileDescriptor stopper1(g_DnsMonitorStop[1]);
106
107 pollfd polls[2];
108 RT_ZERO(polls);
109
110 polls[0].fd = a.fileDescriptor();
111 polls[0].events = POLLIN;
112
113 polls[1].fd = g_DnsMonitorStop[1];
114 polls[1].events = POLLIN;
115
116 monitorThreadInitializationDone();
117
118 int wd[2];
119 wd[0] = wd[1] = -1;
120 /* inotify inialization */
121 wd[0] = inotify_add_watch(a.fileDescriptor(),
122 g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE|IN_DELETE_SELF);
123
124 /**
125 * If /etc/resolv.conf exists we want to listen for movements: because
126 * # mv /etc/resolv.conf ...
127 * won't arm IN_DELETE_SELF on wd[0] instead it will fire IN_MOVE_FROM on wd[1].
128 *
129 * Because on some distributions /etc/resolv.conf is link, wd[0] can't detect deletion,
130 * it's recognizible on directory level (wd[1]) only.
131 */
132 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
133 wd[0] == -1 ? IN_MOVED_TO|IN_CREATE : IN_MOVED_FROM|IN_DELETE);
134
135 struct InotifyEventWithName combo;
136 while(true)
137 {
138 rc = poll(polls, 2, -1);
139 if (rc == -1)
140 continue;
141
142 AssertMsgReturn( ((polls[0].revents & (POLLERR|POLLNVAL)) == 0)
143 && ((polls[1].revents & (POLLERR|POLLNVAL)) == 0),
144 ("Debug Me"), VERR_INTERNAL_ERROR);
145
146 if (polls[1].revents & POLLIN)
147 return VINF_SUCCESS; /* time to shutdown */
148
149 if (polls[0].revents & POLLIN)
150 {
151 RT_ZERO(combo);
152 ssize_t r = read(polls[0].fd, static_cast<void *>(&combo), sizeof(combo));
153 NOREF(r);
154
155 if (combo.e.wd == wd[0])
156 {
157 if (combo.e.mask & IN_CLOSE_WRITE)
158 {
159 readResolvConf();
160 }
161 else if (combo.e.mask & IN_DELETE_SELF)
162 {
163 inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */
164 inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
165 IN_MOVED_TO|IN_CREATE); /* alter folder watcher */
166 }
167 else if (combo.e.mask & IN_IGNORED)
168 {
169 wd[0] = -1; /* we want receive any events on this watch */
170 }
171 else
172 {
173 /**
174 * It shouldn't happen, in release we will just ignore in debug
175 * we will have to chance to look at into inotify_event
176 */
177 AssertMsgFailed(("Debug Me!!!"));
178 }
179 }
180 else if (combo.e.wd == wd[1])
181 {
182 if ( combo.e.mask & IN_MOVED_FROM
183 || combo.e.mask & IN_DELETE)
184 {
185 if (g_ResolvConf == combo.e.name)
186 {
187 /**
188 * Our file has been moved so we should change watching mode.
189 */
190 inotify_rm_watch(a.fileDescriptor(), wd[0]);
191 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
192 IN_MOVED_TO|IN_CREATE);
193 AssertMsg(wd[1] != -1,
194 ("It shouldn't happen, further investigation is needed\n"));
195 }
196 }
197 else
198 {
199 AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE),
200 ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n",
201 combo.e.mask));
202 if (g_ResolvConf == combo.e.name)
203 {
204 AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n"));
205
206 /* alter folder watcher*/
207 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
208 IN_MOVED_FROM|IN_DELETE);
209 AssertMsg(wd[1] != -1, ("It shouldn't happen.\n"));
210
211 wd[0] = inotify_add_watch(a.fileDescriptor(),
212 g_ResolvConfFullPath.c_str(),
213 IN_CLOSE_WRITE | IN_DELETE_SELF);
214 AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n",
215 g_ResolvConfFullPath.c_str()));
216
217 /* Notify our listeners */
218 readResolvConf();
219 }
220 }
221 }
222 else
223 {
224 /* It shouldn't happen */
225 AssertMsgFailed(("Shouldn't happen! Please debug me!"));
226 }
227 }
228 }
229}
230
231
232void HostDnsServiceLinux::monitorThreadShutdown()
233{
234 send(g_DnsMonitorStop[0], "", 1, 0);
235}
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