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