]> git.stg.codes - stg.git/blob - stglibs/srvconf.lib/netunit.cpp
Fixed tests.
[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
27 #include <algorithm> // std::min
28
29 #include <cstdio>
30 #include <cerrno>
31 #include <cstring>
32
33 #include <netdb.h>
34 #include <arpa/inet.h>
35 #include <unistd.h>
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40
41 using namespace STG;
42
43 namespace
44 {
45
46 const std::string::size_type MAX_XML_CHUNK_LENGTH = 2048;
47
48 }
49
50 //---------------------------------------------------------------------------
51
52 #define SEND_DATA_ERROR             "Send data error!"
53 #define RECV_DATA_ANSWER_ERROR      "Recv data answer error!"
54 #define UNKNOWN_ERROR               "Unknown error!"
55 #define CONNECT_FAILED              "Connect failed!"
56 #define BIND_FAILED                 "Bind failed!"
57 #define INCORRECT_LOGIN             "Incorrect login!"
58 #define INCORRECT_HEADER            "Incorrect header!"
59 #define SEND_LOGIN_ERROR            "Send login error!"
60 #define RECV_LOGIN_ANSWER_ERROR     "Recv login answer error!"
61 #define CREATE_SOCKET_ERROR         "Create socket failed!"
62 #define WSASTARTUP_FAILED           "WSAStartup failed!"
63 #define SEND_HEADER_ERROR           "Send header error!"
64 #define RECV_HEADER_ANSWER_ERROR    "Recv header answer error!"
65
66 //---------------------------------------------------------------------------
67 NETTRANSACT::NETTRANSACT(const std::string & s, uint16_t p,
68                          const std::string & l, const std::string & pwd)
69     : server(s),
70       port(p),
71       localPort(0),
72       login(l),
73       password(pwd),
74       outerSocket(-1)
75 {
76 }
77 //---------------------------------------------------------------------------
78 NETTRANSACT::NETTRANSACT(const std::string & s, uint16_t p,
79                          const std::string & la, uint16_t lp,
80                          const std::string & l, const std::string & pwd)
81     : server(s),
82       port(p),
83       localAddress(la),
84       localPort(lp),
85       login(l),
86       password(pwd),
87       outerSocket(-1)
88 {
89 }
90 //---------------------------------------------------------------------------
91 int NETTRANSACT::Connect()
92 {
93 outerSocket = socket(PF_INET, SOCK_STREAM, 0);
94 if (outerSocket < 0)
95     {
96     errorMsg = CREATE_SOCKET_ERROR;
97     return st_conn_fail;
98     }
99
100 if (!localAddress.empty())
101     {
102     if (localPort == 0)
103         localPort = port;
104
105     unsigned long ip = inet_addr(localAddress.c_str());
106
107     if (ip == INADDR_NONE)
108         {
109         struct hostent * phe = gethostbyname(localAddress.c_str());
110         if (phe == NULL)
111             {
112             errorMsg = "DNS error.\nCan not reslove " + localAddress;
113             return st_dns_err;
114             }
115
116         struct hostent he;
117         memcpy(&he, phe, sizeof(he));
118         ip = *((long *)he.h_addr_list[0]);
119         }
120
121     struct sockaddr_in localAddr;
122     memset(&localAddr, 0, sizeof(localAddr));
123     localAddr.sin_family = AF_INET;
124     localAddr.sin_port = htons(localPort);
125     localAddr.sin_addr.s_addr = ip;
126
127     if (bind(outerSocket, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0)
128         {
129         errorMsg = BIND_FAILED;
130         close(outerSocket);
131         return st_conn_fail;
132         }
133     }
134
135 struct sockaddr_in outerAddr;
136 memset(&outerAddr, 0, sizeof(outerAddr));
137
138 unsigned long ip = inet_addr(server.c_str());
139
140 if (ip == INADDR_NONE)
141     {
142     struct hostent * phe = gethostbyname(server.c_str());
143     if (phe == NULL)
144         {
145         errorMsg = "DNS error.\nCan not reslove " + server;
146         return st_dns_err;
147         }
148
149     struct hostent he;
150     memcpy(&he, phe, sizeof(he));
151     ip = *((long *)he.h_addr_list[0]);
152     }
153
154 outerAddr.sin_family = AF_INET;
155 outerAddr.sin_port = htons(port);
156 outerAddr.sin_addr.s_addr = ip;
157
158 if (connect(outerSocket, (struct sockaddr *)&outerAddr, sizeof(outerAddr)) < 0)
159     {
160     errorMsg = CONNECT_FAILED;
161     close(outerSocket);
162     return st_conn_fail;
163     }
164
165 return st_ok;
166 }
167 //---------------------------------------------------------------------------
168 void NETTRANSACT::Disconnect()
169 {
170 close(outerSocket);
171 }
172 //---------------------------------------------------------------------------
173 int NETTRANSACT::Transact(const std::string & request, CALLBACK callback, void * data)
174 {
175 int ret;
176 if ((ret = TxHeader()) != st_ok)
177     {
178     Disconnect();
179     return ret;
180     }
181
182 if ((ret = RxHeaderAnswer()) != st_ok)
183     {
184     Disconnect();
185     return ret;
186     }
187
188 if ((ret = TxLogin()) != st_ok)
189     {
190     Disconnect();
191     return ret;
192     }
193
194 if ((ret = RxLoginAnswer()) != st_ok)
195     {
196     Disconnect();
197     return ret;
198     }
199
200 if ((ret = TxLoginS()) != st_ok)
201     {
202     Disconnect();
203     return ret;
204     }
205
206 if ((ret = RxLoginSAnswer()) != st_ok)
207     {
208     Disconnect();
209     return ret;
210     }
211
212 if ((ret = TxData(request)) != st_ok)
213     {
214     Disconnect();
215     return ret;
216     }
217
218 if ((ret = RxDataAnswer(callback, data)) != st_ok)
219     {
220     Disconnect();
221     return ret;
222     }
223
224 return st_ok;
225 }
226 //---------------------------------------------------------------------------
227 int NETTRANSACT::TxHeader()
228 {
229 if (send(outerSocket, STG_HEADER, strlen(STG_HEADER), 0) <= 0)
230     {
231     errorMsg = SEND_HEADER_ERROR;
232     return st_send_fail;
233     }
234
235 return st_ok;
236 }
237 //---------------------------------------------------------------------------
238 int NETTRANSACT::RxHeaderAnswer()
239 {
240 char buffer[sizeof(STG_HEADER) + 1];
241
242 if (recv(outerSocket, buffer, strlen(OK_HEADER), 0) <= 0)
243     {
244     printf("Receive header answer error: '%s'\n", strerror(errno));
245     errorMsg = RECV_HEADER_ANSWER_ERROR;
246     return st_recv_fail;
247     }
248
249 if (strncmp(OK_HEADER, buffer, strlen(OK_HEADER)) == 0)
250     {
251     return st_ok;
252     }
253 else
254     {
255     if (strncmp(ERR_HEADER, buffer, strlen(ERR_HEADER)) == 0)
256         {
257         errorMsg = INCORRECT_HEADER;
258         return st_header_err;
259         }
260     else
261         {
262         errorMsg = UNKNOWN_ERROR;
263         return st_unknown_err;
264         }
265     }
266 }
267 //---------------------------------------------------------------------------
268 int NETTRANSACT::TxLogin()
269 {
270 char loginZ[ADM_LOGIN_LEN];
271 memset(loginZ, 0, ADM_LOGIN_LEN);
272 strncpy(loginZ, login.c_str(), ADM_LOGIN_LEN);
273
274 if (send(outerSocket, loginZ, ADM_LOGIN_LEN, 0) <= 0)
275     {
276     errorMsg = SEND_LOGIN_ERROR;
277     return st_send_fail;
278     }
279
280 return st_ok;
281 }
282 //---------------------------------------------------------------------------
283 int NETTRANSACT::RxLoginAnswer()
284 {
285 char buffer[sizeof(OK_LOGIN) + 1];
286
287 if (recv(outerSocket, buffer, strlen(OK_LOGIN), 0) <= 0)
288     {
289     printf("Receive login answer error: '%s'\n", strerror(errno));
290     errorMsg = RECV_LOGIN_ANSWER_ERROR;
291     return st_recv_fail;
292     }
293
294 if (strncmp(OK_LOGIN, buffer, strlen(OK_LOGIN)) == 0)
295     {
296     return st_ok;
297     }
298 else
299     {
300     if (strncmp(ERR_LOGIN, buffer, strlen(ERR_LOGIN)) == 0)
301         {
302         errorMsg = INCORRECT_LOGIN;
303         return st_login_err;
304         }
305     else
306         {
307         errorMsg = UNKNOWN_ERROR;
308         return st_unknown_err;
309         }
310     }
311 }
312 //---------------------------------------------------------------------------
313 int NETTRANSACT::TxLoginS()
314 {
315 char loginZ[ADM_LOGIN_LEN];
316 memset(loginZ, 0, ADM_LOGIN_LEN);
317 strncpy(loginZ, login.c_str(), ADM_LOGIN_LEN);
318
319 BLOWFISH_CTX ctx;
320 EnDecodeInit(password.c_str(), PASSWD_LEN, &ctx);
321
322 for (int j = 0; j < ADM_LOGIN_LEN / ENC_MSG_LEN; j++)
323     {
324     char ct[ENC_MSG_LEN];
325     EncodeString(ct, loginZ + j * ENC_MSG_LEN, &ctx);
326     if (send(outerSocket, ct, ENC_MSG_LEN, 0) <= 0)
327         {
328         errorMsg = SEND_LOGIN_ERROR;
329         return st_send_fail;
330         }
331     }
332
333 return st_ok;
334 }
335 //---------------------------------------------------------------------------
336 int NETTRANSACT::RxLoginSAnswer()
337 {
338 char buffer[sizeof(OK_LOGINS) + 1];
339
340 if (recv(outerSocket, buffer, strlen(OK_LOGINS), 0) <= 0)
341     {
342     printf("Receive secret login answer error: '%s'\n", strerror(errno));
343     errorMsg = RECV_LOGIN_ANSWER_ERROR;
344     return st_recv_fail;
345     }
346
347 if (strncmp(OK_LOGINS, buffer, strlen(OK_LOGINS)) == 0)
348     {
349     return st_ok;
350     }
351 else
352     {
353     if (strncmp(ERR_LOGINS, buffer, strlen(ERR_LOGINS)) == 0)
354         {
355         errorMsg = INCORRECT_LOGIN;
356         return st_logins_err;
357         }
358     else
359         {
360         errorMsg = UNKNOWN_ERROR;
361         return st_unknown_err;
362         }
363     }
364 }
365 //---------------------------------------------------------------------------
366 int NETTRANSACT::TxData(const std::string & text)
367 {
368 BLOWFISH_CTX ctx;
369 EnDecodeInit(password.c_str(), PASSWD_LEN, &ctx);
370
371 size_t pos = 0;
372 while (pos < text.size())
373     {
374     char textZ[ENC_MSG_LEN];
375     if (text.size() - pos < ENC_MSG_LEN)
376         memset(textZ, 0, ENC_MSG_LEN);
377     strncpy(textZ, text.c_str() + pos, std::min(ENC_MSG_LEN, (int)(text.size() - pos)));
378     char ct[ENC_MSG_LEN];
379     EncodeString(ct, textZ, &ctx);
380     if (send(outerSocket, ct, ENC_MSG_LEN, 0) <= 0)
381         {
382         errorMsg = SEND_DATA_ERROR;
383         return st_send_fail;
384         }
385     pos += ENC_MSG_LEN;
386     }
387
388 return st_ok;
389 }
390 //---------------------------------------------------------------------------
391 int NETTRANSACT::RxDataAnswer(CALLBACK callback, void * data)
392 {
393 BLOWFISH_CTX ctx;
394 EnDecodeInit(password.c_str(), PASSWD_LEN, &ctx);
395
396 std::string chunk;
397 while (true)
398     {
399     char bufferS[ENC_MSG_LEN];
400     size_t toRead = ENC_MSG_LEN;
401     while (toRead > 0)
402         {
403         int ret = recv(outerSocket, &bufferS[ENC_MSG_LEN - toRead], toRead, 0);
404         if (ret <= 0)
405             {
406             printf("Receive data error: '%s'\n", strerror(errno));
407             close(outerSocket);
408             errorMsg = RECV_DATA_ANSWER_ERROR;
409             return st_recv_fail;
410             }
411         toRead -= ret;
412         }
413
414     char buffer[ENC_MSG_LEN];
415     DecodeString(buffer, bufferS, &ctx);
416
417     bool final = false;
418     size_t pos = 0;
419     for (; pos < ENC_MSG_LEN && buffer[pos] != 0; pos++) ;
420     if (pos < ENC_MSG_LEN && buffer[pos] == 0)
421         final = true;
422
423     if (pos > 0)
424         chunk.append(&buffer[0], &buffer[pos]);
425
426     if (chunk.length() > MAX_XML_CHUNK_LENGTH || final)
427         {
428         if (callback)
429             if (!callback(chunk, final, data))
430                 return st_xml_parse_error;
431         chunk.clear();
432         }
433
434     if (final)
435         return st_ok;
436     }
437 }