PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/wxWidgets-2.9.1/src/unix/net.cpp

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