- implemented experimental capi-isdn mode
[opensuse:smpppd.git] / smpppd / connection.cc
1
2
3 /*
4  *  Author: Arvin Schnell <arvin@suse.de>
5  */
6
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <sys/stat.h>
12 #include <errno.h>
13 #include <glob.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <sys/ioctl.h>
17 #include <sys/socket.h>
18 #include <asm/types.h>
19 #include <net/if.h>
20 #include <linux/ppp_defs.h>
21 #include <linux/if_ppp.h>
22
23 #include <iostream>
24 #include <fstream>
25 #include <algorithm>
26
27 using std::cerr;
28
29 #include "link.h"
30 #include "main.h"
31 #include "modem.h"
32 #include "isdn.h"
33 #include "dsl.h"
34 #include "misc.h"
35 #include "utils.h"
36 #include "config.h"
37 #include "log.h"
38
39
40 PPPStat::PPPStat ()
41 {
42     fd = socket (AF_INET, SOCK_DGRAM, 0);
43     if (fd < 0) {
44         perror ("socket");
45         fd = -1;
46     }
47 }
48
49
50 PPPStat::~PPPStat ()
51 {
52     if (fd >= 0)
53         close (fd);
54 }
55
56
57 bool
58 PPPStat::get_stat (const char* ifname, long& rx_bytes, long& tx_bytes)
59 {
60     struct ifpppstatsreq req;
61     memset (&req, 0, sizeof (req));
62     req.stats_ptr = (caddr_t) &req.stats;
63     strncpy (req.ifr__name, ifname, sizeof (req.ifr__name));
64
65     if (ioctl (fd, SIOCGPPPSTATS, &req) < 0) {
66         perror ("ioctl (SIOCGPPPSTATS)");
67         return false;
68     }
69
70     rx_bytes = req.stats.p.ppp_ibytes;
71     tx_bytes = req.stats.p.ppp_obytes;
72     return true;
73 }
74
75
76 Connection::Connection ()
77 {
78 #ifndef NDEBUG
79     cerr << __PRETTY_FUNCTION__ << '\n';
80 #endif
81
82     defaultroute = true;
83     demand = false;
84     idle_seconds = 600;
85     modify_dns = true;
86     dns1 = dns2 = "";
87
88     modify_ip = true;
89     local_ip = remote_ip = "";
90
91     username = password = "";
92     ask_password = false;
93
94     run_poll_tcpip = true;
95
96     reconnect = false;
97     reconnect_delay = 15;
98     reconnect_time = 0;
99     reconnect_exits = 256;
100
101     rx_bytes = tx_bytes = 0;
102 }
103
104
105 Connection::~Connection ()
106 {
107 #ifndef NDEBUG
108     cerr << __PRETTY_FUNCTION__ << '\n';
109 #endif
110 }
111
112
113 bool
114 Connection::get_rxtx_bytes (long& rx_bytes, long& tx_bytes)
115 {
116     rx_bytes = Connection::rx_bytes;
117     tx_bytes = Connection::tx_bytes;
118     return true;
119 }
120
121
122 bool
123 Connection::read_rxtx_bytes (const char* ifname)
124 {
125     long old_rx_bytes = rx_bytes;
126     long old_tx_bytes = tx_bytes;
127
128     if (!pppstat.get_stat (ifname, rx_bytes, tx_bytes))
129         return false;
130
131 #ifndef NDEBUG
132     cerr << "data total = " << rx_bytes << ' ' << tx_bytes << '\n';
133 #endif
134
135     // FIXME: this is hard to understand
136     if (rx_bytes != old_rx_bytes || tx_bytes != old_tx_bytes) {
137         clients.write_rxtx_bytes ();
138         once_equal = false;
139     } else {
140         if (!once_equal) {
141             clients.write_rxtx_bytes ();
142             once_equal = true;
143         }
144     }
145
146     return true;
147 }
148
149
150 Connection*
151 Connection::create (const Interface* inter, const Provider* prov)
152 {
153     Connection* conn = 0;
154
155     switch (inter->mode) {
156
157         case Interface::MODEM:
158             conn = new ::Modem;
159             break;
160
161         case Interface::ISDN:
162             conn = new ::ISDN;
163             break;
164
165         case Interface::DSL:
166             conn = new ::DSL;
167             break;
168
169     }
170
171     if (conn) {
172         conn->read_config (inter, prov);
173 #ifndef NDEBUG
174         conn->dump_config ();
175 #endif
176         if (!conn->check_config ()) {
177             delete conn;
178             conn = 0;
179         }
180     }
181
182     return conn;
183 }
184
185
186 void
187 Connection::read_config (const Interface* inter, const Provider* prov)
188 {
189     for (int i = 0; i < 2; i++) {
190
191         const string filename = i == 0 ? INTERFACES_DIR + inter->filename
192             : PROVIDERS_DIR + prov->filename;
193
194         std::ifstream fin (filename.c_str ());
195         if (!fin) {
196             cerr << "error, can't open `" << filename << "' for reading: "
197                  << strerror (errno) << '\n';
198             return;
199         }
200
201         string line, key, value;
202
203         while (getline (fin, line)) {
204
205             int ret = getkeyvalue (line, key, value);
206
207             if (ret == 0)
208                 continue;
209
210             if (ret == -1) {
211                 cerr << "warning, syntax error in line `" << line << "'\n";
212                 continue;
213             }
214
215             eval_config (key, value);
216
217         }
218     }
219 }
220
221
222 void
223 Connection::eval_config (const string& key, const string& value)
224 {
225     if (key == "DEFAULTROUTE") {
226         defaultroute = value == "yes";
227         return;
228     }
229
230     if (key == "DEMAND") {
231         demand = value == "yes";
232         return;
233     }
234
235     if (key == "IDLETIME") {
236         idle_seconds = atoi (value.c_str ());
237         return;
238     }
239
240     if (key == "MODIFYDNS") {
241         modify_dns = value == "yes";
242         return;
243     }
244
245     if (key == "DNS1") {
246         dns1 = value;
247         return;
248     }
249
250     if (key == "DNS2") {
251         dns2 = value;
252         return;
253     }
254
255     if (key == "MODIFYIP") {
256         modify_ip = value == "yes";
257         return;
258     }
259
260     if (key == "IPADDR") {
261         local_ip = value;
262         return;
263     }
264
265     if (key == "REMOTE_IPADDR") {
266         remote_ip = value;
267         return;
268     }
269
270     if (key == "USERNAME") {
271         username = value;
272         return;
273     }
274
275     if (key == "PASSWORD") {
276         password = value;
277         return;
278     }
279
280     if (key == "ASKPASSWORD") {
281         ask_password = value == "yes";
282         return;
283     }
284
285     if (key == "AUTO_RECONNECT") {
286         reconnect = value == "yes";
287         return;
288     }
289
290     if (key == "AUTO_RECONNECT_DELAY") {
291         reconnect_delay = atoi (value.c_str ());
292         if (reconnect_delay < 5)
293             reconnect_delay = 5;
294         return;
295     }
296
297     if (key == "AUTO_RECONNECT_EXITS") {
298         reconnect_exits = 0;
299         char* buffer = strdup (value.c_str ());
300         char* tmp = buffer;
301         while (true) {
302             int i = strtol (tmp, &tmp, 10);
303             if (i == 0)
304                 break;
305             bit_set (i, &reconnect_exits);
306         }
307         free (buffer);
308     }
309
310     if (key == "RUN_POLL_TCPIP") {
311         run_poll_tcpip = value != "no";
312         return;
313     }
314
315 }
316
317
318 bool
319 Connection::check_config ()
320 {
321     if (username.empty ()) {
322         mylog.sprintf (true, "Configuration does not specify a username.");
323         return false;
324     }
325
326     return true;
327 }
328
329
330 void
331 Connection::list_config (std::list <string>* config) const
332 {
333     config->push_back ("username = " + username);
334     config->push_back ("password = <hidden>");
335     config->push_back ("ask-password = " + string (ask_password ? "yes" : "no"));
336
337     config->push_back ("defaultroute = " + string (defaultroute ? "yes" : "no"));
338
339     config->push_back ("demand = " + string (demand ? "yes" : "no"));
340     config->push_back ("idle-seconds = " + tostring (idle_seconds));
341
342     config->push_back ("modify-dns = " + string (modify_dns ? "yes" : "no"));
343     config->push_back ("dns1 = " + dns1);
344     config->push_back ("dns2 = " + dns2);
345
346     config->push_back ("modify-ip = " + string (modify_ip ? "yes" : "no"));
347     config->push_back ("local ip = " + local_ip);
348     config->push_back ("remote ip = " + remote_ip);
349
350     config->push_back ("auto-reconnect = " + string (reconnect ? "yes" : "no"));
351     config->push_back ("auto-reconnect-delay = " + tostring (reconnect_delay));
352
353     string tmp1;
354     for (int i = 0; i < 32; i++)
355         if (bit_test (i, reconnect_exits)) {
356             if (!tmp1.empty ())
357                 tmp1.append (" ");
358             tmp1.append (tostring (i));
359         }
360     config->push_back ("auto-reconnect-exits = " + tmp1);
361
362     config->push_back ("run-poll-tcpip = " + string (run_poll_tcpip ? "yes" : "no"));
363 }
364
365
366 #ifndef NDEBUG
367 void
368 Connection::dump_config () const
369 {
370     std::list <string> config;
371     list_config (&config);
372     for (std::list <string>::const_iterator it = config.begin ();
373          it != config.end (); it++)
374         cerr << *it << '\n';
375 }
376 #endif
377