]>
Commit | Line | Data |
---|---|---|
275abf24 | 1 | // -*- c++ -*- /////////////////////////////////////////////////////////////// |
80fdcdb9 | 2 | // Name: src/unix/net.cpp |
275abf24 | 3 | // Purpose: Network related wxWindows classes and functions |
e9670814 | 4 | // Author: Karsten Ballüder |
275abf24 KB |
5 | // Modified by: |
6 | // Created: 03.10.99 | |
e9670814 | 7 | // Copyright: (c) Karsten Ballüder |
275abf24 KB |
8 | // Licence: wxWindows licence |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #include "wx/setup.h" | |
12 | ||
13 | #if wxUSE_DIALUP_MANAGER | |
14 | ||
15 | #ifndef WX_PRECOMP | |
16 | # include "wx/defs.h" | |
17 | #endif // !PCH | |
18 | ||
19 | #include "wx/string.h" | |
20 | #include "wx/event.h" | |
21 | #include "wx/net.h" | |
22 | #include "wx/timer.h" | |
a51e601e | 23 | #include "wx/filename.h" |
275abf24 KB |
24 | #include "wx/utils.h" |
25 | #include "wx/log.h" | |
26 | #include "wx/file.h" | |
27 | ||
28 | #include <stdlib.h> | |
29 | #include <signal.h> | |
30 | #include <fcntl.h> | |
31 | #include <unistd.h> | |
32 | #define __STRICT_ANSI__ | |
33 | #include <sys/socket.h> | |
34 | #include <sys/types.h> | |
35 | #include <sys/stat.h> | |
36 | #include <netdb.h> | |
37 | #include <netinet/in.h> | |
38 | #include <arpa/inet.h> | |
39 | ||
40 | // ---------------------------------------------------------------------------- | |
41 | // A class which groups functions dealing with connecting to the network from a | |
42 | // workstation using dial-up access to the net. There is at most one instance | |
43 | // of this class in the program accessed via GetDialUpManager(). | |
44 | // ---------------------------------------------------------------------------- | |
45 | ||
46 | /* TODO | |
47 | * | |
48 | * 1. more configurability for Unix: i.e. how to initiate the connection, how | |
49 | * to check for online status, &c. | |
50 | * 2. add a "long Dial(long connectionId = -1)" function which asks the user | |
51 | * about which connection to dial (this may be done using native dialogs | |
52 | * under NT, need generic dialogs for all others) and returns the identifier | |
53 | * of the selected connection (it's opaque to the application) - it may be | |
54 | * reused later to dial the same connection later (or use strings instead of | |
55 | * longs may be?) | |
56 | * 3. add an async version of dialing functions which notify the caller about | |
57 | * the progress (or may be even start another thread to monitor it) | |
58 | * 4. the static creation/accessor functions are not MT-safe - but is this | |
59 | * really crucial? I think we may suppose they're always called from the | |
60 | * main thread? | |
61 | */ | |
62 | ||
63 | class WXDLLEXPORT wxDialUpManagerImpl : public wxDialUpManager | |
64 | { | |
65 | public: | |
66 | wxDialUpManagerImpl() | |
67 | { | |
68 | m_IsOnline = -1; // unknown | |
69 | m_timer = NULL; | |
70 | m_CanUseIfconfig = -1; // unknown | |
71 | m_BeaconHost = WXDIALUP_MANAGER_DEFAULT_BEACONHOST; | |
72 | m_BeaconPort = 80; | |
73 | } | |
74 | ||
75 | /** Could the dialup manager be initialized correctly? If this function | |
76 | returns FALSE, no other functions will work neither, so it's a good idea | |
77 | to call this function and check its result before calling any other | |
78 | wxDialUpManager methods. | |
79 | */ | |
80 | virtual bool IsOk() const | |
65391c8f | 81 | { return true; } |
275abf24 KB |
82 | |
83 | /** The simplest way to initiate a dial up: this function dials the given | |
84 | ISP (exact meaning of the parameter depends on the platform), returns | |
85 | TRUE on success or FALSE on failure and logs the appropriate error | |
86 | message in the latter case. | |
87 | @param nameOfISP optional paramater for dial program | |
88 | @param username unused | |
89 | @param password unused | |
90 | */ | |
91 | virtual bool Dial(const wxString& nameOfISP, | |
92 | const wxString& WXUNUSED(username), | |
93 | const wxString& WXUNUSED(password)); | |
94 | ||
95 | /// Hang up the currently active dial up connection. | |
96 | virtual bool HangUp(); | |
03647350 | 97 | |
275abf24 KB |
98 | // returns TRUE if the computer is connected to the network: under Windows, |
99 | // this just means that a RAS connection exists, under Unix we check that | |
100 | // the "well-known host" (as specified by SetWellKnownHost) is reachable | |
101 | virtual bool IsOnline() const | |
102 | { | |
103 | if( (! m_timer) // we are not polling, so test now: | |
104 | || m_IsOnline == -1 | |
105 | ) | |
106 | CheckStatus(); | |
107 | return m_IsOnline != 0; | |
108 | } | |
109 | ||
110 | // sometimes the built-in logic for determining the online status may fail, | |
111 | // so, in general, the user should be allowed to override it. This function | |
112 | // allows to forcefully set the online status - whatever our internal | |
113 | // algorithm may think about it. | |
65391c8f | 114 | virtual void SetOnlineStatus(bool isOnline = true) |
275abf24 KB |
115 | { m_IsOnline = isOnline; } |
116 | ||
117 | // set misc wxDialUpManager options | |
118 | // -------------------------------- | |
119 | ||
120 | // enable automatical checks for the connection status and sending of | |
121 | // wxEVT_DIALUP_CONNECTED/wxEVT_DIALUP_DISCONNECTED events. The interval | |
122 | // parameter is only for Unix where we do the check manually: under | |
123 | // Windows, the notification about the change of connection status is | |
124 | // instantenous. | |
125 | // | |
126 | // Returns FALSE if couldn't set up automatic check for online status. | |
127 | virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds); | |
128 | ||
129 | // disable automatic check for connection status change - notice that the | |
130 | // wxEVT_DIALUP_XXX events won't be sent any more neither. | |
131 | virtual void DisableAutoCheckOnlineStatus(); | |
132 | ||
133 | // under Unix, the value of well-known host is used to check whether we're | |
134 | // connected to the internet. It's unused under Windows, but this function | |
135 | // is always safe to call. The default value is www.yahoo.com. | |
136 | virtual void SetWellKnownHost(const wxString& hostname, | |
137 | int portno = 80); | |
138 | /** Sets the commands to start up the network and to hang up | |
139 | again. Used by the Unix implementations only. | |
140 | */ | |
141 | virtual void SetConnectCommand(const wxString &command, const wxString &hupcmd) | |
142 | { m_ConnectCommand = command; m_HangUpCommand = hupcmd; } | |
143 | ||
144 | private: | |
e9670814 | 145 | /// -1: don't know, 0 = no, 1 = yes |
275abf24 | 146 | int m_IsOnline; |
03647350 | 147 | |
275abf24 KB |
148 | /// Can we use ifconfig to list active devices? |
149 | int m_CanUseIfconfig; | |
150 | /// The path to ifconfig | |
151 | wxString m_IfconfigPath; | |
152 | ||
153 | /// beacon host: | |
154 | wxString m_BeaconHost; | |
155 | /// beacon host portnumber for connect: | |
156 | int m_BeaconPort; | |
157 | ||
158 | /// command to connect to network | |
159 | wxString m_ConnectCommand; | |
160 | /// command to hang up | |
161 | wxString m_HangUpCommand; | |
162 | /// name of ISP | |
163 | wxString m_ISPname; | |
164 | /// a timer for regular testing | |
165 | class AutoCheckTimer *m_timer; | |
166 | ||
167 | friend class AutoCheckTimer; | |
168 | /// determine status | |
169 | void CheckStatus(void) const; | |
170 | ||
171 | /// real status check | |
172 | void CheckStatusInternal(void); | |
173 | }; | |
174 | ||
175 | ||
176 | class AutoCheckTimer : public wxTimer | |
177 | { | |
178 | public: | |
179 | AutoCheckTimer(wxDialUpManagerImpl *dupman) | |
180 | { | |
181 | m_dupman = dupman; | |
65391c8f | 182 | m_started = false; |
275abf24 KB |
183 | } |
184 | ||
185 | virtual bool Start( int millisecs = -1 ) | |
65391c8f | 186 | { m_started = true; return wxTimer::Start(millisecs, false); } |
275abf24 KB |
187 | |
188 | virtual void Notify() | |
189 | { wxLogTrace("Checking dial up network status."); m_dupman->CheckStatus(); } | |
190 | ||
191 | virtual void Stop() | |
192 | { if ( m_started ) wxTimer::Stop(); } | |
193 | public: | |
194 | bool m_started; | |
195 | wxDialUpManagerImpl *m_dupman; | |
196 | }; | |
197 | ||
198 | bool | |
199 | wxDialUpManagerImpl::Dial(const wxString &isp, | |
200 | const wxString & WXUNUSED(username), | |
201 | const wxString & WXUNUSED(password)) | |
202 | { | |
203 | if(m_IsOnline == 1) | |
65391c8f | 204 | return false; |
275abf24 KB |
205 | m_IsOnline = -1; |
206 | m_ISPname = isp; | |
207 | wxString cmd; | |
208 | if(m_ConnectCommand.Find("%s")) | |
209 | cmd.Printf(m_ConnectCommand,m_ISPname.c_str()); | |
210 | else | |
211 | cmd = m_ConnectCommand; | |
212 | return wxExecute(cmd, /* sync */ TRUE) == 0; | |
213 | } | |
214 | ||
215 | bool | |
216 | wxDialUpManagerImpl::HangUp(void) | |
217 | { | |
218 | if(m_IsOnline == 0) | |
65391c8f | 219 | return false; |
275abf24 KB |
220 | m_IsOnline = -1; |
221 | wxString cmd; | |
222 | if(m_HangUpCommand.Find("%s")) | |
223 | cmd.Printf(m_HangUpCommand,m_ISPname.c_str()); | |
224 | else | |
225 | cmd = m_HangUpCommand; | |
226 | return wxExecute(cmd, /* sync */ TRUE) == 0; | |
227 | } | |
228 | ||
229 | ||
230 | bool | |
231 | wxDialUpManagerImpl::EnableAutoCheckOnlineStatus(size_t nSeconds) | |
232 | { | |
233 | wxASSERT(m_timer == NULL); | |
234 | m_timer = new AutoCheckTimer(this); | |
235 | bool rc = m_timer->Start(nSeconds*1000); | |
236 | if(! rc) | |
237 | { | |
5276b0a5 | 238 | wxDELETE(m_timer); |
275abf24 KB |
239 | } |
240 | return rc; | |
241 | } | |
242 | ||
243 | void | |
244 | wxDialUpManagerImpl::DisableAutoCheckOnlineStatus() | |
245 | { | |
246 | wxASSERT(m_timer != NULL); | |
247 | m_timer->Stop(); | |
5276b0a5 | 248 | wxDELETE(m_timer); |
275abf24 KB |
249 | } |
250 | ||
251 | ||
252 | void | |
253 | wxDialUpManagerImpl::SetWellKnownHost(const wxString& hostname, int portno) | |
254 | { | |
255 | /// does hostname contain a port number? | |
256 | wxString port = hostname.After(':'); | |
6636ef8d | 257 | if(port.empty()) |
275abf24 | 258 | { |
6636ef8d DS |
259 | m_BeaconHost = hostname; |
260 | m_BeaconPort = portno; | |
275abf24 KB |
261 | } |
262 | else | |
263 | { | |
6636ef8d DS |
264 | m_BeaconHost = hostname.Before(':'); |
265 | m_BeaconPort = atoi(port); | |
275abf24 KB |
266 | } |
267 | } | |
268 | ||
269 | ||
270 | void | |
271 | wxDialUpManagerImpl::CheckStatus(void) const | |
272 | { | |
273 | // This function calls the CheckStatusInternal() helper function | |
274 | // which is OS - specific and then sends the events. | |
275 | ||
276 | int oldIsOnline = m_IsOnline; | |
277 | ( /* non-const */ (wxDialUpManagerImpl *)this)->CheckStatusInternal(); | |
278 | ||
279 | // now send the events as appropriate: | |
280 | if(m_IsOnline != oldIsOnline) | |
281 | { | |
282 | if(m_IsOnline) | |
283 | ; // send ev | |
284 | else | |
285 | ; // send ev | |
286 | } | |
287 | } | |
288 | ||
289 | /* | |
290 | We have three methods that we can use: | |
291 | ||
292 | 1. test via /sbin/ifconfig and grep for "sl", "ppp", "pl" | |
293 | --> should be fast enough for regular polling | |
294 | 2. test if we can reach the well known beacon host | |
295 | --> too slow for polling | |
296 | 3. check /proc/net/dev on linux?? | |
297 | This method should be preferred, if possible. Need to do more | |
298 | testing. | |
03647350 | 299 | |
275abf24 KB |
300 | */ |
301 | ||
302 | void | |
303 | wxDialUpManagerImpl::CheckStatusInternal(void) | |
304 | { | |
305 | m_IsOnline = -1; | |
306 | ||
307 | // First time check for ifconfig location. We only use the variant | |
308 | // which does not take arguments, a la GNU. | |
309 | if(m_CanUseIfconfig == -1) // unknown | |
310 | { | |
311 | if(wxFileExists("/sbin/ifconfig")) | |
312 | m_IfconfigPath = "/sbin/ifconfig"; | |
313 | else if(wxFileExists("/usr/sbin/ifconfig")) | |
314 | m_IfconfigPath = "/usr/sbin/ifconfig"; | |
315 | } | |
316 | ||
317 | wxLogNull ln; // suppress all error messages | |
e9670814 | 318 | // Let's try the ifconfig method first, should be fastest: |
275abf24 KB |
319 | if(m_CanUseIfconfig != 0) // unknown or yes |
320 | { | |
6636ef8d | 321 | wxASSERT( !m_IfconfigPath.empty() ); |
03647350 | 322 | |
a51e601e | 323 | wxString tmpfile = wxFileName::CreateTempFileName("_wxdialuptest"); |
275abf24 KB |
324 | wxString cmd = "/bin/sh -c \'"; |
325 | cmd << m_IfconfigPath << " >" << tmpfile << '\''; | |
326 | /* I tried to add an option to wxExecute() to not close stdout, | |
327 | so we could let ifconfig write directly to the tmpfile, but | |
e9670814 | 328 | this does not work. That should be faster, as it doesn't call |
275abf24 KB |
329 | the shell first. I have no idea why. :-( (KB) */ |
330 | #if 0 | |
331 | // temporarily redirect stdout/stderr: | |
332 | int | |
333 | new_stdout = dup(STDOUT_FILENO), | |
334 | new_stderr = dup(STDERR_FILENO); | |
335 | close(STDOUT_FILENO); | |
336 | close(STDERR_FILENO); | |
337 | ||
338 | int | |
339 | // new stdout: | |
340 | output_fd = open(tmpfile, O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR), | |
341 | // new stderr: | |
342 | null_fd = open("/dev/null", O_CREAT, S_IRUSR|S_IWUSR); | |
343 | // verify well behaved unix behaviour: | |
344 | wxASSERT(output_fd == STDOUT_FILENO); | |
345 | wxASSERT(null_fd == STDERR_FILENO); | |
346 | int rc = wxExecute(m_IfconfigPath,TRUE /* sync */,NULL ,wxEXECUTE_DONT_CLOSE_FDS); | |
347 | close(null_fd); close(output_fd); | |
348 | // restore old stdout, stderr: | |
349 | int test; | |
350 | test = dup(new_stdout); close(new_stdout); wxASSERT(test == STDOUT_FILENO); | |
351 | test = dup(new_stderr); close(new_stderr); wxASSERT(test == STDERR_FILENO); | |
352 | if(rc == 0) | |
353 | #endif | |
354 | if(wxExecute(cmd,TRUE /* sync */) == 0) | |
355 | { | |
356 | m_CanUseIfconfig = 1; | |
357 | wxFile file; | |
358 | if( file.Open(tmpfile) ) | |
359 | { | |
360 | char *output = new char [file.Length()+1]; | |
361 | output[file.Length()] = '\0'; | |
362 | if(file.Read(output,file.Length()) == file.Length()) | |
363 | { | |
364 | if(strstr(output,"ppp") // ppp | |
365 | || strstr(output,"sl") // slip | |
366 | || strstr(output,"pl") // plip | |
367 | ) | |
368 | m_IsOnline = 1; | |
369 | else | |
370 | m_IsOnline = 0; | |
371 | } | |
372 | file.Close(); | |
373 | delete [] output; | |
374 | } | |
375 | // else m_IsOnline remains -1 as we don't know for sure | |
376 | } | |
377 | else // could not run ifconfig correctly | |
e9670814 | 378 | m_CanUseIfconfig = 0; // don't try again |
275abf24 KB |
379 | (void) wxRemoveFile(tmpfile); |
380 | if(m_IsOnline != -1) // we are done | |
381 | return; | |
382 | } | |
383 | ||
384 | // second method: try to connect to well known host: | |
385 | // This can be used under Win 9x, too! | |
386 | struct hostent *hp; | |
387 | struct sockaddr_in serv_addr; | |
03647350 | 388 | int sockfd; |
275abf24 KB |
389 | |
390 | m_IsOnline = 0; // assume false | |
391 | if((hp = gethostbyname(m_BeaconHost)) == NULL) | |
392 | return; // no DNS no net | |
03647350 VZ |
393 | |
394 | serv_addr.sin_family = hp->h_addrtype; | |
275abf24 | 395 | memcpy(&serv_addr.sin_addr,hp->h_addr, hp->h_length); |
03647350 VZ |
396 | serv_addr.sin_port = htons(m_BeaconPort); |
397 | if( ( sockfd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) | |
398 | { | |
275abf24 KB |
399 | // sys_error("cannot create socket for gw"); |
400 | return; | |
401 | } | |
402 | if( connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) | |
03647350 | 403 | { |
275abf24 KB |
404 | //sys_error("cannot connect to server"); |
405 | return; | |
406 | } | |
407 | //connected! | |
408 | close(sockfd); | |
409 | } | |
410 | ||
411 | ||
412 | /* static */ | |
413 | wxDialUpManager * | |
414 | wxDialUpManager::wxDialUpManager::Create(void) | |
415 | { | |
416 | return new wxDialUpManagerImpl; | |
417 | } | |
418 | ||
419 | #endif // wxUSE_DIALUP_MANAGER |