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
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): ______________________________________.
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"
50 #include <ptlib/pipechan.h>
51 #include <ptlib/remconn.h>
54 #include <sys/ioctl.h>
55 #include <sys/socket.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()
129 PRemoteConnection::PRemoteConnection(const PString
& name
)
135 PRemoteConnection::~PRemoteConnection()
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
,
154 // cannot open remote connection with an empty name
155 if (name
.IsEmpty()) {
156 status
= NoNameOrNumber
;
157 PProcess::PXShowSystemWarning(1000, ErrorTable
[0].str
);
161 // cannot open remote connection not in config file
162 PConfig
config(0, RasStr
);
164 if ((phoneNumber
= config
.GetString(name
, NumberStr
, "")).IsEmpty()) {
165 status
= NoNameOrNumber
;
166 PProcess::PXShowSystemWarning(1001, ErrorTable
[1].str
);
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) {
186 // name = name of configuration
187 // sectionName = name of config section
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
;
224 argArray
[argCount
++] = portName
;
225 argArray
[argCount
++] = baudRate
;
227 PStringArray tokens
= PPPDOpts
.Tokenise(' ');
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
;
259 argArray
[argCount
++] = addressStr
+ ":";
261 ///////////////////////////////////////////
263 // instigate a dial using pppd
265 pipeChannel
= PNEW
PPipeChannel(pppdStr
, argArray
);
268 ///////////////////////////////////////////
270 // wait until the dial succeeds, or times out
272 PTimer
timer(timeout
*1000);
274 if (pipeChannel
== NULL
|| !pipeChannel
->IsRunning())
277 if (PPPDeviceStatus(deviceStr
) > 0) {
282 if (!timer
.IsRunning())
285 PThread::Current()->Sleep(1000);
289 ///////////////////////////////////////////
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()
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);
334 if (!pipeChannel
->IsRunning() ||
335 (PPPDeviceStatus(deviceStr
) <= 0) ||
338 PThread::Current()->Sleep(1000);
341 // kill the connection for real
347 PRemoteConnection::Status
PRemoteConnection::GetStatus() const
349 if (pipeChannel
!= NULL
&&
350 pipeChannel
->IsRunning() &&
351 PPPDeviceStatus(deviceStr
) > 0)
357 PStringArray
PRemoteConnection::GetAvailableNames()
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
;
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)
387 // Create a channel to the NET kernel.
388 if ((skfd
= socket(AF_INET
, SOCK_DGRAM
,0)) < 0)
391 // attempt to get the status of the ppp connection
393 strcpy(ifr
.ifr_name
, devName
);
394 if (ioctl(skfd
, SIOCGIFFLAGS
, &ifr
) < 0)
397 stat
= (ifr
.ifr_flags
& IFF_UP
) ? 1 : 0;
399 // attempt to get the status of the ppp connection
403 #warning "No PPPDeviceExists implementation defined"
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
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
;
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
);
471 cfg
.SetString(PortStr
, config
.device
);
473 cfg
.SetString(NumberStr
, config
.phoneNumber
);
475 if (config
.ipAddress
.IsEmpty())
476 cfg
.DeleteKey(AddressStr
);
478 cfg
.SetString(AddressStr
, config
.ipAddress
);
480 if (config
.dnsAddress
.IsEmpty())
481 cfg
.DeleteKey(NameServerStr
);
483 cfg
.SetString(NameServerStr
, config
.dnsAddress
);
485 if (config
.script
.IsEmpty())
486 cfg
.DeleteKey(LoginStr
);
488 cfg
.SetString(LoginStr
, config
.script
);
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
);
509 // End of File ////////////////////////////////////////////////////////////////