VirtualBox

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

Last change on this file since 53517 was 52617, checked in by vboxsync, 10 years ago

Main/src-server: missed header update.

  • 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 52617 2014-09-05 11:36:45Z 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 /* notifyAll() takes required locks */
156 notifyAll();
157 }
158 else if (combo.e.mask & IN_DELETE_SELF)
159 {
160 inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */
161 inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
162 IN_MOVED_TO|IN_CREATE); /* alter folder watcher */
163 }
164 else if (combo.e.mask & IN_IGNORED)
165 {
166 wd[0] = -1; /* we want receive any events on this watch */
167 }
168 else
169 {
170 /**
171 * It shouldn't happen, in release we will just ignore in debug
172 * we will have to chance to look at into inotify_event
173 */
174 AssertMsgFailed(("Debug Me!!!"));
175 }
176 }
177 else if (combo.e.wd == wd[1])
178 {
179 if ( combo.e.mask & IN_MOVED_FROM
180 || combo.e.mask & IN_DELETE)
181 {
182 if (g_ResolvConf == combo.e.name)
183 {
184 /**
185 * Our file has been moved so we should change watching mode.
186 */
187 inotify_rm_watch(a.fileDescriptor(), wd[0]);
188 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
189 IN_MOVED_TO|IN_CREATE);
190 AssertMsg(wd[1] != -1,
191 ("It shouldn't happen, further investigation is needed\n"));
192 }
193 }
194 else
195 {
196 AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE),
197 ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n",
198 combo.e.mask));
199 if (g_ResolvConf == combo.e.name)
200 {
201 AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n"));
202
203 /* alter folder watcher*/
204 wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
205 IN_MOVED_FROM|IN_DELETE);
206 AssertMsg(wd[1] != -1, ("It shouldn't happen.\n"));
207
208 wd[0] = inotify_add_watch(a.fileDescriptor(),
209 g_ResolvConfFullPath.c_str(),
210 IN_CLOSE_WRITE | IN_DELETE_SELF);
211 AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n",
212 g_ResolvConfFullPath.c_str()));
213
214 /* Notify our listeners */
215 readResolvConf();
216 notifyAll();
217
218 }
219 }
220 }
221 else
222 {
223 /* It shouldn't happen */
224 AssertMsgFailed(("Shouldn't happen! Please debug me!"));
225 }
226 }
227 }
228}
229
230
231void HostDnsServiceLinux::monitorThreadShutdown()
232{
233 send(g_DnsMonitorStop[0], "", 1, 0);
234}
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