- reactivated isdn
[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 <stddef.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <asm/types.h>
18 #include <net/if.h>
19 #include <stdarg.h>
20
21 #include <algorithm>
22
23 #include "dsl.h"
24 #include "isdn.h"
25 #include "modem.h"
26 #include "defines.h"
27 #include "utils.h"
28 #include "parse.h"
29
30
31 Connection::Connection (const ConnectionConfig* config,
32                         void (*lcb) (bool, const string&),
33                         void (*scb) (Status), void (*ecb) ())
34     : config (config),
35       lcb (lcb),
36       scb (scb),
37       ecb (ecb)
38 {
39     dns_changed = false;
40
41     rx_bytes = tx_bytes = 0;
42
43     accounting_is_up = false;
44     next_alive = (time_t)(-1);
45
46     reconnect_time = (time_t)(-1);
47 }
48
49
50 Connection::~Connection ()
51 {
52     dprintf ("%s\n", __PRETTY_FUNCTION__);
53
54     dns_restore ();
55 }
56
57
58 bool
59 Connection::accounting_up ()
60 {
61     time_begin = time (0);
62     rx_begin = rx_bytes;
63     tx_begin = tx_bytes;
64
65     accounting_is_up = true;
66
67     string tmp1 = tostring (time_begin, true, false);
68     string tmp2 = config->ifcfg_filename.substr (6, string::npos);
69     string tmp3 = qap (config->provider_menuname);
70
71     FILE* fout = fopen (ACCOUNTING_LOG, "a");
72     if (!fout) {
73         logit (true, "error: can't open `" ACCOUNTING_LOG
74                "' for writing: %s", strerror (errno));
75         return false;
76     }
77
78     // file locking should not be necessary
79
80     fprintf (fout, "%s %s u om %s\n", tmp1.c_str (), tmp2.c_str (),
81              tmp3.c_str ());
82
83     fclose (fout);
84
85     // schedule next alive info
86     if (config->alive_interval > (time_t)(0))
87         next_alive = time (0) + config->alive_interval;
88     else
89         next_alive = (time_t)(-1);
90
91     return true;
92 }
93
94
95 bool
96 Connection::accounting_alive ()
97 {
98     if (!accounting_is_up)
99         return false;
100
101     string tmp1 = tostring (time (0), true, false);
102     string tmp2 = config->ifcfg_filename.substr (6, string::npos);
103
104     FILE* fout = fopen (ACCOUNTING_LOG, "a");
105     if (!fout) {
106         logit (true, "error: can't open `" ACCOUNTING_LOG
107                "' for writing: %s", strerror (errno));
108         return false;
109     }
110
111     // file locking should not be necessary
112
113     fprintf (fout, "%s %s a om %llu %llu\n", tmp1.c_str (), tmp2.c_str (),
114              rx_bytes - rx_begin, tx_bytes - tx_begin);
115
116     fclose (fout);
117
118     // schedule next alive info
119
120     if (config->alive_interval > (time_t)(0))
121         next_alive = time (0) + config->alive_interval;
122     else
123         next_alive = (time_t)(-1);
124
125     return true;
126 }
127
128
129 bool
130 Connection::accounting_down ()
131 {
132     if (!accounting_is_up)
133         return true;
134
135     accounting_is_up = false;
136
137     string tmp1 = tostring (time (0), true, false);
138     string tmp2 = config->ifcfg_filename.substr (6, string::npos);
139
140     FILE* fout = fopen (ACCOUNTING_LOG, "a");
141     if (!fout) {
142         logit (true, "error: can't open `" ACCOUNTING_LOG
143                "' for writing: %s", strerror (errno));
144         return false;
145     }
146
147     // file locking should not be necessary
148
149     fprintf (fout, "%s %s d om %llu %llu\n", tmp1.c_str (), tmp2.c_str (),
150              rx_bytes - rx_begin, tx_bytes - tx_begin);
151
152     fclose (fout);
153
154     // no more alive info
155     next_alive = (time_t)(-1);
156
157     return true;
158 }
159
160
161 void
162 Connection::timer ()
163 {
164     if (next_alive != (time_t)(-1) && next_alive <= time (0))
165         accounting_alive ();
166 }
167
168
169 string
170 Connection::status_name (Status status)
171 {
172     switch (status) {
173         case DISCONNECTED:
174             return "disconnected";
175         case CONNECTING:
176             return "connecting";
177         case CONNECTED:
178             return "connected";
179         case DISCONNECTING:
180             return "disconnecting";
181         case LURKING:
182             return "lurking";
183         default:
184             return "error";
185     }
186 }
187
188
189 bool
190 Connection::get_rxtx_bytes (bytes_t& rx_bytes, bytes_t& tx_bytes)
191 {
192     rx_bytes = Connection::rx_bytes;
193     tx_bytes = Connection::tx_bytes;
194     return true;
195 }
196
197
198 bool
199 Connection::read_rxtx_bytes (const char* ifname)
200 {
201     if (!pppstat.get_stat (ifname, rx_bytes, tx_bytes))
202         return false;
203
204     dprintf ("data total = %lld %lld\n", rx_bytes, tx_bytes);
205
206     return true;
207 }
208
209
210 Connection*
211 Connection::create (const ConnectionConfig* conf, void (*lcb) (bool, const string&),
212                     void (*scb) (Status), void (*ecb) ())
213 {
214     const DSLConfig* dslconf = dynamic_cast <const DSLConfig*> (conf);
215     if (dslconf)
216         return new DSL (dslconf, lcb, scb, ecb);
217
218     const ISDNConfig* isdnconf = dynamic_cast <const ISDNConfig*> (conf);
219     if (isdnconf)
220         return new ISDN (isdnconf, lcb, scb, ecb);
221
222     const ModemConfig* modemconf = dynamic_cast <const ModemConfig*> (conf);
223     if (modemconf)
224         return new Modem (modemconf, lcb, scb, ecb);
225
226     return 0;
227 }
228
229
230 bool
231 Connection::add_ip_options (Process* pppd)
232 {
233     if (config->modify_ip)
234     {
235         if (config->demand)
236         {
237             if (!config->local_ip.empty () || !config->remote_ip.empty ())
238                 *pppd << config->local_ip + ":" + config->remote_ip;
239             else
240                 *pppd << "192.168.99.1:192.168.99.99";
241         }
242
243         *pppd << "ipcp-accept-local" << "ipcp-accept-remote";
244     }
245     else
246     {
247         *pppd << config->local_ip + ":" + config->remote_ip;
248     }
249
250     return true;
251 }
252
253
254 bool
255 Connection::add_user_pass_options (Process* pppd)
256 {
257     *pppd << "user" << config->username.c_str ();
258
259     // open a pipe to pass password to pppd
260
261     int pppd_passwdfd[2];
262     if (pipe (pppd_passwdfd) == -1)
263     {
264         const char* se = strerror (errno);
265         logit (true, "Pipe failed (very bad): %s", se);
266         dprintf ("error, pipe failed: %m\n");
267         return false;
268     }
269
270     write (pppd_passwdfd[1], config->password.c_str (),
271            config->password.length ());
272     close (pppd_passwdfd[1]);
273
274     *pppd << "passwordfd" << pppd_passwdfd[0];
275     pppd->add_fd_notclose (pppd_passwdfd[0]);
276
277     return true;
278 }
279
280
281 bool
282 Connection::add_ipparam (Process* pppd)
283 {
284     // FIXME: see if this really makes it
285 #if 0
286     if (!run_poll_tcpip)
287         *pppd << "ipparam" << "no_poll_tcpip";
288 #else
289     *pppd << "ipparam" << qap (config->ifcfg_filename, QAP_SH) + ' ' +
290         qap (config->provider_filename, QAP_SH);
291 #endif
292     return true;
293 }
294
295
296 void
297 Connection::status_callback (Status n)
298 {
299     status = n;
300
301     if (scb)
302         (*scb) (status);
303 }
304
305
306 void
307 Connection::logit (bool highlight, const char* format, ...) const
308 {
309     if (lcb)
310     {
311         char* result = 0;
312
313         va_list ap;
314         va_start (ap, format);
315         vasprintf (&result, format, ap);
316         va_end (ap);
317
318         (*lcb) (highlight, result);
319
320         free (result);
321     }
322 }
323
324
325 void
326 Connection::weexit ()
327 {
328     if (ecb)
329         (*ecb) ();
330 }
331
332
333 void
334 Connection::dns_modify (const string& dns1, const string& dns2)
335 {
336     if (dns1.empty () && dns2.empty ())
337         return;
338
339     Process resolv;
340     resolv << "/sbin/modify_resolvconf" << "modify";
341     resolv << "--service" << "smpppd" << "--script" << "/usr/sbin/smpppd";
342     resolv << "--process" << "smpppd" << "--pid" << getpid ();
343     resolv << "--nameservers" << dns1 + " " + dns2;
344
345     resolv << "--text" <<
346         "If you do not want the smpppd to change your nameserver settings\n"
347         "set AUTODNS=no in the config file for this provider in\n"
348         "/etc/sysconfig/network/providers/.";
349
350     if (!resolv.start ())
351         return;
352
353     dns_changed = true;
354
355     resolv.wait_for_dead ();
356 }
357
358
359 void
360 Connection::dns_restore ()
361 {
362     if (!dns_changed)
363         return;
364
365     Process resolv;
366     resolv << "/sbin/modify_resolvconf" << "restore";
367     resolv << "--service" << "smpppd";
368
369     if (!resolv.start ())
370         return;
371
372     dns_changed = false;
373
374     resolv.wait_for_dead ();
375 }
376
377
378 bool
379 Connection::check_peers_file (const char* file)
380 {
381     string tmp1 = string (_PATH_PEERS) + file;
382     if (access (tmp1.c_str (), R_OK) == 0)
383         return true;
384
385     logit (true, "error: peers file %s does not exits", tmp1.c_str ());
386     return false;
387 }