VirtualBox

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

Last change on this file since 50263 was 50263, checked in by vboxsync, 11 years ago

Main/HostDnsService:

  • Generic part could be used with threading on or off: OS which can monitor changes on DNS structures might need this (e.g. Windows, Darwin, Linux)
  • ResolvConf based (Linux, Solaris, FreeBSD ans Os/2) doesn't use scanf based resovl.conf parsing new Slirp's parser used instead. It's configured to provide strings instead of addresses. (to resolve xtracker/7034c2)
  • Darwin monitoring code has been refactored.
  • linux changed to handle cases described in xtracker/7034c3
  • Windows monitors changes on register changes.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.1 KB
Line 
1/* $Id: HostDnsServiceLinux.cpp 50263 2014-01-28 19:29:52Z vboxsync $ */
2/** @file
3 * Linux specific DNS information fetching.
4 */
5
6/*
7 * Copyright (C) 2013 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
149 if (combo.e.wd == wd[0])
150 {
151 if (combo.e.mask & IN_CLOSE_WRITE)
152 {
153 readResolvConf();
154 /* notifyAll() takes required locks */
155 notifyAll();
156 }
157 else if (combo.e.mask & IN_DELETE_SELF)
158 {
159 inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */
160 inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
161 IN_MOVED_TO|IN_CREATE); /* alter folder watcher */
162 }
163 else if (combo.e.mask & IN_IGNORED)
164 {
165 wd[0] = -1; /* we want receive any events on this watch */
166 }
167 else
168 {
169 /**
170 * It shouldn't happen, in release we will just ignore in debug
171 * we will have to chance to look at into inotify_event
172 */
173 AssertMsgFailed(("Debug Me!!!"));
174 }
175 }
176 else if (combo.e.wd == wd[1])
177 {
178 if ( combo.e.mask & IN_MOVED_FROM
179 || combo.e.mask & IN_DELETE)
180 {
181 if (g_ResolvConf == combo.e.name)
182 {
183 /**
184 * Our file has been moved so we should change watching mode.
185 */
186 inotify_rm_watch(a.fileDescriptor(), wd[0]);
187 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
188 IN_MOVED_TO|IN_CREATE);
189 AssertMsg(wd[1] != -1,
190 ("It shouldn't happen, further investigation is needed\n"));
191 }
192 }
193 else
194 {
195 AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE),
196 ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n",
197 combo.e.mask));
198 if (g_ResolvConf == combo.e.name)
199 {
200 AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n"));
201
202 /* alter folder watcher*/
203 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
204 IN_MOVED_FROM|IN_DELETE);
205 AssertMsg(wd[1] != -1, ("It shouldn't happen.\n"));
206
207 wd[0] = inotify_add_watch(a.fileDescriptor(),
208 g_ResolvConfFullPath.c_str(),
209 IN_CLOSE_WRITE | IN_DELETE_SELF);
210 AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n",
211 g_ResolvConfFullPath.c_str()));
212
213 /* Notify our listeners */
214 readResolvConf();
215 notifyAll();
216
217 }
218 }
219 }
220 else
221 {
222 /* It shouldn't happen */
223 AssertMsgFailed(("Shouldn't happen! Please debug me!"));
224 }
225 }
226 }
227}
228
229
230void HostDnsServiceLinux::monitorThreadShutdown()
231{
232 send(g_DnsMonitorStop[0], "", 1, 0);
233}
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