- added some sanity checks for the configuration
[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     : ok (false)
78 {
79 #ifndef NDEBUG
80     cerr << __PRETTY_FUNCTION__ << '\n';
81 #endif
82
83     defaultroute = true;
84
85     demand = false;
86     idle_seconds = 0;
87     auto_dns = true;
88     dns1 = dns2 = "";
89
90     username = password = "";
91     ask_password = false;
92
93     rx_bytes = tx_bytes = 0;
94 }
95
96
97 Connection::~Connection ()
98 {
99 #ifndef NDEBUG
100     cerr << __PRETTY_FUNCTION__ << '\n';
101 #endif
102 }
103
104
105 bool
106 Connection::get_rxtx_bytes (long& rx_bytes, long& tx_bytes)
107 {
108     rx_bytes = Connection::rx_bytes;
109     tx_bytes = Connection::tx_bytes;
110     return true;
111 }
112
113
114 bool
115 Connection::read_rxtx_bytes (const char* ifname)
116 {
117     long old_rx_bytes = rx_bytes;
118     long old_tx_bytes = tx_bytes;
119
120     if (!pppstat.get_stat (ifname, rx_bytes, tx_bytes))
121         return false;
122
123 #ifndef NDEBUG
124     cout << "data total = " << rx_bytes << ' ' << tx_bytes << '\n';
125 #endif
126
127     // FIXME: this is hard to understand
128     if (rx_bytes != old_rx_bytes || tx_bytes != old_tx_bytes) {
129         clients.write_rxtx_bytes ();
130         once_equal = false;
131     } else {
132         if (!once_equal) {
133             clients.write_rxtx_bytes ();
134             once_equal = true;
135         }
136     }
137
138     return true;
139 }
140
141
142 Connection*
143 Connection::create (const Interface* inter, const Provider* prov)
144 {
145     Connection* conn = 0;
146
147     switch (inter->mode) {
148
149         case Interface::MODEM:
150             conn = new ::Modem;
151             break;
152
153         case Interface::ISDN:
154             conn = new ::ISDN;
155             break;
156
157         case Interface::DSL:
158             conn = new ::DSL;
159             break;
160
161     }
162
163     if (conn) {
164         conn->read_config (inter, prov);
165 #ifndef NDEBUG
166         conn->dump_config ();
167 #endif
168         if (!conn->check_config ()) {
169             delete conn;
170             conn = 0;
171         }
172     }
173
174     return conn;
175 }
176
177
178 void
179 Connection::read_config (const Interface* inter, const Provider* prov)
180 {
181     for (int i = 0; i < 2; i++) {
182
183         const string filename = i == 0 ? inter->filename : prov->filename;
184
185         std::ifstream fin (filename.c_str ());
186         if (!fin) {
187             cerr << "error, can't open `" << filename << "' for reading: "
188                  << strerror (errno) << '\n';
189             return;
190         }
191
192         string line, key, value;
193
194         while (getline (fin, line)) {
195
196             int ret = getkeyvalue (line, key, value);
197
198             if (ret == 0)
199                 continue;
200
201             if (ret == -1) {
202                 cerr << "warning, syntax error in line `" << line << "'\n";
203                 continue;
204             }
205
206             eval_config (key, value);
207
208         }
209     }
210 }
211
212
213 void
214 Connection::eval_config (const string& key, const string& value)
215 {
216     if (key == "DEFAULTROUTE") {
217         defaultroute = value == "yes";
218         return;
219     }
220
221     if (key == "DEMAND") {
222         demand = value == "yes";
223         return;
224     }
225
226     if (key == "IDLETIME") {
227         idle_seconds = atoi (value.c_str ());
228         return;
229     }
230
231     if (key == "AUTODNS") {
232         auto_dns = value == "yes";
233         return;
234     }
235
236     if (key == "DNS1") {
237         dns1 = value;
238         return;
239     }
240
241     if (key == "DNS2") {
242         dns2 = value;
243         return;
244     }
245
246     if (key == "USERNAME") {
247         username = value;
248         return;
249     }
250
251     if (key == "PASSWORD") {
252         password = value;
253         return;
254     }
255
256     if (key == "ASKPASSWORD") {
257         ask_password = value == "yes";
258         return;
259     }
260 }
261
262
263 #ifndef NDEBUG
264 void
265 Connection::dump_config () const
266 {
267     cout << "defaultroute" << (defaultroute ? "yes" : "no") << '\n';
268     cout << "demand = " << (demand ? "yes" : "no") << '\n';
269     cout << "idle seconds = " << idle_seconds << '\n';
270     cout << "auto dns = " << (auto_dns ? "yes" : "no") << '\n';
271     cout << "dns = " << dns1 << ' ' << dns2 << '\n';
272     cout << "username = " << username << '\n';
273     cout << "password = " << password << '\n';
274     cout << "ask password = " << (ask_password ? "yes" : "no") << '\n';
275 }
276 #endif
277
278
279 bool
280 Connection::check_config ()
281 {
282     if (username.empty ()) {
283         mylog.sprintf (true, "Configuration does not specify a username.");
284         return false;
285     }
286
287     return true;
288 }
289