|
1 /*************************************************************************** |
|
2 sockethandler.cpp - description |
|
3 ------------------- |
|
4 begin : Sa Feb 12 2005 |
|
5 copyright : (C) 2005 by Christian Hilgers |
|
6 email : christian@hilgers.ag |
|
7 ***************************************************************************/ |
|
8 |
|
9 /*************************************************************************** |
|
10 * * |
|
11 * This program is free software; you can redistribute it and/or modify * |
|
12 * it under the terms of the GNU General Public License as published by * |
|
13 * the Free Software Foundation; either version 2 of the License, or * |
|
14 * (at your option) any later version. * |
|
15 * * |
|
16 ***************************************************************************/ |
|
17 |
|
18 #include "sockethandler.h" |
|
19 #include "logfile.h" |
|
20 #include "params.h" |
|
21 #include "utils.h" |
|
22 |
|
23 #include <netdb.h> |
|
24 #include <unistd.h> |
|
25 #include <fcntl.h> |
|
26 #include <errno.h> |
|
27 |
|
28 #ifndef INADDR_NONE |
|
29 #define INADDR_NONE ((unsigned long) -1) |
|
30 #endif |
|
31 #ifndef AF_LOCAL |
|
32 #define AF_LOCAL AF_UNIX |
|
33 #endif |
|
34 |
|
35 //Create Server Socket |
|
36 bool SocketHandler::CreateServer( int portT, in_addr_t bind_addrT ) |
|
37 { |
|
38 int i = 1; |
|
39 |
|
40 my_s_addr.sin_addr.s_addr = bind_addrT; |
|
41 my_s_addr.sin_port = htons(portT); |
|
42 |
|
43 if ( (sock_fd = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) |
|
44 { |
|
45 LogFile::ErrorMessage("socket() failed: %s\n", strerror(errno)); |
|
46 return false; |
|
47 } |
|
48 |
|
49 // Enable re-use Socket |
|
50 if ( setsockopt( sock_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i) ) < 0 ) |
|
51 { |
|
52 LogFile::ErrorMessage("setsockopt() failed: %s\n", strerror(errno)); |
|
53 return false; |
|
54 } |
|
55 |
|
56 if ( ::bind( sock_fd, (struct sockaddr *) &my_s_addr, sizeof(my_s_addr) ) < 0 ) |
|
57 { |
|
58 LogFile::ErrorMessage("bind() failed: %s\n", strerror(errno)); |
|
59 return false; |
|
60 } |
|
61 |
|
62 if ( ::listen( sock_fd, MAXCONNECTIONS ) < 0 ) |
|
63 { |
|
64 LogFile::ErrorMessage("listen() failed: %s\n", strerror(errno)); |
|
65 return false; |
|
66 } |
|
67 |
|
68 return true; |
|
69 } |
|
70 |
|
71 |
|
72 //Create Server Socket, convert ASCII address representation into binary one |
|
73 bool SocketHandler::CreateServer( int portT, string bind_addrT ) |
|
74 { |
|
75 if ( bind_addrT == "" ) |
|
76 { |
|
77 return CreateServer( portT, INADDR_ANY ); |
|
78 } |
|
79 else |
|
80 { |
|
81 return CreateServer( portT, inet_addr( Params::GetConfigString("BIND_ADDRESS").c_str() ) ); |
|
82 } |
|
83 } |
|
84 |
|
85 |
|
86 //Connect to Server |
|
87 bool SocketHandler::ConnectToServer() |
|
88 { |
|
89 if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) |
|
90 { |
|
91 LogFile::ErrorMessage("ConnectToServer socket() failed: %s\n", strerror(errno)); |
|
92 return false; |
|
93 } |
|
94 |
|
95 if ( source_address != "" ) |
|
96 { |
|
97 if ( ::bind(sock_fd, (struct sockaddr *) &l_addr, sizeof(l_addr)) < 0 ) |
|
98 { |
|
99 LogFile::ErrorMessage("ConnectoToServer bind() failed: %s\n", strerror(errno)); |
|
100 Close(); |
|
101 return false; |
|
102 } |
|
103 } |
|
104 |
|
105 int flags, ret; |
|
106 |
|
107 //Nonblocking connect to get a proper timeout |
|
108 while ( (flags = fcntl(sock_fd, F_GETFL, 0)) < 0 ) |
|
109 { |
|
110 if (errno == EINTR) continue; |
|
111 |
|
112 LogFile::ErrorMessage("ConnectToServer fcntl() get failed: %s\n", strerror(errno)); |
|
113 Close(); |
|
114 return false; |
|
115 } |
|
116 while ( fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK) < 0 ) |
|
117 { |
|
118 if (errno == EINTR) continue; |
|
119 |
|
120 LogFile::ErrorMessage("ConnectToServer fcntl() O_NONBLOCK failed: %s\n", strerror(errno)); |
|
121 Close(); |
|
122 return false; |
|
123 } |
|
124 |
|
125 while ( (ret = ::connect(sock_fd, (struct sockaddr *) &my_s_addr, sizeof(my_s_addr))) < 0 ) |
|
126 { |
|
127 if (errno == EINTR) continue; |
|
128 |
|
129 if (errno != EINPROGRESS) |
|
130 { |
|
131 if (errno != EINVAL) LogFile::ErrorMessage("connect() failed: %s\n", strerror(errno)); |
|
132 Close(); |
|
133 return false; |
|
134 } |
|
135 |
|
136 break; |
|
137 } |
|
138 |
|
139 if ( ret != 0 ) |
|
140 { |
|
141 FD_ZERO(&checkfd); |
|
142 FD_SET(sock_fd,&checkfd); |
|
143 wset = checkfd; |
|
144 |
|
145 Timeout.tv_sec = CONNTIMEOUT; |
|
146 Timeout.tv_usec = 0; |
|
147 |
|
148 ret = select_eintr(sock_fd+1, &checkfd, &wset, NULL, &Timeout); |
|
149 |
|
150 if ( ret <= 0 ) |
|
151 { |
|
152 Close(); |
|
153 return false; |
|
154 } |
|
155 |
|
156 addr_len = sizeof(peer_addr); |
|
157 |
|
158 if ( getpeername(sock_fd, (struct sockaddr *) &peer_addr, (socklen_t *) &addr_len) < 0 ) |
|
159 { |
|
160 Close(); |
|
161 return false; |
|
162 } |
|
163 } |
|
164 |
|
165 while ( fcntl(sock_fd, F_SETFL, flags) < 0 ) |
|
166 { |
|
167 if (errno == EINTR) continue; |
|
168 |
|
169 LogFile::ErrorMessage("ConnectToServer fcntl() set failed: %s\n", strerror(errno)); |
|
170 Close(); |
|
171 return false; |
|
172 } |
|
173 |
|
174 return true; |
|
175 } |
|
176 |
|
177 |
|
178 bool SocketHandler::ConnectToSocket( string SocketPath, int retry ) |
|
179 { |
|
180 strncpy(my_u_addr.sun_path, SocketPath.c_str(), sizeof(my_u_addr.sun_path)-1); |
|
181 |
|
182 if ( (sock_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0 ) |
|
183 { |
|
184 LogFile::ErrorMessage("ConnectToSocket socket() failed: %s\n", strerror(errno)); |
|
185 return false; |
|
186 } |
|
187 |
|
188 int tries = 0; |
|
189 int ret; |
|
190 |
|
191 for(;;) |
|
192 { |
|
193 while ( (ret = ::connect(sock_fd, (struct sockaddr *) &my_u_addr, sizeof(my_u_addr))) < 0 ) |
|
194 { |
|
195 if (errno == EINTR) continue; |
|
196 |
|
197 if (errno != ENOENT) LogFile::ErrorMessage("ConnectToSocket connect() failed: %s\n", strerror(errno)); |
|
198 break; |
|
199 } |
|
200 |
|
201 //Success? |
|
202 if ( ret == 0 ) return true; |
|
203 |
|
204 //All retried? |
|
205 if ( ++tries > retry ) break; |
|
206 |
|
207 //Try again in one second |
|
208 sleep(1); |
|
209 continue; |
|
210 } |
|
211 |
|
212 Close(); |
|
213 return false; |
|
214 } |
|
215 |
|
216 |
|
217 //Accept Client |
|
218 bool SocketHandler::AcceptClient( SocketHandler &accept_socketT ) |
|
219 { |
|
220 addr_len = sizeof(my_s_addr); |
|
221 |
|
222 while ((accept_socketT.sock_fd = ::accept(sock_fd, (sockaddr *) &my_s_addr, (socklen_t *) &addr_len)) < 0) |
|
223 { |
|
224 if (errno == EINTR) continue; |
|
225 |
|
226 LogFile::ErrorMessage("accept() failed: %s\n", strerror(errno)); |
|
227 |
|
228 return false; |
|
229 } |
|
230 |
|
231 //Save IP to ToBrowser |
|
232 accept_socketT.my_s_addr = my_s_addr; |
|
233 |
|
234 return true; |
|
235 } |
|
236 |
|
237 //Send String |
|
238 bool SocketHandler::Send( const char *sock_outT, int len ) |
|
239 { |
|
240 int total_sent = 0; |
|
241 int ret, buffer_count; |
|
242 |
|
243 do |
|
244 { |
|
245 Timeout.tv_sec = SENDTIMEOUT; |
|
246 Timeout.tv_usec = 0; |
|
247 FD_ZERO(&checkfd); |
|
248 FD_SET(sock_fd,&checkfd); |
|
249 |
|
250 ret = select_eintr(sock_fd+1, NULL, &checkfd, NULL, &Timeout); |
|
251 |
|
252 if (ret <= 0) |
|
253 { |
|
254 return false; |
|
255 } |
|
256 |
|
257 while ((buffer_count = ::send(sock_fd, sock_outT + total_sent, len - total_sent, 0)) < 0) |
|
258 { |
|
259 if (errno == EINTR) continue; |
|
260 |
|
261 return false; |
|
262 } |
|
263 if (buffer_count == 0) |
|
264 { |
|
265 return false; |
|
266 } |
|
267 |
|
268 total_sent += buffer_count; |
|
269 } |
|
270 while (total_sent < len); |
|
271 |
|
272 return true; |
|
273 } |
|
274 |
|
275 //Send String |
|
276 bool SocketHandler::Send( string &sock_outT ) |
|
277 { |
|
278 int total_sent = 0; |
|
279 int len = sock_outT.size(); |
|
280 int ret, buffer_count; |
|
281 |
|
282 do |
|
283 { |
|
284 Timeout.tv_sec = SENDTIMEOUT; |
|
285 Timeout.tv_usec = 0; |
|
286 FD_ZERO(&checkfd); |
|
287 FD_SET(sock_fd,&checkfd); |
|
288 |
|
289 ret = select_eintr(sock_fd+1, NULL, &checkfd, NULL, &Timeout); |
|
290 |
|
291 if (ret <= 0) |
|
292 { |
|
293 return false; |
|
294 } |
|
295 |
|
296 while ((buffer_count = ::send(sock_fd, sock_outT.substr(total_sent).c_str(), len - total_sent, 0)) < 0) |
|
297 { |
|
298 if (errno == EINTR) continue; |
|
299 |
|
300 return false; |
|
301 } |
|
302 if (buffer_count == 0) |
|
303 { |
|
304 return false; |
|
305 } |
|
306 |
|
307 total_sent += buffer_count; |
|
308 } |
|
309 while (total_sent < len); |
|
310 |
|
311 return true; |
|
312 } |
|
313 |
|
314 |
|
315 //Receive String - Maximal MAXRECV |
|
316 //sock_del = false : Do not delete Data from Socket |
|
317 ssize_t SocketHandler::Recv( string &sock_inT, bool sock_delT, int timeout ) |
|
318 { |
|
319 if ( RecvBuf.size() > 0 ) |
|
320 { |
|
321 sock_inT.append( RecvBuf ); |
|
322 |
|
323 if ( sock_delT == true ) |
|
324 { |
|
325 ssize_t tempsize = RecvBuf.size(); |
|
326 |
|
327 RecvBuf = ""; |
|
328 |
|
329 return tempsize; |
|
330 } |
|
331 |
|
332 return RecvBuf.size(); |
|
333 } |
|
334 |
|
335 char buffer[MAXRECV+1]; |
|
336 ssize_t buffer_count; |
|
337 int ret; |
|
338 |
|
339 if ( timeout != -1 ) |
|
340 { |
|
341 Timeout.tv_sec = timeout; |
|
342 } |
|
343 else |
|
344 { |
|
345 Timeout.tv_sec = RECVTIMEOUT; |
|
346 } |
|
347 Timeout.tv_usec = 0; |
|
348 |
|
349 FD_ZERO(&checkfd); |
|
350 FD_SET(sock_fd,&checkfd); |
|
351 |
|
352 ret = select_eintr(sock_fd+1, &checkfd, NULL, NULL, &Timeout); |
|
353 |
|
354 if (ret <= 0) |
|
355 { |
|
356 return -1; |
|
357 } |
|
358 |
|
359 while ((buffer_count = ::recv(sock_fd, buffer, MAXRECV, 0)) < 0) |
|
360 { |
|
361 if (errno == EINTR) continue; |
|
362 |
|
363 return -1; |
|
364 } |
|
365 |
|
366 if ( sock_delT == false ) |
|
367 { |
|
368 RecvBuf.append( buffer, buffer_count ); |
|
369 } |
|
370 |
|
371 if ( buffer_count == 0 ) |
|
372 { |
|
373 return 0; |
|
374 } |
|
375 |
|
376 sock_inT.append( buffer, buffer_count ); |
|
377 |
|
378 return buffer_count; |
|
379 } |
|
380 |
|
381 |
|
382 //Receive String of length sock_length |
|
383 bool SocketHandler::RecvLength( string &sock_inT, unsigned int sock_lengthT ) |
|
384 { |
|
385 if ( RecvBuf.size() >= sock_lengthT ) |
|
386 { |
|
387 sock_inT.append( RecvBuf.substr( 0, sock_lengthT ) ); |
|
388 |
|
389 RecvBuf.erase( 0, sock_lengthT ); |
|
390 |
|
391 return true; |
|
392 } |
|
393 |
|
394 char buffer[MAXRECV+1]; |
|
395 ssize_t buffer_count; |
|
396 unsigned int received = 0; |
|
397 |
|
398 if ( RecvBuf.size() > 0 ) |
|
399 { |
|
400 sock_inT.append( RecvBuf ); |
|
401 received += RecvBuf.size(); |
|
402 |
|
403 RecvBuf = ""; |
|
404 } |
|
405 |
|
406 for(;;) |
|
407 { |
|
408 Timeout.tv_sec = RECVTIMEOUT; |
|
409 Timeout.tv_usec = 0; |
|
410 |
|
411 FD_ZERO(&checkfd); |
|
412 FD_SET(sock_fd,&checkfd); |
|
413 |
|
414 int ret = select_eintr(sock_fd+1, &checkfd, NULL, NULL, &Timeout); |
|
415 |
|
416 if ( ret <= 0 ) |
|
417 { |
|
418 return false; |
|
419 } |
|
420 |
|
421 while ((buffer_count = ::recv(sock_fd, buffer, MAXRECV, 0)) < 0 && errno == EINTR); |
|
422 |
|
423 if ( buffer_count < 1 ) |
|
424 { |
|
425 return false; |
|
426 } |
|
427 |
|
428 if ( received + buffer_count >= sock_lengthT ) |
|
429 { |
|
430 string Rest; |
|
431 Rest.append( buffer, buffer_count ); |
|
432 |
|
433 unsigned int needed = sock_lengthT - received; |
|
434 |
|
435 sock_inT.append( Rest.substr( 0, needed ) ); |
|
436 if ( Rest.size() > needed ) RecvBuf.append( Rest.substr( needed ) ); |
|
437 |
|
438 return true; |
|
439 } |
|
440 |
|
441 sock_inT.append( buffer, buffer_count ); |
|
442 received += buffer_count; |
|
443 } |
|
444 |
|
445 return true; |
|
446 } |
|
447 |
|
448 |
|
449 //Wait and get something from socket until separator |
|
450 bool SocketHandler::GetLine( string &lineT, string separator, int timeout ) |
|
451 { |
|
452 lineT = ""; |
|
453 |
|
454 string TempLine; |
|
455 string::size_type Position; |
|
456 |
|
457 do |
|
458 { |
|
459 if ( Recv( TempLine, false, timeout ) == false ) |
|
460 { |
|
461 return false; |
|
462 } |
|
463 } |
|
464 while ( (Position = TempLine.find( separator )) == string::npos ); |
|
465 |
|
466 TempLine = ""; |
|
467 |
|
468 if ( RecvLength( TempLine, Position + separator.size() ) == false ) |
|
469 { |
|
470 return false; |
|
471 } |
|
472 |
|
473 lineT = TempLine.erase( Position ); |
|
474 |
|
475 return true; |
|
476 } |
|
477 |
|
478 |
|
479 //Resolve and set hostname/port for connecting |
|
480 bool SocketHandler::SetDomainAndPort( string domainT, int portT ) |
|
481 { |
|
482 if ( domainT == "" ) return false; |
|
483 if ( portT < 1 || portT > 65536 ) return false; |
|
484 |
|
485 int domlen = domainT.length(); |
|
486 |
|
487 if (domlen > 250) domainT = domainT.substr(0, 250); |
|
488 my_s_addr.sin_port = htons(portT); |
|
489 |
|
490 //IP? |
|
491 if ( domlen >= 7 && domlen <= 15 && domainT.find_first_not_of("0123456789.") == string::npos ) |
|
492 { |
|
493 LastHost = ""; |
|
494 if ( inet_aton( domainT.c_str(), &my_s_addr.sin_addr ) != 0 ) return true; |
|
495 return false; |
|
496 } |
|
497 |
|
498 //Same host as last time, use next IP |
|
499 if ( server && LastHost == domainT ) |
|
500 { |
|
501 if ( ips == 1 ) return true; |
|
502 |
|
503 if ( ++ip_count == ips ) ip_count = 0; |
|
504 memcpy((char *) &my_s_addr.sin_addr.s_addr, server->h_addr_list[ip_count], server->h_length); |
|
505 |
|
506 return true; |
|
507 } |
|
508 |
|
509 //Resolve host |
|
510 if ( (server = gethostbyname( domainT.c_str() )) ) |
|
511 { |
|
512 //Count IPs |
|
513 for ( ips = 0; server->h_addr_list[ips] != NULL && server->h_addrtype == AF_INET && ips != 16; ips++ ); |
|
514 |
|
515 if ( !ips ) return false; |
|
516 |
|
517 memcpy((char *) &my_s_addr.sin_addr.s_addr, server->h_addr_list[0], server->h_length); |
|
518 |
|
519 ip_count = 0; |
|
520 LastHost = domainT; |
|
521 |
|
522 return true; |
|
523 } |
|
524 |
|
525 LastHost = ""; |
|
526 return false; |
|
527 } |
|
528 |
|
529 int SocketHandler::IPCount() |
|
530 { |
|
531 return ips; |
|
532 } |
|
533 |
|
534 string SocketHandler::GetIP() |
|
535 { |
|
536 string ip = inet_ntoa(my_s_addr.sin_addr); |
|
537 return ip; |
|
538 } |
|
539 |
|
540 bool SocketHandler::CheckForData( int timeout ) |
|
541 { |
|
542 if ( RecvBuf.size() > 0 ) |
|
543 { |
|
544 return true; |
|
545 } |
|
546 |
|
547 int ret; |
|
548 |
|
549 Timeout.tv_sec = timeout; |
|
550 Timeout.tv_usec = 0; |
|
551 |
|
552 FD_ZERO(&checkfd); |
|
553 FD_SET(sock_fd,&checkfd); |
|
554 |
|
555 ret = select_eintr(sock_fd+1, &checkfd, NULL, NULL, &Timeout); |
|
556 |
|
557 if (ret <= 0) |
|
558 { |
|
559 return false; |
|
560 } |
|
561 |
|
562 return true; |
|
563 } |
|
564 |
|
565 |
|
566 #ifdef SSLTUNNEL |
|
567 int SocketHandler::CheckForSSLData( int sockBrowser, int sockServer ) |
|
568 { |
|
569 fd_set readfd; |
|
570 int fds; |
|
571 |
|
572 FD_ZERO(&readfd); |
|
573 FD_SET(sockBrowser,&readfd); |
|
574 FD_SET(sockServer,&readfd); |
|
575 |
|
576 if ( sockBrowser > sockServer ) |
|
577 { |
|
578 fds = sockBrowser; |
|
579 } |
|
580 else |
|
581 { |
|
582 fds = sockServer; |
|
583 } |
|
584 |
|
585 Timeout.tv_sec = 20; |
|
586 Timeout.tv_usec = 0; |
|
587 |
|
588 int ret = select_eintr(fds+1, &readfd, NULL, NULL, &Timeout); |
|
589 |
|
590 if (ret <= 0) return 0; |
|
591 |
|
592 if (FD_ISSET(sockBrowser,&readfd)) return 1; |
|
593 |
|
594 return 2; |
|
595 } |
|
596 #endif |
|
597 |
|
598 |
|
599 void SocketHandler::Close() |
|
600 { |
|
601 //Clear receive buffer |
|
602 RecvBuf = ""; |
|
603 |
|
604 //Check that we have a real fd |
|
605 if ( sock_fd > -1 ) |
|
606 { |
|
607 while ( ::close(sock_fd) < 0 ) |
|
608 { |
|
609 if (errno == EINTR) continue; |
|
610 if (errno == EBADF) break; |
|
611 |
|
612 //IO error? |
|
613 LogFile::ErrorMessage("close() failed: %s\n", strerror(errno)); |
|
614 } |
|
615 |
|
616 //Mark socket unused |
|
617 sock_fd = -1; |
|
618 } |
|
619 } |
|
620 |
|
621 |
|
622 //Constructor |
|
623 SocketHandler::SocketHandler() |
|
624 { |
|
625 memset(&my_s_addr, 0, sizeof(my_s_addr)); |
|
626 my_s_addr.sin_family = AF_INET; |
|
627 |
|
628 memset(&my_u_addr, 0, sizeof(my_u_addr)); |
|
629 my_u_addr.sun_family = AF_LOCAL; |
|
630 |
|
631 ip_count = 0; |
|
632 ips = 0; |
|
633 |
|
634 //No socket exists yet |
|
635 sock_fd = -1; |
|
636 |
|
637 source_address = Params::GetConfigString("SOURCE_ADDRESS"); |
|
638 |
|
639 if ( source_address != "" ) |
|
640 { |
|
641 l_addr.sin_family = AF_INET; |
|
642 l_addr.sin_port = htons(0); |
|
643 l_addr.sin_addr.s_addr = inet_addr( source_address.c_str() ); |
|
644 } |
|
645 |
|
646 RecvBuf.reserve(1500); |
|
647 RecvBuf = ""; |
|
648 } |
|
649 |
|
650 |
|
651 //Destructor |
|
652 SocketHandler::~SocketHandler() |
|
653 { |
|
654 } |