- implemented correct output for utf-8 terminals
[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     if (!pppstat.get_stat (ifname, rx_bytes, tx_bytes))
153         return false;
154
155     dprintf ("data total = %lld %lld\n", rx_bytes, tx_bytes);
156
157     return true;
158 }
159
160
161 Connection*
162 Connection::create (const ConnectionConfig* conf, void (*lcb) (bool, const char*),
163                     void (*scb) (Status), void (*ecb) ())
164 {
165     const DSLConfig* dslconf = dynamic_cast <const DSLConfig*> (conf);
166     if (dslconf)
167         return new DSL (dslconf, lcb, scb, ecb);
168
169     const ModemConfig* modemconf = dynamic_cast <const ModemConfig*> (conf);
170     if (modemconf)
171         return new Modem (modemconf, lcb, scb, ecb);
172
173     return 0;
174 }
175
176
177 bool
178 Connection::add_ip_options (Process* pppd)
179 {
180     if (config->modify_ip)
181     {
182         if (config->demand)
183         {
184             if (!config->local_ip.empty () || !config->remote_ip.empty ())
185                 *pppd << config->local_ip + ":" + config->remote_ip;
186             else
187                 *pppd << "192.168.99.1:192.168.99.99";
188         }
189
190         *pppd << "ipcp-accept-local" << "ipcp-accept-remote";
191     }
192     else
193     {
194         *pppd << config->local_ip + ":" + config->remote_ip;
195     }
196
197     return true;
198 }
199
200
201 bool
202 Connection::add_user_pass_options (Process* pppd)
203 {
204     *pppd << "user" << config->username.c_str ();
205
206     // open a pipe to pass password to pppd
207
208     int pppd_passwdfd[2];
209     if (pipe (pppd_passwdfd) == -1)
210     {
211         const char* se = strerror (errno);
212         logit (true, "Pipe failed (very bad): %s", se);
213         dprintf ("error, pipe failed: %m\n");
214         return false;
215     }
216
217     write (pppd_passwdfd[1], config->password.c_str (),
218            config->password.length ());
219     close (pppd_passwdfd[1]);
220
221     *pppd << "passwordfd" << pppd_passwdfd[0];
222     pppd->add_fd_notclose (pppd_passwdfd[0]);
223
224     return true;
225 }
226
227
228 bool
229 Connection::add_ipparam (Process* pppd)
230 {
231     // FIXME: see if this realy makes it
232 #if 0
233     if (!run_poll_tcpip)
234         *pppd << "ipparam" << "no_poll_tcpip";
235 #else
236     *pppd << "ipparam" << qande (config->ifcfg_filename) + ' ' +
237         qande (config->provider_filename);
238 #endif
239     return true;
240 }
241
242
243 void
244 Connection::status_callback (Status n)
245 {
246     status = n;
247
248     if (scb)
249         (*scb) (status);
250 }
251
252
253 void
254 Connection::logit (bool highlight, const char* format, ...) const
255 {
256     if (lcb)
257     {
258         char* result = 0;
259
260         va_list ap;
261         va_start (ap, format);
262         vasprintf (&result, format, ap);
263         va_end (ap);
264
265         (*lcb) (highlight, result);
266
267         free (result);
268     }
269 }
270
271
272 void
273 Connection::weexit ()
274 {
275     if (ecb)
276         (*ecb) ();
277 }
278
279
280 void
281 Connection::dns_modify (const string& dns1, const string& dns2)
282 {
283     if (dns1.empty () && dns2.empty ())
284         return;
285
286     Process resolv;
287     resolv << "/sbin/modify_resolvconf" << "modify";
288     resolv << "--service" << "smpppd" << "--script" << "/usr/sbin/smpppd";
289     resolv << "--process" << "smpppd" << "--pid" << getpid ();
290     resolv << "--nameservers" << dns1 + " " + dns2;
291
292     resolv << "--text" <<
293         "If you do not want the smpppd to change your nameserver settings\n"
294         "set AUTODNS=no in the config file for this provider in\n"
295         "/etc/sysconfig/network/providers/.";
296
297     if (!resolv.start ())
298         return;
299
300     dns_changed = true;
301
302     resolv.wait_for_dead ();
303 }
304
305
306 void
307 Connection::dns_restore ()
308 {
309     if (!dns_changed)
310         return;
311
312     Process resolv;
313     resolv << "/sbin/modify_resolvconf" << "restore";
314     resolv << "--service" << "smpppd";
315
316     if (!resolv.start ())
317         return;
318
319     dns_changed = false;
320
321     resolv.wait_for_dead ();
322 }
323
324
325 bool
326 Connection::check_peers_file (const char* file)
327 {
328     string tmp1 = string (_PATH_PEERS) + file;
329     if (access (tmp1.c_str (), R_OK) == 0)
330         return true;
331
332     logit (true, "error: peers file %s does not exits", tmp1.c_str ());
333     return false;
334 }