VirtualBox

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

Last change on this file since 56035 was 54662, checked in by vboxsync, 10 years ago

Main/HostDnsService: instead of keeping fragile state g/c notifyAll()
and just notify proxy directly from setInfo() when info changed.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.0 KB
Line 
1/* $Id: HostDnsServiceLinux.cpp 54662 2015-03-06 05:29:44Z vboxsync $ */
2/** @file
3 * Linux specific DNS information fetching.
4 */
5
6/*
7 * Copyright (C) 2013-2014 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#include <sys/inotify.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40
41#include <string>
42#include <vector>
43#include "../HostDnsService.h"
44
45
46static int g_DnsMonitorStop[2];
47
48static const std::string g_EtcFolder = "/etc";
49static const std::string g_ResolvConf = "resolv.conf";
50static const std::string g_ResolvConfFullPath = "/etc/resolv.conf";
51
52class FileDescriptor
53{
54 public:
55 FileDescriptor(int d = -1):fd(d){}
56
57 virtual ~FileDescriptor() {
58 if (fd != -1)
59 close(fd);
60 }
61
62 int fileDescriptor() const {return fd;}
63
64 protected:
65 int fd;
66};
67
68
69class AutoNotify:public FileDescriptor
70{
71 public:
72 AutoNotify()
73 {
74 FileDescriptor::fd = inotify_init();
75 AssertReturnVoid(FileDescriptor::fd != -1);
76 }
77};
78
79struct InotifyEventWithName
80{
81 struct inotify_event e;
82 char name[NAME_MAX];
83};
84
85HostDnsServiceLinux::~HostDnsServiceLinux()
86{
87 monitorThreadShutdown();
88}
89
90
91int HostDnsServiceLinux::monitorWorker()
92{
93
94 AutoNotify a;
95
96 int rc = socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_DnsMonitorStop);
97 AssertMsgReturn(rc == 0, ("socketpair: failed (%d: %s)\n", errno, strerror(errno)), E_FAIL);
98
99 FileDescriptor stopper0(g_DnsMonitorStop[0]);
100 FileDescriptor stopper1(g_DnsMonitorStop[1]);
101
102 pollfd polls[2];
103 RT_ZERO(polls);
104
105 polls[0].fd = a.fileDescriptor();
106 polls[0].events = POLLIN;
107
108 polls[1].fd = g_DnsMonitorStop[1];
109 polls[1].events = POLLIN;
110
111 monitorThreadInitializationDone();
112
113 int wd[2];
114 wd[0] = wd[1] = -1;
115 /* inotify inialization */
116 wd[0] = inotify_add_watch(a.fileDescriptor(),
117 g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE|IN_DELETE_SELF);
118
119 /**
120 * If /etc/resolv.conf exists we want to listen for movements: because
121 * # mv /etc/resolv.conf ...
122 * won't arm IN_DELETE_SELF on wd[0] instead it will fire IN_MOVE_FROM on wd[1].
123 *
124 * Because on some distributions /etc/resolv.conf is link, wd[0] can't detect deletion,
125 * it's recognizible on directory level (wd[1]) only.
126 */
127 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
128 wd[0] == -1 ? IN_MOVED_TO|IN_CREATE : IN_MOVED_FROM|IN_DELETE);
129
130 struct InotifyEventWithName combo;
131 while(true)
132 {
133 rc = poll(polls, 2, -1);
134 if (rc == -1)
135 continue;
136
137 AssertMsgReturn( ((polls[0].revents & (POLLERR|POLLNVAL)) == 0)
138 && ((polls[1].revents & (POLLERR|POLLNVAL)) == 0),
139 ("Debug Me"), VERR_INTERNAL_ERROR);
140
141 if (polls[1].revents & POLLIN)
142 return VINF_SUCCESS; /* time to shutdown */
143
144 if (polls[0].revents & POLLIN)
145 {
146 RT_ZERO(combo);
147 ssize_t r = read(polls[0].fd, static_cast<void *>(&combo), sizeof(combo));
148 NOREF(r);
149
150 if (combo.e.wd == wd[0])
151 {
152 if (combo.e.mask & IN_CLOSE_WRITE)
153 {
154 readResolvConf();
155 }
156 else if (combo.e.mask & IN_DELETE_SELF)
157 {
158 inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */
159 inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
160 IN_MOVED_TO|IN_CREATE); /* alter folder watcher */
161 }
162 else if (combo.e.mask & IN_IGNORED)
163 {
164 wd[0] = -1; /* we want receive any events on this watch */
165 }
166 else
167 {
168 /**
169 * It shouldn't happen, in release we will just ignore in debug
170 * we will have to chance to look at into inotify_event
171 */
172 AssertMsgFailed(("Debug Me!!!"));
173 }
174 }
175 else if (combo.e.wd == wd[1])
176 {
177 if ( combo.e.mask & IN_MOVED_FROM
178 || combo.e.mask & IN_DELETE)
179 {
180 if (g_ResolvConf == combo.e.name)
181 {
182 /**
183 * Our file has been moved so we should change watching mode.
184 */
185 inotify_rm_watch(a.fileDescriptor(), wd[0]);
186 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
187 IN_MOVED_TO|IN_CREATE);
188 AssertMsg(wd[1] != -1,
189 ("It shouldn't happen, further investigation is needed\n"));
190 }
191 }
192 else
193 {
194 AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE),
195 ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n",
196 combo.e.mask));
197 if (g_ResolvConf == combo.e.name)
198 {
199 AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n"));
200
201 /* alter folder watcher*/
202 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
203 IN_MOVED_FROM|IN_DELETE);
204 AssertMsg(wd[1] != -1, ("It shouldn't happen.\n"));
205
206 wd[0] = inotify_add_watch(a.fileDescriptor(),
207 g_ResolvConfFullPath.c_str(),
208 IN_CLOSE_WRITE | IN_DELETE_SELF);
209 AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n",
210 g_ResolvConfFullPath.c_str()));
211
212 /* Notify our listeners */
213 readResolvConf();
214 }
215 }
216 }
217 else
218 {
219 /* It shouldn't happen */
220 AssertMsgFailed(("Shouldn't happen! Please debug me!"));
221 }
222 }
223 }
224}
225
226
227void HostDnsServiceLinux::monitorThreadShutdown()
228{
229 send(g_DnsMonitorStop[0], "", 1, 0);
230}
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