1 | /* |
2 | This file is part of Mtproto-proxy Library. |
3 | |
4 | Mtproto-proxy Library is free software: you can redistribute it and/or modify |
5 | it under the terms of the GNU Lesser General Public License as published by |
6 | the Free Software Foundation, either version 2 of the License, or |
7 | (at your option) any later version. |
8 | |
9 | Mtproto-proxy Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public License |
15 | along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>. |
16 | |
17 | Copyright 2014 Telegram Messenger Inc |
18 | 2014 Vitaly Valtman |
19 | */ |
20 | |
21 | #include <assert.h> |
22 | #include <stdlib.h> |
23 | #include <stdio.h> |
24 | #include <unistd.h> |
25 | #include <stdarg.h> |
26 | #include <string.h> |
27 | #include <sys/types.h> |
28 | #include <sys/stat.h> |
29 | #include <fcntl.h> |
30 | |
31 | #include "md5.h" |
32 | #include "common/parse-config.h" |
33 | #include "resolver.h" |
34 | #include "kprintf.h" |
35 | |
36 | #define MAX_CONFIG_SIZE (16 << 20) |
37 | |
38 | static char *config_buff; |
39 | char *config_name, *cfg_start, *cfg_end, *cfg_cur; |
40 | int config_bytes, cfg_lno, cfg_lex = -1; |
41 | |
42 | int cfg_skipspc (void) { |
43 | while (*cfg_cur == ' ' || *cfg_cur == 9 || *cfg_cur == 13 || *cfg_cur == 10 || *cfg_cur == '#') { |
44 | if (*cfg_cur == '#') { |
45 | do cfg_cur++; while (*cfg_cur && *cfg_cur != 10); |
46 | continue; |
47 | } |
48 | if (*cfg_cur == 10) { |
49 | cfg_lno++; |
50 | } |
51 | cfg_cur++; |
52 | } |
53 | return (unsigned char) *cfg_cur; |
54 | } |
55 | |
56 | int cfg_skspc (void) { |
57 | while (*cfg_cur == ' ' || *cfg_cur == 9) { |
58 | cfg_cur++; |
59 | } |
60 | return (unsigned char) *cfg_cur; |
61 | } |
62 | |
63 | int cfg_getlex (void) { |
64 | switch (cfg_skipspc()) { |
65 | case ';': |
66 | case ':': |
67 | case '{': |
68 | case '}': |
69 | return cfg_lex = *cfg_cur++; |
70 | case 0: |
71 | return cfg_lex = 0; |
72 | } |
73 | return cfg_lex = -1; |
74 | } |
75 | |
76 | int cfg_getword (void) { |
77 | cfg_skspc(); |
78 | char *s = cfg_cur; |
79 | if (*s != '[') { |
80 | while ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || (*s >= '0' && *s <= '9') || *s == '.' || *s == '-' || *s == '_') { |
81 | s++; |
82 | } |
83 | } else { |
84 | s++; |
85 | while ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || (*s >= '0' && *s <= '9') || *s == '.' || *s == '-' || *s == '_' || *s == ':') { |
86 | s++; |
87 | } |
88 | if (*s == ']') { |
89 | s++; |
90 | } |
91 | } |
92 | return s - cfg_cur; |
93 | } |
94 | |
95 | int cfg_getstr (void) { |
96 | cfg_skspc(); |
97 | char *s = cfg_cur; |
98 | if (*s == '"') { return 1; } // fix later |
99 | while (*s > ' ' && *s != ';') { |
100 | s++; |
101 | } |
102 | return s - cfg_cur; |
103 | } |
104 | |
105 | long long cfg_getint (void) { |
106 | cfg_skspc (); |
107 | char *s = cfg_cur; |
108 | long long x = 0; |
109 | while (*s >= '0' && *s <= '9') { |
110 | x = x * 10 + *(s ++) - '0'; |
111 | } |
112 | cfg_cur = s; |
113 | return x; |
114 | } |
115 | |
116 | long long cfg_getint_zero (void) { |
117 | cfg_skspc (); |
118 | char *s = cfg_cur; |
119 | long long x = 0; |
120 | while (*s >= '0' && *s <= '9') { |
121 | x = x * 10 + *(s ++) - '0'; |
122 | } |
123 | if (cfg_cur == s) { |
124 | return -1; |
125 | } else { |
126 | cfg_cur = s; |
127 | return x; |
128 | } |
129 | } |
130 | |
131 | long long cfg_getint_signed_zero (void) { |
132 | cfg_skspc (); |
133 | char *s = cfg_cur; |
134 | long long x = 0; |
135 | int sgn = 1; |
136 | if (*s == '-') { |
137 | sgn = -1; |
138 | ++s; |
139 | } |
140 | while (*s >= '0' && *s <= '9') { |
141 | x = x * 10 + sgn * (*(s++) - '0'); |
142 | } |
143 | if (s == cfg_cur + (sgn < 0)) { |
144 | return (-1LL << 63); |
145 | } else { |
146 | cfg_cur = s; |
147 | return x; |
148 | } |
149 | } |
150 | |
151 | void syntax (const char *msg, ...) { |
152 | if (!msg) { |
153 | msg = "syntax error" ; |
154 | } |
155 | if (cfg_lno) { |
156 | fprintf (stderr, "%s:%d: " , config_name, cfg_lno); |
157 | } |
158 | fprintf (stderr, "fatal: " ); |
159 | va_list args; |
160 | va_start (args, msg); |
161 | vfprintf (stderr, msg, args); |
162 | va_end (args); |
163 | int len = 0; |
164 | while (cfg_cur[len] && cfg_cur[len] != 13 && cfg_cur[len] != 10 && len < 20) { |
165 | len++; |
166 | } |
167 | fprintf (stderr, " near %.*s%s\n" , len, cfg_cur, len >= 20 ? " ..." : "" ); |
168 | } |
169 | |
170 | void syntax_warning (const char *msg, ...) { |
171 | va_list args; |
172 | if (cfg_lno) { |
173 | fprintf (stderr, "%s:%d: " , config_name, cfg_lno); |
174 | } |
175 | fputs ("warning: " , stderr); |
176 | va_start (args, msg); |
177 | vfprintf (stderr, msg, args); |
178 | va_end (args); |
179 | int len = 0; |
180 | while (cfg_cur[len] && cfg_cur[len] != 13 && cfg_cur[len] != 10 && len < 20) { |
181 | len++; |
182 | } |
183 | fprintf (stderr, " near %.*s%s\n" , len, cfg_cur, len >= 20 ? " ..." : "" ); |
184 | } |
185 | |
186 | int expect_lexem (int lexem) { |
187 | if (cfg_lex != lexem) { |
188 | syntax ("%c expected" , lexem); |
189 | return -1; |
190 | } else { |
191 | return 0; |
192 | } |
193 | } |
194 | |
195 | int expect_word (const char *name, int len) { |
196 | int l = cfg_getword (); |
197 | if (len != l || memcmp (name, cfg_cur, len)) { |
198 | syntax ("Expected %.*s" , len, name); |
199 | return -1; |
200 | } |
201 | cfg_cur += l; |
202 | return 0; |
203 | } |
204 | |
205 | struct hostent *cfg_gethost_ex (int verb) { |
206 | struct hostent *h; |
207 | int l = cfg_getword (); |
208 | if (!l || l > 63) { |
209 | syntax ("hostname expected" ); |
210 | return 0; |
211 | } |
212 | char c = cfg_cur[l]; |
213 | //hostname = cfg_cur; |
214 | cfg_cur[l] = 0; |
215 | |
216 | if (!(h = kdb_gethostbyname (cfg_cur)) || !h->h_addr_list || !h->h_addr) { |
217 | if (verbosity >= verb) { |
218 | syntax ("cannot resolve '%s'\n" , cfg_cur); |
219 | } |
220 | *(cfg_cur += l) = c; |
221 | return 0; |
222 | } |
223 | *(cfg_cur += l) = c; |
224 | return h; |
225 | } |
226 | |
227 | struct hostent *cfg_gethost (void) { |
228 | return cfg_gethost_ex (0); |
229 | } |
230 | |
231 | void reset_config (void) { |
232 | assert (config_buff); |
233 | cfg_cur = cfg_start = config_buff; |
234 | cfg_end = cfg_start + config_bytes; |
235 | *cfg_end = 0; |
236 | cfg_lno = 0; |
237 | } |
238 | |
239 | int load_config (const char *file, int fd) { |
240 | if (!config_buff) { |
241 | config_buff = malloc (MAX_CONFIG_SIZE+4); |
242 | assert (config_buff); |
243 | } |
244 | if (fd < 0) { |
245 | fd = open (file, O_RDONLY); |
246 | if (fd < 0) { |
247 | fprintf (stderr, "Can not open file %s: %m\n" , file); |
248 | return -1; |
249 | } |
250 | } |
251 | int r; |
252 | config_bytes = r = read (fd, config_buff, MAX_CONFIG_SIZE + 1); |
253 | if (r < 0) { |
254 | fprintf (stderr, "error reading configuration file %s: %m\n" , config_name); |
255 | return -2; |
256 | } |
257 | if (r > MAX_CONFIG_SIZE) { |
258 | fprintf (stderr, "configuration file %s too long (max %d bytes)\n" , config_name, MAX_CONFIG_SIZE); |
259 | return -2; |
260 | } |
261 | if (config_name) { |
262 | free (config_name); |
263 | } |
264 | if (file) { |
265 | config_name = strdup (file); |
266 | } |
267 | |
268 | reset_config (); |
269 | return fd; |
270 | } |
271 | |
272 | void md5_hex_config (char *out) { |
273 | assert (config_buff); |
274 | md5_hex (config_buff, config_bytes, out); |
275 | } |
276 | |
277 | void close_config (int *fd) { |
278 | if (config_buff) { |
279 | free (config_buff); |
280 | config_buff = NULL; |
281 | } |
282 | if (config_name) { |
283 | free (config_name); |
284 | config_name = NULL; |
285 | } |
286 | config_bytes = 0; |
287 | cfg_cur = cfg_start = cfg_end = NULL; |
288 | if (fd) { |
289 | if (*fd >= 0) { |
290 | assert (!close (*fd)); |
291 | *fd = -1; |
292 | } |
293 | } |
294 | } |
295 | |