1 // -*- c++ -*- /////////////////////////////////////////////////////////////// 
   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 
  20 #include "wx/string.h" 
  24 #include "wx/filefn.h" 
  33 #define __STRICT_ANSI__ 
  34 #include <sys/socket.h> 
  35 #include <sys/types.h> 
  38 #include <netinet/in.h> 
  39 #include <arpa/inet.h> 
  41 // ---------------------------------------------------------------------------- 
  42 // A class which groups functions dealing with connecting to the network from a 
  43 // workstation using dial-up access to the net. There is at most one instance 
  44 // of this class in the program accessed via GetDialUpManager(). 
  45 // ---------------------------------------------------------------------------- 
  49  * 1. more configurability for Unix: i.e. how to initiate the connection, how 
  50  *    to check for online status, &c. 
  51  * 2. add a "long Dial(long connectionId = -1)" function which asks the user 
  52  *    about which connection to dial (this may be done using native dialogs 
  53  *    under NT, need generic dialogs for all others) and returns the identifier 
  54  *    of the selected connection (it's opaque to the application) - it may be 
  55  *    reused later to dial the same connection later (or use strings instead of 
  57  * 3. add an async version of dialing functions which notify the caller about 
  58  *    the progress (or may be even start another thread to monitor it) 
  59  * 4. the static creation/accessor functions are not MT-safe - but is this 
  60  *    really crucial? I think we may suppose they're always called from the 
  64 class WXDLLEXPORT wxDialUpManagerImpl 
: public wxDialUpManager
 
  69          m_IsOnline 
= -1; // unknown 
  71          m_CanUseIfconfig 
= -1; // unknown 
  72          m_BeaconHost 
= WXDIALUP_MANAGER_DEFAULT_BEACONHOST
; 
  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
)); 
  96    /// Hang up the currently active dial up connection. 
  97    virtual bool HangUp(); 
  99    // returns TRUE if the computer is connected to the network: under Windows, 
 100    // this just means that a RAS connection exists, under Unix we check that 
 101    // the "well-known host" (as specified by SetWellKnownHost) is reachable 
 102    virtual bool IsOnline() const 
 104          if( (! m_timer
) // we are not polling, so test now: 
 108          return m_IsOnline 
!= 0; 
 111    // sometimes the built-in logic for determining the online status may fail, 
 112    // so, in general, the user should be allowed to override it. This function 
 113    // allows to forcefully set the online status - whatever our internal 
 114    // algorithm may think about it. 
 115    virtual void SetOnlineStatus(bool isOnline 
= TRUE
) 
 116       { m_IsOnline 
= isOnline
; } 
 118    // set misc wxDialUpManager options 
 119    // -------------------------------- 
 121    // enable automatical checks for the connection status and sending of 
 122    // wxEVT_DIALUP_CONNECTED/wxEVT_DIALUP_DISCONNECTED events. The interval 
 123    // parameter is only for Unix where we do the check manually: under 
 124    // Windows, the notification about the change of connection status is 
 127    // Returns FALSE if couldn't set up automatic check for online status. 
 128    virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
); 
 130    // disable automatic check for connection status change - notice that the 
 131    // wxEVT_DIALUP_XXX events won't be sent any more neither. 
 132    virtual void DisableAutoCheckOnlineStatus(); 
 134    // under Unix, the value of well-known host is used to check whether we're 
 135    // connected to the internet. It's unused under Windows, but this function 
 136    // is always safe to call. The default value is www.yahoo.com. 
 137    virtual void SetWellKnownHost(const wxString
& hostname
, 
 139    /** Sets the commands to start up the network and to hang up 
 140        again. Used by the Unix implementations only. 
 142    virtual void SetConnectCommand(const wxString 
&command
, const wxString 
&hupcmd
) 
 143       { m_ConnectCommand 
= command
; m_HangUpCommand 
= hupcmd
; } 
 146    /// -1: don´t know, 0 = no, 1 = yes 
 149    ///  Can we use ifconfig to list active devices? 
 150    int m_CanUseIfconfig
; 
 151    /// The path to ifconfig 
 152    wxString m_IfconfigPath
; 
 155    wxString m_BeaconHost
; 
 156    /// beacon host portnumber for connect: 
 159    /// command to connect to network 
 160    wxString m_ConnectCommand
; 
 161    /// command to hang up 
 162    wxString m_HangUpCommand
; 
 165    /// a timer for regular testing 
 166    class AutoCheckTimer 
*m_timer
; 
 168    friend class AutoCheckTimer
; 
 170    void CheckStatus(void) const; 
 172    /// real status check 
 173    void CheckStatusInternal(void); 
 177 class AutoCheckTimer 
: public wxTimer
 
 180    AutoCheckTimer(wxDialUpManagerImpl 
*dupman
) 
 186    virtual bool Start( int millisecs 
= -1 ) 
 187       { m_started 
= TRUE
; return wxTimer::Start(millisecs
, FALSE
); } 
 189    virtual void Notify() 
 190       { wxLogTrace("Checking dial up network status."); m_dupman
->CheckStatus(); } 
 193       { if ( m_started 
) wxTimer::Stop(); } 
 196    wxDialUpManagerImpl 
*m_dupman
; 
 200 wxDialUpManagerImpl::Dial(const wxString 
&isp
, 
 201                           const wxString 
& WXUNUSED(username
), 
 202                           const wxString 
& WXUNUSED(password
)) 
 209    if(m_ConnectCommand
.Find("%s")) 
 210       cmd
.Printf(m_ConnectCommand
,m_ISPname
.c_str()); 
 212       cmd 
= m_ConnectCommand
; 
 213    return wxExecute(cmd
, /* sync */ TRUE
) == 0; 
 217 wxDialUpManagerImpl::HangUp(void) 
 223    if(m_HangUpCommand
.Find("%s")) 
 224       cmd
.Printf(m_HangUpCommand
,m_ISPname
.c_str()); 
 226       cmd 
= m_HangUpCommand
; 
 227    return wxExecute(cmd
, /* sync */ TRUE
) == 0; 
 232 wxDialUpManagerImpl::EnableAutoCheckOnlineStatus(size_t nSeconds
) 
 234    wxASSERT(m_timer 
== NULL
); 
 235    m_timer 
= new AutoCheckTimer(this); 
 236    bool rc 
= m_timer
->Start(nSeconds
*1000); 
 246 wxDialUpManagerImpl::DisableAutoCheckOnlineStatus() 
 248    wxASSERT(m_timer 
!= NULL
); 
 256 wxDialUpManagerImpl::SetWellKnownHost(const wxString
& hostname
, int portno
) 
 258    /// does hostname contain a port number? 
 259    wxString port 
= hostname
.After(':'); 
 262       m_BeaconHost 
= hostname
.Before(':'); 
 263       m_BeaconPort 
= atoi(port
); 
 267       m_BeaconHost 
= hostname
; 
 268       m_BeaconPort 
= portno
; 
 274 wxDialUpManagerImpl::CheckStatus(void) const 
 276    // This function calls the CheckStatusInternal() helper function 
 277    // which is OS - specific and then sends the events. 
 279    int oldIsOnline 
= m_IsOnline
; 
 280    ( /* non-const */ (wxDialUpManagerImpl 
*)this)->CheckStatusInternal(); 
 282    // now send the events as appropriate: 
 283    if(m_IsOnline 
!= oldIsOnline
) 
 293   We have three methods that we can use: 
 295   1. test via /sbin/ifconfig and grep for "sl", "ppp", "pl" 
 296      --> should be fast enough for regular polling 
 297   2. test if we can reach the well known beacon host 
 298      --> too slow for polling 
 299   3. check /proc/net/dev on linux?? 
 300      This method should be preferred, if possible. Need to do more 
 306 wxDialUpManagerImpl::CheckStatusInternal(void) 
 310    // First time check for ifconfig location. We only use the variant 
 311    // which does not take arguments, a la GNU. 
 312    if(m_CanUseIfconfig 
== -1) // unknown 
 314       if(wxFileExists("/sbin/ifconfig")) 
 315          m_IfconfigPath 
= "/sbin/ifconfig"; 
 316       else if(wxFileExists("/usr/sbin/ifconfig")) 
 317          m_IfconfigPath 
= "/usr/sbin/ifconfig"; 
 320    wxLogNull ln
; // suppress all error messages 
 321    // Let´s try the ifconfig method first, should be fastest: 
 322    if(m_CanUseIfconfig 
!= 0) // unknown or yes 
 324       wxASSERT(m_IfconfigPath
.length()); 
 326       wxString tmpfile 
= wxGetTempFileName("_wxdialuptest"); 
 327       wxString cmd 
= "/bin/sh -c \'"; 
 328       cmd 
<< m_IfconfigPath 
<< " >" << tmpfile 
<<  '\''; 
 329       /* I tried to add an option to wxExecute() to not close stdout, 
 330          so we could let ifconfig write directly to the tmpfile, but 
 331          this does not work. That should be faster, as it doesn´t call  
 332          the shell first. I have no idea why. :-(  (KB) */ 
 334       // temporarily redirect stdout/stderr: 
 336          new_stdout 
= dup(STDOUT_FILENO
), 
 337          new_stderr 
= dup(STDERR_FILENO
); 
 338       close(STDOUT_FILENO
); 
 339       close(STDERR_FILENO
); 
 343          output_fd 
= open(tmpfile
, O_CREAT
|O_TRUNC
, S_IRUSR
|S_IWUSR
), 
 345          null_fd 
= open("/dev/null", O_CREAT
, S_IRUSR
|S_IWUSR
); 
 346       // verify well behaved unix behaviour: 
 347       wxASSERT(output_fd 
== STDOUT_FILENO
); 
 348       wxASSERT(null_fd 
== STDERR_FILENO
); 
 349       int rc 
= wxExecute(m_IfconfigPath
,TRUE 
/* sync */,NULL 
,wxEXECUTE_DONT_CLOSE_FDS
); 
 350       close(null_fd
); close(output_fd
); 
 351       // restore old stdout, stderr: 
 353       test 
= dup(new_stdout
); close(new_stdout
); wxASSERT(test 
== STDOUT_FILENO
); 
 354       test 
= dup(new_stderr
); close(new_stderr
); wxASSERT(test 
== STDERR_FILENO
); 
 357       if(wxExecute(cmd
,TRUE 
/* sync */) == 0) 
 359          m_CanUseIfconfig 
= 1; 
 361          if( file
.Open(tmpfile
) ) 
 363             char *output 
= new char [file
.Length()+1]; 
 364             output
[file
.Length()] = '\0'; 
 365             if(file
.Read(output
,file
.Length()) == file
.Length()) 
 367                if(strstr(output
,"ppp")   // ppp 
 368                   || strstr(output
,"sl") // slip 
 369                   || strstr(output
,"pl") // plip 
 378          // else m_IsOnline remains -1 as we don't know for sure 
 380       else // could not run ifconfig correctly 
 381          m_CanUseIfconfig 
= 0; // don´t try again 
 382       (void) wxRemoveFile(tmpfile
); 
 383       if(m_IsOnline 
!= -1) // we are done 
 387    // second method: try to connect to well known host: 
 388    // This can be used under Win 9x, too! 
 390    struct sockaddr_in  serv_addr
; 
 393    m_IsOnline 
= 0; // assume false 
 394    if((hp 
= gethostbyname(m_BeaconHost
)) == NULL
) 
 395       return; // no DNS no net 
 397    serv_addr
.sin_family         
= hp
->h_addrtype
; 
 398    memcpy(&serv_addr
.sin_addr
,hp
->h_addr
, hp
->h_length
); 
 399    serv_addr
.sin_port           
= htons(m_BeaconPort
); 
 400    if( ( sockfd 
= socket(hp
->h_addrtype
, SOCK_STREAM
, 0)) < 0)  
 402       //  sys_error("cannot create socket for gw"); 
 405    if( connect(sockfd
, (struct sockaddr 
*) &serv_addr
, sizeof(serv_addr
)) < 0) 
 407       //sys_error("cannot connect to server"); 
 417 wxDialUpManager::wxDialUpManager::Create(void) 
 419    return new wxDialUpManagerImpl
; 
 422 #endif // wxUSE_DIALUP_MANAGER