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