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