Uncommented beaudio code
[pwlib.git] / src / ptlib / unix / remconn.cxx
blob76fbf57cf6abdf71ae829f4948b7de36d3a6ebbe
1 /*
2 * remconn.CXX
4 * Remote network connection (ppp) class implementation
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.20 2004/02/22 03:36:41 ykiryanov
31 * Added inclusion of signal.h on BeOS to define SIGINT
33 * Revision 1.19 2003/12/02 10:46:15 csoutheren
34 * Added patch for Solaris, thanks to Michal Zygmuntowicz
36 * Revision 1.18 2002/10/10 04:43:44 robertj
37 * VxWorks port, thanks Martijn Roest
39 * Revision 1.17 1998/11/30 21:51:49 robertj
40 * New directory structure.
42 * Revision 1.16 1998/09/24 04:12:15 robertj
43 * Added open software license.
47 #pragma implementation "remconn.h"
49 #include <ptlib.h>
50 #include <ptlib/pipechan.h>
51 #include <ptlib/remconn.h>
53 #include <stdio.h>
54 #include <sys/ioctl.h>
55 #include <sys/socket.h>
56 #ifdef P_VXWORKS
57 #include <socklib.h>
58 #endif // P_VXWORKS
60 #ifdef P_SOLARIS
61 #include <signal.h>
62 #endif
64 #ifdef __BEOS__
65 #include <signal.h>
66 #endif
68 #include "uerror.h"
70 static const PString RasStr = "ras";
71 static const PString NumberStr = "Number";
72 static const PCaselessString UsernameStr = "$USERID";
73 static const PCaselessString PasswordStr = "$PASSWORD";
74 static const PString AddressStr = "Address";
75 static const PString NameServerStr = "NameServer";
77 static const PString OptionsStr = "Options";
79 static const PString DeviceStr = "Device";
80 static const PString DefaultDevice = "ppp0";
82 static const PString PPPDStr = "PPPD";
83 static const PString DefaultPPPD = "pppd";
85 static const PString ChatStr = "Chat";
86 static const PString DefaultChat = "chat";
88 static const PString PortStr = "Port";
89 static const PString DefaultPort = "/dev/modem";
91 static const PString DialPrefixStr = "DialPrefix";
92 static const PString DefaultDialPrefix = "ATDT";
94 static const PString LoginStr = "Login";
95 static const PString DefaultLogin = "'' sername: $USERID assword: $PASSWORD";
97 static const PString TimeoutStr = "TimeoutStr";
98 static const PString DefaultTimeout = "90";
100 static const PString PPPDOptsStr = "PPPDOpts";
101 static const PString PPPDOpts = "-detach";
102 static const PString DefaultPPPDOpts = "crtscts modem defaultroute lock";
104 static const PString BaudRateStr = "BaudRate";
105 static const PString DefaultBaudRate = "57600";
107 static const PString ErrorsStr = "Errors";
108 static const PString DefaultErrors = "ABORT 'NO CARRIER' ABORT BUSY ABORT 'NO DIALTONE'";
110 static const PString InitStr = "Init";
111 static const PString DefaultInit = "'' ATE1Q0Z OK";
114 static const PXErrorStruct ErrorTable[] =
116 // Remote connection errors
117 { 1000, "Attempt to open remote connection with empty system name" },
118 { 1001, "Attempt to open connection to unknown remote system"},
119 { 1002, "pppd could not connect to remote system"},
122 static int PPPDeviceStatus(const char * devName);
124 PRemoteConnection::PRemoteConnection()
126 Construct();
129 PRemoteConnection::PRemoteConnection(const PString & name)
130 : remoteName(name)
132 Construct();
135 PRemoteConnection::~PRemoteConnection()
137 Close();
141 BOOL PRemoteConnection::Open(const PString & name, BOOL existing)
143 return Open(name, "", "", existing);
146 BOOL PRemoteConnection::Open(const PString & name,
147 const PString & user,
148 const PString & pword,
149 BOOL existing)
151 userName = user;
152 password = pword;
154 // cannot open remote connection with an empty name
155 if (name.IsEmpty()) {
156 status = NoNameOrNumber;
157 PProcess::PXShowSystemWarning(1000, ErrorTable[0].str);
158 return FALSE;
161 // cannot open remote connection not in config file
162 PConfig config(0, RasStr);
163 PString phoneNumber;
164 if ((phoneNumber = config.GetString(name, NumberStr, "")).IsEmpty()) {
165 status = NoNameOrNumber;
166 PProcess::PXShowSystemWarning(1001, ErrorTable[1].str);
167 return FALSE;
170 // if there is a connection active, check to see if it has the same name
171 if (pipeChannel != NULL &&
172 pipeChannel->IsRunning() &&
173 name == remoteName &&
174 PPPDeviceStatus(deviceStr) > 0) {
175 osError = errno;
176 status = Connected;
177 return TRUE;
179 osError = errno;
181 if (existing)
182 return FALSE;
184 Close();
186 // name = name of configuration
187 // sectionName = name of config section
188 remoteName = name;
190 ///////////////////////////////////////////
192 // get global options
194 config.SetDefaultSection(OptionsStr);
195 deviceStr = config.GetString(DeviceStr, DefaultDevice);
196 PString pppdStr = config.GetString(PPPDStr, DefaultPPPD);
197 PString chatStr = config.GetString(ChatStr, DefaultChat);
198 PString baudRate = config.GetString(BaudRateStr, DefaultBaudRate);
199 PString chatErrs = config.GetString(ErrorsStr, DefaultErrors);
200 PString modemInit = config.GetString(InitStr, DefaultInit);
201 PString dialPrefix = config.GetString(DialPrefixStr, DefaultDialPrefix);
202 PString pppdOpts = config.GetString(PPPDOptsStr, DefaultPPPDOpts);
204 ///////////////////////////////////////////
206 // get remote system parameters
208 config.SetDefaultSection(remoteName);
209 PString portName = config.GetString(PortStr,
210 config.GetString(OptionsStr, PortStr, DefaultPort));
211 PString loginStr = config.GetString(LoginStr, DefaultLogin);
212 PString timeoutStr = config.GetString(TimeoutStr, DefaultTimeout);
213 PINDEX timeout = timeoutStr.AsInteger();
214 PString addressStr = config.GetString(AddressStr, "");
215 PString nameServerStr = config.GetString(NameServerStr, "");
218 ///////////////////////////////////////////
220 // start constructing the command argument array
222 PStringArray argArray;
223 PINDEX argCount = 0;
224 argArray[argCount++] = portName;
225 argArray[argCount++] = baudRate;
227 PStringArray tokens = PPPDOpts.Tokenise(' ');
228 PINDEX i;
229 for (i = 0; i < tokens.GetSize(); i++)
230 argArray[argCount++] = tokens[i];
232 tokens = pppdOpts.Tokenise(' ');
233 for (i = 0; i < tokens.GetSize(); i++)
234 argArray[argCount++] = tokens[i];
236 if (!nameServerStr.IsEmpty()) {
237 argArray[argCount++] = "ipparam";
238 argArray[argCount++] = nameServerStr;
241 ///////////////////////////////////////////
243 // replace metastrings in the login string
245 loginStr.Replace(UsernameStr, user);
246 loginStr.Replace(PasswordStr, pword);
248 ///////////////////////////////////////////
250 // setup the chat command
252 PString chatCmd = chatErrs & modemInit & dialPrefix + phoneNumber & loginStr;
253 if (!chatCmd.IsEmpty()) {
254 argArray[argCount++] = "connect";
255 argArray[argCount++] = chatStr & "-t" + timeoutStr & chatCmd;
258 if (!addressStr)
259 argArray[argCount++] = addressStr + ":";
261 ///////////////////////////////////////////
263 // instigate a dial using pppd
265 pipeChannel = PNEW PPipeChannel(pppdStr, argArray);
266 osError = errno;
268 ///////////////////////////////////////////
270 // wait until the dial succeeds, or times out
272 PTimer timer(timeout*1000);
273 for (;;) {
274 if (pipeChannel == NULL || !pipeChannel->IsRunning())
275 break;
277 if (PPPDeviceStatus(deviceStr) > 0) {
278 osError = errno;
279 return TRUE;
282 if (!timer.IsRunning())
283 break;
285 PThread::Current()->Sleep(1000);
287 osError = errno;
289 ///////////////////////////////////////////
291 // dial failed
293 Close();
295 return FALSE;
299 PObject::Comparison PRemoteConnection::Compare(const PObject & obj) const
301 return remoteName.Compare(((const PRemoteConnection &)obj).remoteName);
305 PINDEX PRemoteConnection::HashFunction() const
307 return remoteName.HashFunction();
311 void PRemoteConnection::Construct()
313 pipeChannel = NULL;
314 status = Idle;
315 osError = 0;
319 BOOL PRemoteConnection::Open(BOOL existing)
321 return Open(remoteName, existing);
325 void PRemoteConnection::Close()
327 if (pipeChannel != NULL) {
329 // give pppd a chance to clean up
330 pipeChannel->Kill(SIGINT);
332 PTimer timer(10*1000);
333 for (;;) {
334 if (!pipeChannel->IsRunning() ||
335 (PPPDeviceStatus(deviceStr) <= 0) ||
336 !timer.IsRunning())
337 break;
338 PThread::Current()->Sleep(1000);
341 // kill the connection for real
342 delete pipeChannel;
343 pipeChannel = NULL;
347 PRemoteConnection::Status PRemoteConnection::GetStatus() const
349 if (pipeChannel != NULL &&
350 pipeChannel->IsRunning() &&
351 PPPDeviceStatus(deviceStr) > 0)
352 return Connected;
354 return Idle;
357 PStringArray PRemoteConnection::GetAvailableNames()
359 PStringArray names;
361 // get the list of remote system names from the system config file
362 PConfig config(0, RasStr);
364 // remotes have section names of the form "Remote-x" where X is some
365 // unique identifier, usually a number or the system name
366 PStringList sections = config.GetSections();
367 for (PINDEX i = 0; i < sections.GetSize(); i++) {
368 PString sectionName = sections[i];
369 if (sectionName != OptionsStr)
370 names[names.GetSize()] = sectionName;
373 return names;
377 // <0 = does not exist
378 // 0 = exists, but is down
379 // >0 = exists, is up
381 static int PPPDeviceStatus(const char * devName)
383 #if defined(HAS_IFREQ)
384 int skfd;
385 struct ifreq ifr;
387 // Create a channel to the NET kernel.
388 if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0)
389 return -1;
391 // attempt to get the status of the ppp connection
392 int stat;
393 strcpy(ifr.ifr_name, devName);
394 if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
395 stat = -1;
396 else
397 stat = (ifr.ifr_flags & IFF_UP) ? 1 : 0;
399 // attempt to get the status of the ppp connection
400 close(skfd);
401 return stat;
402 #else
403 #warning "No PPPDeviceExists implementation defined"
404 return FALSE;
405 #endif
409 PRemoteConnection::Status PRemoteConnection::GetConfiguration(
410 Configuration & config // Configuration of remote connection
413 return GetConfiguration(remoteName, config);
417 PRemoteConnection::Status PRemoteConnection::GetConfiguration(
418 const PString & name, // Remote connection name to get configuration
419 Configuration & config // Configuration of remote connection
422 if (name.IsEmpty())
423 return NoNameOrNumber;
425 PConfig cfg(0, RasStr);
426 if (cfg.GetString(name, NumberStr, "").IsEmpty())
427 return NoNameOrNumber;
429 cfg.SetDefaultSection(name);
431 config.device = cfg.GetString(OptionsStr, PortStr, DefaultPort);
432 config.phoneNumber = cfg.GetString(NumberStr);
433 config.ipAddress = cfg.GetString(AddressStr);
434 config.dnsAddress = cfg.GetString(NameServerStr);
435 config.script = cfg.GetString(LoginStr, DefaultLogin);
436 config.subEntries = 0;
437 config.dialAllSubEntries = FALSE;
439 return Connected;
443 PRemoteConnection::Status PRemoteConnection::SetConfiguration(
444 const Configuration & config, // Configuration of remote connection
445 BOOL create // Flag to create connection if not present
448 return SetConfiguration(remoteName, config, create);
452 PRemoteConnection::Status PRemoteConnection::SetConfiguration(
453 const PString & name, // Remote connection name to configure
454 const Configuration & config, // Configuration of remote connection
455 BOOL create // Flag to create connection if not present
458 if (config.phoneNumber.IsEmpty())
459 return GeneralFailure;
461 PConfig cfg(0, RasStr);
463 if (!create && cfg.GetString(name, NumberStr, "").IsEmpty())
464 return NoNameOrNumber;
466 cfg.SetDefaultSection(name);
468 if (config.device.IsEmpty())
469 cfg.DeleteKey(PortStr);
470 else
471 cfg.SetString(PortStr, config.device);
473 cfg.SetString(NumberStr, config.phoneNumber);
475 if (config.ipAddress.IsEmpty())
476 cfg.DeleteKey(AddressStr);
477 else
478 cfg.SetString(AddressStr, config.ipAddress);
480 if (config.dnsAddress.IsEmpty())
481 cfg.DeleteKey(NameServerStr);
482 else
483 cfg.SetString(NameServerStr, config.dnsAddress);
485 if (config.script.IsEmpty())
486 cfg.DeleteKey(LoginStr);
487 else
488 cfg.SetString(LoginStr, config.script);
490 return Connected;
494 PRemoteConnection::Status PRemoteConnection::RemoveConfiguration(
495 const PString & name // Remote connection to remove
498 PConfig cfg(0, RasStr);
500 if (cfg.GetString(name, NumberStr, "").IsEmpty())
501 return NoNameOrNumber;
503 cfg.DeleteSection(name);
504 return Connected;
509 // End of File ////////////////////////////////////////////////////////////////