1 // -*- c++ -*- ///////////////////////////////////////////////////////////////
2 // Name: unix/dialup.cpp
3 // Purpose: Network related wxWindows classes and functions
4 // Author: Karsten Ballüder
8 // Copyright: (c) Karsten Ballüder
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
14 #if wxUSE_DIALUP_MANAGER
17 #pragma implementation "dialup.h"
24 #include "wx/string.h"
26 #include "wx/dialup.h"
28 #include "wx/filefn.h"
32 #include "wx/process.h"
41 #define __STRICT_ANSI__
42 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
47 // ----------------------------------------------------------------------------
48 // A class which groups functions dealing with connecting to the network from a
49 // workstation using dial-up access to the net. There is at most one instance
50 // of this class in the program accessed via GetDialUpManager().
51 // ----------------------------------------------------------------------------
55 * 1. more configurability for Unix: i.e. how to initiate the connection, how
56 * to check for online status, &c.
57 * 2. add a "long Dial(long connectionId = -1)" function which asks the user
58 * about which connection to dial (this may be done using native dialogs
59 * under NT, need generic dialogs for all others) and returns the identifier
60 * of the selected connection (it's opaque to the application) - it may be
61 * reused later to dial the same connection later (or use strings instead of
63 * 3. add an async version of dialing functions which notify the caller about
64 * the progress (or may be even start another thread to monitor it)
65 * 4. the static creation/accessor functions are not MT-safe - but is this
66 * really crucial? I think we may suppose they're always called from the
70 class WXDLLEXPORT wxDialUpManagerImpl
: public wxDialUpManager
73 wxDialUpManagerImpl();
74 ~wxDialUpManagerImpl();
76 /** Could the dialup manager be initialized correctly? If this function
77 returns FALSE, no other functions will work neither, so it's a good idea
78 to call this function and check its result before calling any other
79 wxDialUpManager methods.
81 virtual bool IsOk() const
84 /** The simplest way to initiate a dial up: this function dials the given
85 ISP (exact meaning of the parameter depends on the platform), returns
86 TRUE on success or FALSE on failure and logs the appropriate error
87 message in the latter case.
88 @param nameOfISP optional paramater for dial program
89 @param username unused
90 @param password unused
92 virtual bool Dial(const wxString
& nameOfISP
,
93 const wxString
& WXUNUSED(username
),
94 const wxString
& WXUNUSED(password
),
97 /// Hang up the currently active dial up connection.
98 virtual bool HangUp();
100 // returns TRUE if the computer is connected to the network: under Windows,
101 // this just means that a RAS connection exists, under Unix we check that
102 // the "well-known host" (as specified by SetWellKnownHost) is reachable
103 virtual bool IsOnline() const
105 if( (! m_timer
) // we are not polling, so test now:
109 return m_IsOnline
!= 0;
112 /// returns TRUE if (async) dialing is in progress
113 inline virtual bool IsDialling() const
114 { return m_DialProcess
!= NULL
; }
116 // cancel dialing the number initiated with Dial(async = TRUE)
117 // NB: this won't result in DISCONNECTED event being sent
118 virtual bool CancelDialing();
120 // sometimes the built-in logic for determining the online status may fail,
121 // so, in general, the user should be allowed to override it. This function
122 // allows to forcefully set the online status - whatever our internal
123 // algorithm may think about it.
124 virtual void SetOnlineStatus(bool isOnline
= TRUE
)
125 { m_IsOnline
= isOnline
; }
127 // set misc wxDialUpManager options
128 // --------------------------------
130 // enable automatical checks for the connection status and sending of
131 // wxEVT_DIALUP_CONNECTED/wxEVT_DIALUP_DISCONNECTED events. The interval
132 // parameter is only for Unix where we do the check manually: under
133 // Windows, the notification about the change of connection status is
136 // Returns FALSE if couldn't set up automatic check for online status.
137 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
);
139 // disable automatic check for connection status change - notice that the
140 // wxEVT_DIALUP_XXX events won't be sent any more neither.
141 virtual void DisableAutoCheckOnlineStatus();
143 // under Unix, the value of well-known host is used to check whether we're
144 // connected to the internet. It's unused under Windows, but this function
145 // is always safe to call. The default value is www.yahoo.com.
146 virtual void SetWellKnownHost(const wxString
& hostname
,
148 /** Sets the commands to start up the network and to hang up
149 again. Used by the Unix implementations only.
151 virtual void SetConnectCommand(const wxString
&command
, const wxString
&hupcmd
)
152 { m_ConnectCommand
= command
; m_HangUpCommand
= hupcmd
; }
155 /// -1: don´t know, 0 = no, 1 = yes
158 /// Can we use ifconfig to list active devices?
159 int m_CanUseIfconfig
;
160 /// The path to ifconfig
161 wxString m_IfconfigPath
;
164 wxString m_BeaconHost
;
165 /// beacon host portnumber for connect:
168 /// command to connect to network
169 wxString m_ConnectCommand
;
170 /// command to hang up
171 wxString m_HangUpCommand
;
174 /// a timer for regular testing
175 class AutoCheckTimer
*m_timer
;
176 friend class AutoCheckTimer
;
178 /// a wxProcess for dialling in background
179 class wxDialProcess
*m_DialProcess
;
180 /// pid of dial process
182 friend class wxDialProcess
;
185 void CheckStatus(bool fromAsync
= FALSE
) const;
187 /// real status check
188 void CheckStatusInternal(void);
192 class AutoCheckTimer
: public wxTimer
195 AutoCheckTimer(wxDialUpManagerImpl
*dupman
)
201 virtual bool Start( int millisecs
= -1 )
202 { m_started
= TRUE
; return wxTimer::Start(millisecs
, FALSE
); }
204 virtual void Notify()
205 { wxLogTrace("Checking dial up network status."); m_dupman
->CheckStatus(); }
208 { if ( m_started
) wxTimer::Stop(); }
211 wxDialUpManagerImpl
*m_dupman
;
214 class wxDialProcess
: public wxProcess
217 wxDialProcess(wxDialUpManagerImpl
*dupman
)
221 void OnTerminate(int WXUNUSED(pid
), int WXUNUSED(status
)) const
223 m_DupMan
->m_DialProcess
= NULL
;
224 m_DupMan
->CheckStatus(TRUE
);
227 wxDialUpManagerImpl
*m_DupMan
;
231 wxDialUpManagerImpl::wxDialUpManagerImpl()
233 m_IsOnline
= -1; // unknown
234 m_DialProcess
= NULL
;
236 m_CanUseIfconfig
= -1; // unknown
237 m_BeaconHost
= WXDIALUP_MANAGER_DEFAULT_BEACONHOST
;
241 wxDialUpManagerImpl::~wxDialUpManagerImpl()
243 if(m_timer
) delete m_timer
;
244 if(m_DialProcess
) m_DialProcess
->Detach();
248 wxDialUpManagerImpl::Dial(const wxString
&isp
,
249 const wxString
& WXUNUSED(username
),
250 const wxString
& WXUNUSED(password
),
258 if(m_ConnectCommand
.Find("%s"))
259 cmd
.Printf(m_ConnectCommand
,m_ISPname
.c_str());
261 cmd
= m_ConnectCommand
;
265 m_DialProcess
= new wxDialProcess(this);
266 m_DialPId
= wxExecute(cmd
, FALSE
, m_DialProcess
);
269 delete m_DialProcess
;
270 m_DialProcess
= NULL
;
277 return wxExecute(cmd
, /* sync */ TRUE
) == 0;
281 wxDialUpManagerImpl::HangUp(void)
287 wxLogError(_("Already dialling ISP."));
292 if(m_HangUpCommand
.Find("%s"))
293 cmd
.Printf(m_HangUpCommand
,m_ISPname
.c_str(), m_DialProcess
);
295 cmd
= m_HangUpCommand
;
296 return wxExecute(cmd
, /* sync */ TRUE
) == 0;
301 wxDialUpManagerImpl::CancelDialing()
305 return kill(m_DialPId
, SIGTERM
) > 0;
309 wxDialUpManagerImpl::EnableAutoCheckOnlineStatus(size_t nSeconds
)
311 wxASSERT(m_timer
== NULL
);
312 m_timer
= new AutoCheckTimer(this);
313 bool rc
= m_timer
->Start(nSeconds
*1000);
323 wxDialUpManagerImpl::DisableAutoCheckOnlineStatus()
325 wxASSERT(m_timer
!= NULL
);
333 wxDialUpManagerImpl::SetWellKnownHost(const wxString
& hostname
, int portno
)
335 /// does hostname contain a port number?
336 wxString port
= hostname
.After(':');
339 m_BeaconHost
= hostname
.Before(':');
340 m_BeaconPort
= atoi(port
);
344 m_BeaconHost
= hostname
;
345 m_BeaconPort
= portno
;
351 wxDialUpManagerImpl::CheckStatus(bool fromAsync
) const
353 // This function calls the CheckStatusInternal() helper function
354 // which is OS - specific and then sends the events.
356 int oldIsOnline
= m_IsOnline
;
357 ( /* non-const */ (wxDialUpManagerImpl
*)this)->CheckStatusInternal();
359 // now send the events as appropriate:
360 if(m_IsOnline
!= oldIsOnline
&& oldIsOnline
!= -1)
362 wxDialUpEvent
event(m_IsOnline
, ! fromAsync
);
363 (void)wxTheApp
->ProcessEvent(event
);
368 We have three methods that we can use:
370 1. test via /sbin/ifconfig and grep for "sl", "ppp", "pl"
371 --> should be fast enough for regular polling
372 2. test if we can reach the well known beacon host
373 --> too slow for polling
374 3. check /proc/net/dev on linux??
375 This method should be preferred, if possible. Need to do more
381 wxDialUpManagerImpl::CheckStatusInternal(void)
385 // First time check for ifconfig location. We only use the variant
386 // which does not take arguments, a la GNU.
387 if(m_CanUseIfconfig
== -1) // unknown
389 if(wxFileExists("/sbin/ifconfig"))
390 m_IfconfigPath
= "/sbin/ifconfig";
391 else if(wxFileExists("/usr/sbin/ifconfig"))
392 m_IfconfigPath
= "/usr/sbin/ifconfig";
395 wxLogNull ln
; // suppress all error messages
396 // Let´s try the ifconfig method first, should be fastest:
397 if(m_CanUseIfconfig
!= 0) // unknown or yes
399 wxASSERT(m_IfconfigPath
.length());
401 wxString tmpfile
= wxGetTempFileName("_wxdialuptest");
402 wxString cmd
= "/bin/sh -c \'";
403 cmd
<< m_IfconfigPath
<< " >" << tmpfile
<< '\'';
404 /* I tried to add an option to wxExecute() to not close stdout,
405 so we could let ifconfig write directly to the tmpfile, but
406 this does not work. That should be faster, as it doesn´t call
407 the shell first. I have no idea why. :-( (KB) */
409 // temporarily redirect stdout/stderr:
411 new_stdout
= dup(STDOUT_FILENO
),
412 new_stderr
= dup(STDERR_FILENO
);
413 close(STDOUT_FILENO
);
414 close(STDERR_FILENO
);
418 output_fd
= open(tmpfile
, O_CREAT
|O_TRUNC
, S_IRUSR
|S_IWUSR
),
420 null_fd
= open("/dev/null", O_CREAT
, S_IRUSR
|S_IWUSR
);
421 // verify well behaved unix behaviour:
422 wxASSERT(output_fd
== STDOUT_FILENO
);
423 wxASSERT(null_fd
== STDERR_FILENO
);
424 int rc
= wxExecute(m_IfconfigPath
,TRUE
/* sync */,NULL
,wxEXECUTE_DONT_CLOSE_FDS
);
425 close(null_fd
); close(output_fd
);
426 // restore old stdout, stderr:
428 test
= dup(new_stdout
); close(new_stdout
); wxASSERT(test
== STDOUT_FILENO
);
429 test
= dup(new_stderr
); close(new_stderr
); wxASSERT(test
== STDERR_FILENO
);
432 if(wxExecute(cmd
,TRUE
/* sync */) == 0)
434 m_CanUseIfconfig
= 1;
436 if( file
.Open(tmpfile
) )
438 char *output
= new char [file
.Length()+1];
439 output
[file
.Length()] = '\0';
440 if(file
.Read(output
,file
.Length()) == file
.Length())
442 if(strstr(output
,"ppp") // ppp
443 || strstr(output
,"sl") // slip
444 || strstr(output
,"pl") // plip
453 // else m_IsOnline remains -1 as we don't know for sure
455 else // could not run ifconfig correctly
456 m_CanUseIfconfig
= 0; // don´t try again
457 (void) wxRemoveFile(tmpfile
);
458 if(m_IsOnline
!= -1) // we are done
462 // second method: try to connect to well known host:
463 // This can be used under Win 9x, too!
465 struct sockaddr_in serv_addr
;
468 m_IsOnline
= 0; // assume false
469 if((hp
= gethostbyname(m_BeaconHost
)) == NULL
)
470 return; // no DNS no net
472 serv_addr
.sin_family
= hp
->h_addrtype
;
473 memcpy(&serv_addr
.sin_addr
,hp
->h_addr
, hp
->h_length
);
474 serv_addr
.sin_port
= htons(m_BeaconPort
);
475 if( ( sockfd
= socket(hp
->h_addrtype
, SOCK_STREAM
, 0)) < 0)
477 // sys_error("cannot create socket for gw");
483 if(sendto(sockfd
, "hello", strlen("hello"), /* flags */ 0, &serv_addr
,
484 sizeof(serv_addr
)) == -1)
488 if( connect(sockfd
, (struct sockaddr
*) &serv_addr
, sizeof(serv_addr
)) < 0)
490 //sys_error("cannot connect to server");
501 wxDialUpManager::Create(void)
503 return new wxDialUpManagerImpl
;
506 #endif // wxUSE_DIALUP_MANAGER