]> git.stg.codes - stg.git/blob - stglibs/srvconf.lib/netunit.cpp
Fixed srvconf due to changes in BFStream.
[stg.git] / stglibs / srvconf.lib / netunit.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
19  */
20
21 #include "netunit.h"
22
23 #include "stg/servconf_types.h"
24 #include "stg/common.h"
25 #include "stg/blowfish.h"
26 #include "stg/bfstream.h"
27
28 #include <algorithm> // std::min
29
30 #include <cstdio>
31 #include <cerrno>
32 #include <cstring>
33 #include <cassert>
34
35 #include <netdb.h>
36 #include <arpa/inet.h>
37 #include <unistd.h>
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42
43 using namespace STG;
44
45 namespace
46 {
47
48 const std::string::size_type MAX_XML_CHUNK_LENGTH = 2048;
49
50 struct ReadState
51 {
52     bool final;
53     NETTRANSACT::CALLBACK callback;
54     void * callbackData;
55     NETTRANSACT * nt;
56 };
57
58 }
59
60 //---------------------------------------------------------------------------
61
62 #define SEND_DATA_ERROR             "Send data error!"
63 #define RECV_DATA_ANSWER_ERROR      "Recv data answer error!"
64 #define UNKNOWN_ERROR               "Unknown error!"
65 #define CONNECT_FAILED              "Connect failed!"
66 #define BIND_FAILED                 "Bind failed!"
67 #define INCORRECT_LOGIN             "Incorrect login!"
68 #define INCORRECT_HEADER            "Incorrect header!"
69 #define SEND_LOGIN_ERROR            "Send login error!"
70 #define RECV_LOGIN_ANSWER_ERROR     "Recv login answer error!"
71 #define CREATE_SOCKET_ERROR         "Create socket failed!"
72 #define WSASTARTUP_FAILED           "WSAStartup failed!"
73 #define SEND_HEADER_ERROR           "Send header error!"
74 #define RECV_HEADER_ANSWER_ERROR    "Recv header answer error!"
75
76 //---------------------------------------------------------------------------
77 NETTRANSACT::NETTRANSACT(const std::string & s, uint16_t p,
78                          const std::string & l, const std::string & pwd)
79     : server(s),
80       port(p),
81       localPort(0),
82       login(l),
83       password(pwd),
84       sock(-1)
85 {
86 }
87 //---------------------------------------------------------------------------
88 NETTRANSACT::NETTRANSACT(const std::string & s, uint16_t p,
89                          const std::string & la, uint16_t lp,
90                          const std::string & l, const std::string & pwd)
91     : server(s),
92       port(p),
93       localAddress(la),
94       localPort(lp),
95       login(l),
96       password(pwd),
97       sock(-1)
98 {
99 }
100 //---------------------------------------------------------------------------
101 NETTRANSACT::~NETTRANSACT()
102 {
103 Disconnect();
104 }
105 //---------------------------------------------------------------------------
106 int NETTRANSACT::Connect()
107 {
108 sock = socket(PF_INET, SOCK_STREAM, 0);
109 if (sock < 0)
110     {
111     errorMsg = CREATE_SOCKET_ERROR;
112     return st_conn_fail;
113     }
114
115 if (!localAddress.empty())
116     {
117     if (localPort == 0)
118         localPort = port;
119
120     unsigned long ip = inet_addr(localAddress.c_str());
121
122     if (ip == INADDR_NONE)
123         {
124         struct hostent * phe = gethostbyname(localAddress.c_str());
125         if (phe == NULL)
126             {
127             errorMsg = "DNS error.\nCan not reslove " + localAddress;
128             return st_dns_err;
129             }
130
131         struct hostent he;
132         memcpy(&he, phe, sizeof(he));
133         ip = *((long *)he.h_addr_list[0]);
134         }
135
136     struct sockaddr_in localAddr;
137     memset(&localAddr, 0, sizeof(localAddr));
138     localAddr.sin_family = AF_INET;
139     localAddr.sin_port = htons(localPort);
140     localAddr.sin_addr.s_addr = ip;
141
142     if (bind(sock, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0)
143         {
144         errorMsg = BIND_FAILED;
145         return st_conn_fail;
146         }
147     }
148
149 struct sockaddr_in outerAddr;
150 memset(&outerAddr, 0, sizeof(outerAddr));
151
152 unsigned long ip = inet_addr(server.c_str());
153
154 if (ip == INADDR_NONE)
155     {
156     struct hostent * phe = gethostbyname(server.c_str());
157     if (phe == NULL)
158         {
159         errorMsg = "DNS error.\nCan not reslove " + server;
160         return st_dns_err;
161         }
162
163     struct hostent he;
164     memcpy(&he, phe, sizeof(he));
165     ip = *((long *)he.h_addr_list[0]);
166     }
167
168 outerAddr.sin_family = AF_INET;
169 outerAddr.sin_port = htons(port);
170 outerAddr.sin_addr.s_addr = ip;
171
172 if (connect(sock, (struct sockaddr *)&outerAddr, sizeof(outerAddr)) < 0)
173     {
174     errorMsg = CONNECT_FAILED;
175     return st_conn_fail;
176     }
177
178 return st_ok;
179 }
180 //---------------------------------------------------------------------------
181 void NETTRANSACT::Disconnect()
182 {
183 if (sock != -1)
184     {
185     shutdown(sock, SHUT_RDWR);
186     close(sock);
187     sock = -1;
188     }
189 }
190 //---------------------------------------------------------------------------
191 int NETTRANSACT::Transact(const std::string & request, CALLBACK callback, void * data)
192 {
193 int ret;
194 if ((ret = TxHeader()) != st_ok)
195     return ret;
196
197 if ((ret = RxHeaderAnswer()) != st_ok)
198     return ret;
199
200 if ((ret = TxLogin()) != st_ok)
201     return ret;
202
203 if ((ret = RxLoginAnswer()) != st_ok)
204     return ret;
205
206 if ((ret = TxLoginS()) != st_ok)
207     return ret;
208
209 if ((ret = RxLoginSAnswer()) != st_ok)
210     return ret;
211
212 if ((ret = TxData(request)) != st_ok)
213     return ret;
214
215 if ((ret = RxDataAnswer(callback, data)) != st_ok)
216     return ret;
217
218 return st_ok;
219 }
220 //---------------------------------------------------------------------------
221 int NETTRANSACT::TxHeader()
222 {
223 if (!WriteAll(sock, STG_HEADER, strlen(STG_HEADER)))
224     {
225     errorMsg = SEND_HEADER_ERROR;
226     return st_send_fail;
227     }
228
229 return st_ok;
230 }
231 //---------------------------------------------------------------------------
232 int NETTRANSACT::RxHeaderAnswer()
233 {
234 char buffer[sizeof(STG_HEADER) + 1];
235
236 if (!ReadAll(sock, buffer, strlen(OK_HEADER)))
237     {
238     printf("Receive header answer error: '%s'\n", strerror(errno));
239     errorMsg = RECV_HEADER_ANSWER_ERROR;
240     return st_recv_fail;
241     }
242
243 if (strncmp(OK_HEADER, buffer, strlen(OK_HEADER)) == 0)
244     return st_ok;
245
246 if (strncmp(ERR_HEADER, buffer, strlen(ERR_HEADER)) == 0)
247     {
248     errorMsg = INCORRECT_HEADER;
249     return st_header_err;
250     }
251 else
252     {
253     errorMsg = UNKNOWN_ERROR;
254     return st_unknown_err;
255     }
256 }
257 //---------------------------------------------------------------------------
258 int NETTRANSACT::TxLogin()
259 {
260 char loginZ[ADM_LOGIN_LEN + 1];
261 memset(loginZ, 0, ADM_LOGIN_LEN + 1);
262 strncpy(loginZ, login.c_str(), ADM_LOGIN_LEN);
263
264 if (!WriteAll(sock, loginZ, ADM_LOGIN_LEN))
265     {
266     errorMsg = SEND_LOGIN_ERROR;
267     return st_send_fail;
268     }
269
270 return st_ok;
271 }
272 //---------------------------------------------------------------------------
273 int NETTRANSACT::RxLoginAnswer()
274 {
275 char buffer[sizeof(OK_LOGIN) + 1];
276
277 if (!ReadAll(sock, buffer, strlen(OK_LOGIN)))
278     {
279     printf("Receive login answer error: '%s'\n", strerror(errno));
280     errorMsg = RECV_LOGIN_ANSWER_ERROR;
281     return st_recv_fail;
282     }
283
284 if (strncmp(OK_LOGIN, buffer, strlen(OK_LOGIN)) == 0)
285     return st_ok;
286
287 if (strncmp(ERR_LOGIN, buffer, strlen(ERR_LOGIN)) == 0)
288     {
289     errorMsg = INCORRECT_LOGIN;
290     return st_login_err;
291     }
292 else
293     {
294     errorMsg = UNKNOWN_ERROR;
295     return st_unknown_err;
296     }
297 }
298 //---------------------------------------------------------------------------
299 int NETTRANSACT::TxLoginS()
300 {
301 char loginZ[ADM_LOGIN_LEN + 1];
302 memset(loginZ, 0, ADM_LOGIN_LEN + 1);
303
304 BLOWFISH_CTX ctx;
305 InitContext(password.c_str(), PASSWD_LEN, &ctx);
306 EncryptString(loginZ, login.c_str(), std::min<size_t>(login.length() + 1, ADM_LOGIN_LEN), &ctx);
307 if (!WriteAll(sock, loginZ, ADM_LOGIN_LEN))
308     {
309     errorMsg = SEND_LOGIN_ERROR;
310     return st_send_fail;
311     }
312
313 return st_ok;
314 }
315 //---------------------------------------------------------------------------
316 int NETTRANSACT::RxLoginSAnswer()
317 {
318 char buffer[sizeof(OK_LOGINS) + 1];
319
320 if (!ReadAll(sock, buffer, strlen(OK_LOGINS)))
321     {
322     printf("Receive secret login answer error: '%s'\n", strerror(errno));
323     errorMsg = RECV_LOGIN_ANSWER_ERROR;
324     return st_recv_fail;
325     }
326
327 if (strncmp(OK_LOGINS, buffer, strlen(OK_LOGINS)) == 0)
328     return st_ok;
329
330 if (strncmp(ERR_LOGINS, buffer, strlen(ERR_LOGINS)) == 0)
331     {
332     errorMsg = INCORRECT_LOGIN;
333     return st_logins_err;
334     }
335 else
336     {
337     errorMsg = UNKNOWN_ERROR;
338     return st_unknown_err;
339     }
340 }
341 //---------------------------------------------------------------------------
342 int NETTRANSACT::TxData(const std::string & text)
343 {
344 STG::ENCRYPT_STREAM stream(password, TxCrypto, this);
345 stream.Put(text.c_str(), text.length() + 1, true);
346 if (!stream.IsOk())
347     {
348     errorMsg = SEND_DATA_ERROR;
349     return st_send_fail;
350     }
351
352 return st_ok;
353 }
354 //---------------------------------------------------------------------------
355 int NETTRANSACT::RxDataAnswer(CALLBACK callback, void * data)
356 {
357 ReadState state = {false, callback, data, this};
358 STG::DECRYPT_STREAM stream(password, RxCrypto, &state);
359 while (!state.final)
360     {
361     char buffer[1024];
362     ssize_t res = read(sock, buffer, sizeof(buffer));
363     if (res < 0)
364         {
365         printf("Receive data error: '%s'\n", strerror(errno));
366         errorMsg = RECV_DATA_ANSWER_ERROR;
367         return st_recv_fail;
368         }
369     stream.Put(buffer, res, res == 0);
370     if (!stream.IsOk())
371         return st_xml_parse_error;
372     }
373
374 return st_ok;
375 }
376 //---------------------------------------------------------------------------
377 bool NETTRANSACT::TxCrypto(const void * block, size_t size, void * data)
378 {
379 assert(data != NULL);
380 NETTRANSACT & nt = *static_cast<NETTRANSACT *>(data);
381 if (!WriteAll(nt.sock, block, size))
382     return false;
383 return true;
384 }
385 //---------------------------------------------------------------------------
386 bool NETTRANSACT::RxCrypto(const void * block, size_t size, void * data)
387 {
388 assert(data != NULL);
389 ReadState & state = *static_cast<ReadState *>(data);
390
391 const char * buffer = static_cast<const char *>(block);
392 for (size_t pos = 0; pos < size; ++pos)
393     if (buffer[pos] == 0)
394         {
395         state.final = true;
396         size = pos; // Adjust string size
397         }
398
399 if (state.callback)
400     if (!state.callback(std::string(buffer, size), state.final, state.callbackData))
401         return false;
402
403 return true;
404 }