1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 1998-2013 Licq developers <licq-dev@googlegroups.com>
4 *
5 * Licq is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Licq is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Licq; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "icq.h"
21
22 #include <boost/foreach.hpp>
23 #include <cerrno>
24 #include <ctime>
25 #include <unistd.h>
26
27 #include <licq/contactlist/owner.h>
28 #include <licq/contactlist/usermanager.h>
29 #include <licq/event.h>
30 #include <licq/plugin/pluginmanager.h>
31 #include <licq/pluginsignal.h>
32 #include <licq/protocolmanager.h>
33 #include <licq/logging/log.h>
34
35 #include "buffer.h"
36 #include "defines.h"
37 #include "gettext.h"
38 #include "icqprotocolplugin.h"
39 #include "oscarservice.h"
40 #include "owner.h"
41 #include "packet-srv.h"
42 #include "packet-tcp.h"
43 #include "socket.h"
44 #include "user.h"
45
46 #define MAX_CONNECTS 256
47 #define DEBUG_THREADS(x)
48 //#define DEBUG_THREADS(x) gLog.info(x)
49
50 namespace LicqIcq
51 {
52 void* ProcessRunningEvent_Server_tep(void* p);
53 void* ProcessRunningEvent_Client_tep(void* p);
54 void* ReverseConnectToUser_tep(void* v);
55 void* Ping_tep(void* p);
56 void* MonitorSockets_func();
57 void* UpdateUsers_tep(void* p);
58 }
59
60 using namespace LicqIcq;
61 using Licq::gLog;
62 using std::list;
63 using std::string;
64
cleanup_mutex(void * m)65 void cleanup_mutex(void *m)
66 {
67 pthread_mutex_unlock((pthread_mutex_t *)m);
68 }
69
cleanup_socket(void * s)70 void cleanup_socket(void *s)
71 {
72 gSocketManager.DropSocket((Licq::INetSocket *)s);
73 }
74
cleanup_thread_tep(void * t)75 void *cleanup_thread_tep(void *t)
76 {
77 pthread_detach(pthread_self());
78 void *s;
79 pthread_join(*((pthread_t *)t), &s);
80 delete (pthread_t *)t;
81 delete (int *)s;
82 pthread_exit(NULL);
83 }
84
cleanup_thread(void * t)85 void cleanup_thread(void *t)
86 {
87 pthread_t cleanup;
88 pthread_create(&cleanup, NULL, &cleanup_thread_tep, t);
89 }
90
ConnectToServer_tep(void * s)91 void *ConnectToServer_tep(void *s)
92 {
93 *((int *)s) = gIcqProtocol.ConnectToLoginServer();
94 pthread_exit(s);
95 }
96
97
98 /*------------------------------------------------------------------------------
99 * ProcessRunningEvent_tep
100 *
101 * Thread entry point to run an event. First checks to see if the socket for
102 * the given event needs to be connected and calls the relevant connection
103 * function. Then sends the event, retrying after a timeout. If an ack is
104 * received, the thread will be cancelled by the receiving thread.
105 *
106 * The parameter is only used to get the CICQDaemon, the actual event is
107 * now popped off the send queue to prevent packets being sent out of order
108 * which is a severe error with OSCAR.
109 *----------------------------------------------------------------------------*/
ProcessRunningEvent_Server_tep(void *)110 void* LicqIcq::ProcessRunningEvent_Server_tep(void* /* p */)
111 {
112 pthread_detach(pthread_self());
113
114 static unsigned short nNext = 0;
115 static pthread_mutex_t send_mutex = PTHREAD_MUTEX_INITIALIZER;
116
117 /* want to be cancelled immediately so we don't try to derefrence the event
118 after it has been deleted */
119 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
120
121 DEBUG_THREADS("[ProcessRunningEvent_Server_tep] Caught event.\n");
122
123 // Must send packets in sequential order
124 pthread_mutex_lock(&send_mutex);
125 pthread_mutex_lock(&gIcqProtocol.mutex_sendqueue_server);
126
127 list<Licq::Event*>::iterator iter;
128 Licq::Event* e = NULL;
129
130 while (e == NULL)
131 {
132
133 for (iter = gIcqProtocol.m_lxSendQueue_Server.begin();
134 iter != gIcqProtocol.m_lxSendQueue_Server.end(); ++iter)
135 {
136 CSrvPacketTcp* srvPacket = dynamic_cast<CSrvPacketTcp*>((*iter)->m_pPacket);
137 if (srvPacket != NULL && srvPacket->icqChannel() == ICQ_CHNxNEW)
138 {
139 e = *iter;
140 nNext = e->Sequence() + 1;
141 break;
142 }
143
144 if ((*iter)->Sequence() == nNext)
145 {
146 e = *iter;
147 nNext++;
148 break;
149 }
150 }
151
152 if (e == NULL)
153 {
154 bool bEmpty = gIcqProtocol.m_lxSendQueue_Server.empty();
155
156 pthread_mutex_unlock(&gIcqProtocol.mutex_sendqueue_server);
157 pthread_mutex_unlock(&send_mutex);
158
159 if (bEmpty)
160 pthread_exit(NULL);
161
162 struct timeval tv = { 1, 0 };
163 select(0, NULL, NULL, NULL, &tv);
164 pthread_mutex_lock(&send_mutex);
165 pthread_mutex_lock(&gIcqProtocol.mutex_sendqueue_server);
166 }
167 else
168 {
169 gIcqProtocol.m_lxSendQueue_Server.erase(iter);
170
171 if (e->m_bCancelled)
172 {
173 delete e;
174 e = NULL;
175 }
176 }
177 }
178
179 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
180
181 e->thread_send = pthread_self();
182 e->thread_running = true;
183
184 // Done reading the queue now
185 pthread_mutex_unlock(&gIcqProtocol.mutex_sendqueue_server);
186
187 // declared here because pthread_cleanup_push starts a new block
188 Licq::Buffer* buf;
189 bool sent = false;
190 bool bExit = false;
191 string errorStr;
192
193 pthread_cleanup_push(cleanup_mutex, &send_mutex);
194
195 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
196 pthread_testcancel();
197
198 int socket = -1;
199 unsigned short nSequence;
200 Licq::INetSocket *s;
201
202 // Check if the socket is connected
203 if (e->m_nSocketDesc == -1)
204 {
205 // Connect to the server if we are logging on
206 CSrvPacketTcp* srvPacket = dynamic_cast<CSrvPacketTcp*>(e->m_pPacket);
207 if (srvPacket != NULL && srvPacket->icqChannel() == ICQ_CHNxNEW)
208 {
209 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
210 gLog.info(tr("Connecting to login server."));
211
212 pthread_t *t = new pthread_t;
213 int *s = new int;
214 pthread_create(t, NULL, ConnectToServer_tep, s);
215 pthread_cleanup_push(cleanup_thread, t);
216 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
217 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
218 pthread_testcancel();
219 pthread_join(*t, NULL);
220 pthread_cleanup_pop(0);
221 int socket = *s;
222 delete t;
223 delete s;
224
225 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
226 pthread_testcancel();
227
228 e->m_nSocketDesc = socket;
229
230 // Check again, if still -1, fail the event
231 if (e->m_nSocketDesc == -1)
232 {
233 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
234 gLog.info(tr("Connecting to login server failed, failing event."));
235 // we need to initialize the logon time for the next retry
236 gIcqProtocol.m_tLogonTime = time(NULL);
237 gIcqProtocol.m_eStatus = STATUS_OFFLINE_FORCED;
238 gIcqProtocol.m_bLoggingOn = false;
239 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
240 {
241 gIcqProtocol.DoneExtendedEvent(e, Licq::Event::ResultError);
242 gIcqProtocol.ProcessDoneEvent(e);
243 }
244 else
245 {
246 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
247 pthread_testcancel();
248 delete e;
249 }
250 bExit = true;
251 goto exit_server_thread;
252 }
253 }
254 else
255 {
256 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
257 gLog.info(tr("Not connected to server, failing event."));
258 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
259 {
260 gIcqProtocol.DoneExtendedEvent(e, Licq::Event::ResultError);
261 gIcqProtocol.ProcessDoneEvent(e);
262 }
263 else
264 {
265 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
266 pthread_testcancel();
267 delete e;
268 }
269 bExit = true;
270 goto exit_server_thread;
271 }
272 }
273
274 socket = e->m_nSocketDesc;
275 nSequence = e->m_nSequence;
276
277 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
278 // Start sending the event
279 s = gSocketManager.FetchSocket(socket);
280 if (s == NULL)
281 {
282 gLog.warning(tr("Socket not connected or invalid (#%hu)."), nSequence);
283 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
284 {
285 gIcqProtocol.DoneExtendedEvent(e, Licq::Event::ResultError);
286 gIcqProtocol.ProcessDoneEvent(e);
287 }
288 else
289 {
290 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
291 pthread_testcancel();
292 delete e;
293 }
294 bExit = true;
295 goto exit_server_thread;
296 }
297
298 pthread_cleanup_push(cleanup_socket, s);
299
300 pthread_mutex_lock(&gIcqProtocol.mutex_cancelthread);
301
302 // check to make sure we were not cancelled already
303 pthread_cleanup_push(cleanup_mutex, &gIcqProtocol.mutex_cancelthread);
304 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
305 pthread_testcancel();
306 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
307
308 //if we get here then we haven't been cancelled and we won't be
309 //as long as we hold mutex_cancelthread
310
311 buf = e->m_pPacket->Finalize(NULL);
312
313 pthread_mutex_unlock(&gIcqProtocol.mutex_cancelthread);
314 pthread_cleanup_pop(0); //mutex_cancelthread
315
316 sent = s->send(*buf);
317 delete buf;
318
319 if (!sent)
320 errorStr = s->errorStr();
321
322 // We don't close the socket as it should be closed by the server thread
323 gSocketManager.DropSocket(s);
324 pthread_cleanup_pop(0); //socket
325
326 exit_server_thread:
327 pthread_mutex_unlock(&send_mutex);
328 pthread_cleanup_pop(0); //send_mutex
329
330 if (bExit)
331 pthread_exit(NULL);
332
333 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
334 pthread_testcancel();
335
336 if (!sent)
337 {
338 unsigned short nSequence = e->m_nSequence;
339
340 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
341
342 gLog.warning(tr("Error sending event (#%hu): %s."),
343 nSequence, errorStr.c_str());
344
345 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
346 {
347 gIcqProtocol.DoneExtendedEvent(e, Licq::Event::ResultError);
348 gIcqProtocol.ProcessDoneEvent(e);
349 }
350 else
351 {
352 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
353 pthread_testcancel();
354 delete e;
355 }
356 }
357 else
358 {
359 if (e->m_NoAck)
360 {
361 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
362 // send successfully and we don't get an answer from the server
363 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultAcked) != NULL)
364 {
365 gIcqProtocol.DoneExtendedEvent(e, Licq::Event::ResultAcked);
366 gIcqProtocol.ProcessDoneEvent(e);
367 }
368 else
369 {
370 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
371 pthread_testcancel();
372 delete e;
373 }
374 }
375 else
376 {
377 e->thread_running = false;
378 // pthread_exit is not async cancel safe???
379 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
380 }
381 }
382
383 pthread_exit(NULL);
384
385 return NULL;
386 }
387
388
ProcessRunningEvent_Client_tep(void * p)389 void* LicqIcq::ProcessRunningEvent_Client_tep(void *p)
390 {
391 pthread_detach(pthread_self());
392
393 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
394 /* want to be cancelled immediately so we don't try to derefence the event
395 after it has been deleted */
396 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
397
398 DEBUG_THREADS("[ProcessRunningEvent_Client_tep] Caught event.\n");
399
400 Licq::Event* e = (Licq::Event*)p;
401
402 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
403 pthread_testcancel();
404
405 // Check if the socket is connected
406 if (e->m_nSocketDesc == -1)
407 {
408 Licq::UserId userId = e->userId();
409 string id = userId.accountId();
410 CPacketTcp* packetTcp = dynamic_cast<CPacketTcp*>(e->m_pPacket);
411 int channel = (packetTcp != NULL ? packetTcp->channel() : DcSocket::ChannelNormal);
412 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
413
414 unsigned long nVersion;
415 bool directMode;
416 unsigned short nRemotePort;
417 bool bSendIntIp;
418 {
419 UserReadGuard u(userId);
420 if (!u.isLocked())
421 {
422 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
423 gIcqProtocol.ProcessDoneEvent(e);
424 else
425 {
426 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
427 pthread_testcancel();
428 delete e;
429 }
430 pthread_exit(NULL);
431 }
432
433 nVersion = u->Version();
434 directMode = u->directMode();
435 nRemotePort = u->Port();
436 bSendIntIp = u->SendIntIp();
437 }
438
439 unsigned long nIP;
440 unsigned short nLocalPort;
441 {
442 Licq::OwnerReadGuard o(gIcqProtocol.ownerId());
443 nIP = bSendIntIp ? o->IntIp() : o->Ip();
444 nLocalPort = o->Port();
445 }
446
447 int socket = -1;
448 if (!bSendIntIp && nVersion > 6 && !directMode)
449 {
450 int nId = gIcqProtocol.requestReverseConnection(userId, channel, nIP, nLocalPort, nRemotePort);
451 if (nId != -1)
452 {
453 gIcqProtocol.waitForReverseConnection(nId, userId);
454 UserReadGuard u(userId);
455 if (!u.isLocked())
456 {
457 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
458 gIcqProtocol.ProcessDoneEvent(e);
459 else
460 {
461 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
462 pthread_testcancel();
463 delete e;
464 }
465 pthread_exit(NULL);
466 }
467 socket = u->socketDesc(channel);
468 }
469
470 // if we failed, try direct anyway
471 if (socket == -1)
472 {
473 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
474 pthread_testcancel();
475 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
476
477 socket = gIcqProtocol.connectToUser(userId, channel);
478 }
479 }
480 else
481 {
482 socket = gIcqProtocol.connectToUser(userId, channel);
483
484 // if we failed, try through server
485 if (socket == -1)
486 {
487 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
488 pthread_testcancel();
489 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
490
491 int nId = gIcqProtocol.requestReverseConnection(userId, channel, nIP,
492 nLocalPort, nRemotePort);
493 if (nId != -1)
494 {
495 gIcqProtocol.waitForReverseConnection(nId, userId);
496 UserReadGuard u(userId);
497 if (!u.isLocked())
498 {
499 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
500 gIcqProtocol.ProcessDoneEvent(e);
501 else
502 {
503 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
504 pthread_testcancel();
505 delete e;
506 }
507 pthread_exit(NULL);
508 }
509 socket = u->socketDesc(channel);
510 }
511 }
512 }
513
514 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
515 pthread_testcancel();
516 e->m_nSocketDesc = socket;
517 // Check again, if still -1, fail the event
518 if (e->m_nSocketDesc == -1)
519 {
520 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
521 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
522 gIcqProtocol.ProcessDoneEvent(e);
523 else
524 {
525 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
526 pthread_testcancel();
527 delete e;
528 }
529 pthread_exit(NULL);
530 }
531 }
532
533 int socket = e->m_nSocketDesc;
534 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
535 Licq::INetSocket* s = gSocketManager.FetchSocket(socket);
536 if (s == NULL)
537 {
538 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
539 pthread_testcancel();
540 unsigned short nSequence = e->m_nSequence;
541 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
542
543 gLog.warning(tr("Socket %d does not exist (#%hu)."), socket,
544 nSequence);
545 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
546 gIcqProtocol.ProcessDoneEvent(e);
547 else
548 {
549 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
550 pthread_testcancel();
551 delete e;
552 }
553 pthread_exit(NULL);
554 }
555
556 Licq::Buffer* buf;
557 bool sent;
558 string errorStr;
559 pthread_cleanup_push(cleanup_socket, s);
560
561 pthread_mutex_lock(&gIcqProtocol.mutex_cancelthread);
562
563 // check to make sure we were not cancelled already
564 pthread_cleanup_push(cleanup_mutex, &gIcqProtocol.mutex_cancelthread);
565 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
566 pthread_testcancel();
567 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
568
569 //if we get here then we haven't been cancelled and we won't be
570 //as long as we hold mutex_cancelthread
571
572 buf = e->m_pPacket->Finalize(s);
573
574 pthread_mutex_unlock(&gIcqProtocol.mutex_cancelthread);
575 pthread_cleanup_pop(0);
576
577 sent = s->send(*buf);
578
579 if (!sent)
580 errorStr = s->errorStr();
581
582 gSocketManager.DropSocket(s);
583 pthread_cleanup_pop(0);
584
585 if (!sent)
586 {
587 // Close the socket, alert the socket thread
588 gSocketManager.CloseSocket(socket);
589 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
590 pthread_testcancel();
591 unsigned short nSequence = e->m_nSequence;
592 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
593
594 gLog.warning(tr("Error sending event (#%d): %s."), -nSequence, errorStr.c_str());
595 gIcqProtocol.myNewSocketPipe.putChar('S');
596 // Kill the event, do after the above as ProcessDoneEvent erase the event
597 if (gIcqProtocol.DoneEvent(e, Licq::Event::ResultError) != NULL)
598 gIcqProtocol.ProcessDoneEvent(e);
599 else
600 {
601 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
602 pthread_testcancel();
603 delete e;
604 }
605 pthread_exit(NULL);
606 }
607 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
608 pthread_testcancel();
609
610 e->thread_running = false;
611
612 // pthread_exit is not async cancel safe???
613 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
614 pthread_exit(NULL);
615 // Avoid compiler warnings
616 return NULL;
617 }
618
619
620 /*------------------------------------------------------------------------------
621 * ReverseConnectToUser_tep
622 *
623 * Creates a new TCPSocket and connects it to a given user. Adds the socket
624 * to the global socket manager and to the user.
625 *----------------------------------------------------------------------------*/
ReverseConnectToUser_tep(void * v)626 void* LicqIcq::ReverseConnectToUser_tep(void* v)
627 {
628 pthread_detach(pthread_self());
629
630 DEBUG_THREADS("[ReverseConnectToUser_tep] Caught event.\n");
631
632 CReverseConnectToUserData *p = (CReverseConnectToUserData *)v;
633
634 Licq::UserId userId(gIcqProtocol.ownerId(), p->myIdString);
635 gIcqProtocol.reverseConnectToUser(userId, p->nIp, p->nPort,
636 p->nVersion, p->nFailedPort, p->nId, p->nMsgID1, p->nMsgID2);
637
638 delete p;
639
640 return NULL;
641 }
642
643
644
645
646 /*------------------------------------------------------------------------------
647 * Ping_tep
648 *
649 * Thread entry point to ping the server every n minutes.
650 *----------------------------------------------------------------------------*/
Ping_tep(void *)651 void* LicqIcq::Ping_tep(void * /*p*/)
652 {
653 pthread_detach(pthread_self());
654
655 struct timeval tv;
656
657 while (true)
658 {
659 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
660 switch (gIcqProtocol.Status())
661 {
662 case STATUS_ONLINE:
663 gIcqProtocol.icqPing();
664 break;
665 case STATUS_OFFLINE_MANUAL:
666 break;
667 case STATUS_OFFLINE_FORCED:
668 if (time(NULL) > gIcqProtocol.m_tLogonTime + IcqProtocol::LogonAttemptDelay)
669 gIcqProtocol.icqRelogon();
670 break;
671 }
672 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
673 pthread_testcancel();
674
675 tv.tv_sec = IcqProtocol::PingFrequency;
676 tv.tv_usec = 0;
677 select(0, NULL, NULL, NULL, &tv);
678
679 pthread_testcancel();
680 }
681 return NULL;
682 }
683
684
685
686 /*------------------------------------------------------------------------------
687 * MonitorSockets_func
688 *
689 * The server thread lives here. The main guy who waits on socket activity
690 * and processes incoming packets.
691 *----------------------------------------------------------------------------*/
MonitorSockets_func()692 void* LicqIcq::MonitorSockets_func()
693 {
694 fd_set f;
695 int nSocketsAvailable, nServiceSocket, l;
696
697 while (true)
698 {
699 f = gSocketManager.socketSet();
700 l = gSocketManager.LargestSocket() + 1;
701
702 // Add the new socket pipe descriptor
703 FD_SET(gIcqProtocol.myNewSocketPipe.getReadFd(), &f);
704 if (gIcqProtocol.myNewSocketPipe.getReadFd() >= l)
705 l = gIcqProtocol.myNewSocketPipe.getReadFd() + 1;
706
707 // Add plugin notification pipe
708 FD_SET(gIcqProtocolPlugin->getReadPipe(), &f);
709 if (gIcqProtocolPlugin->getReadPipe() >= l)
710 l = gIcqProtocolPlugin->getReadPipe() + 1;
711
712 nSocketsAvailable = select(l, &f, NULL, NULL, NULL);
713
714 if (gIcqProtocol.m_xBARTService)
715 {
716 COscarService *svc = gIcqProtocol.m_xBARTService;
717 nServiceSocket = svc->GetSocketDesc();
718 }
719 else
720 nServiceSocket = -1;
721
722 for (int nCurrentSocket = 0; nSocketsAvailable >= 0 && nCurrentSocket < l; ++nCurrentSocket)
723 {
724 if (!FD_ISSET(nCurrentSocket, &f))
725 continue;
726
727 --nSocketsAvailable;
728
729
730 // New socket event ----------------------------------------------------
731 if (nCurrentSocket == gIcqProtocol.myNewSocketPipe.getReadFd())
732 {
733 char buf = gIcqProtocol.myNewSocketPipe.getChar();
734 if (buf == 'S')
735 {
736 DEBUG_THREADS("[MonitorSockets_tep] Reloading socket info.\n");
737 }
738 else if (buf == 'X')
739 {
740 DEBUG_THREADS("[MonitorSockets_tep] Exiting.\n");
741 return NULL;
742 }
743 }
744
745 if (nCurrentSocket == gIcqProtocolPlugin->getReadPipe())
746 {
747 gIcqProtocolPlugin->processPipe();
748 continue;
749 }
750
751 Licq::INetSocket *s = gSocketManager.FetchSocket(nCurrentSocket);
752 if (s != NULL && s->userId().isValid() &&
753 s->userId() == gIcqProtocol.ownerId() &&
754 gIcqProtocol.m_nTCPSrvSocketDesc == -1)
755 {
756 /* This is the server socket and it is about to be destoryed
757 so ignore this message (it's probably a disconnection anyway) */
758 gSocketManager.DropSocket(s);
759 continue;
760 }
761
762 // Message from the server -------------------------------------------
763 if (nCurrentSocket == gIcqProtocol.m_nTCPSrvSocketDesc)
764 {
765 DEBUG_THREADS("[MonitorSockets_tep] Data on TCP server socket.\n");
766 SrvSocket* srvTCP = dynamic_cast<SrvSocket*>(s);
767 if (srvTCP == NULL)
768 {
769 gLog.warning(tr("Invalid server socket in set."));
770 close(nCurrentSocket);
771 continue;
772 }
773
774 // DAW FIXME error handling when socket is closed..
775 Buffer packet;
776 if (srvTCP->receiveFlap(packet))
777 {
778 gSocketManager.DropSocket(srvTCP);
779 if (!gIcqProtocol.ProcessSrvPacket(packet))
780 {} // gIcqProtocol.icqRelogon();
781 }
782 else {
783 // probably server closed socket, try to relogon after a while
784 // if ping-thread is running already
785 int nSD = gIcqProtocol.m_nTCPSrvSocketDesc;
786 gIcqProtocol.m_nTCPSrvSocketDesc = -1;
787 gLog.info(tr("Dropping server connection."));
788 gSocketManager.DropSocket(srvTCP);
789 gSocketManager.CloseSocket(nSD);
790 // we need to initialize the logon time for the next retry
791 gIcqProtocol.m_tLogonTime = time(NULL);
792 gIcqProtocol.m_eStatus = STATUS_OFFLINE_FORCED;
793 gIcqProtocol.m_bLoggingOn = false;
794 gIcqProtocol.postLogoff(nSD, NULL);
795 }
796 }
797
798 // Message from the service sockets -----------------------------------
799 else if (nCurrentSocket == nServiceSocket)
800 {
801 DEBUG_THREADS("[MonitorSockets_tep] Data on BART service socket.\n");
802 COscarService *svc = gIcqProtocol.m_xBARTService;
803 SrvSocket* sock_svc = dynamic_cast<SrvSocket*>(s);
804 if (sock_svc == NULL)
805 {
806 gLog.warning(tr("Invalid BART service socket in set."));
807 close(nCurrentSocket);
808 continue;
809 }
810 Buffer packet;
811 if (sock_svc->receiveFlap(packet))
812 {
813 gSocketManager.DropSocket(sock_svc);
814 if (!svc->ProcessPacket(packet))
815 {
816 gLog.warning(tr("Can't process packet for service 0x%02X."), svc->GetFam());
817 svc->ResetSocket();
818 svc->ChangeStatus(STATUS_UNINITIALIZED);
819 gSocketManager.CloseSocket(nCurrentSocket);
820 }
821 }
822 else
823 {
824 gLog.warning(tr("Can't receive packet for service 0x%02X."), svc->GetFam());
825 svc->ResetSocket();
826 svc->ChangeStatus(STATUS_UNINITIALIZED);
827 gSocketManager.DropSocket(sock_svc);
828 gSocketManager.CloseSocket(nCurrentSocket);
829 }
830 }
831
832 // Connection on the server port -------------------------------------
833 else if (nCurrentSocket == gIcqProtocol.m_nTCPSocketDesc)
834 {
835 DEBUG_THREADS("[MonitorSockets_tep] Data on listening TCP socket."
836 "\n");
837 Licq::TCPSocket* tcp = dynamic_cast<Licq::TCPSocket*>(s);
838 if (tcp == NULL)
839 {
840 gLog.warning(tr("Invalid server TCP socket in set."));
841 close(nCurrentSocket);
842 continue;
843 }
844
845 DcSocket* newSocket = new DcSocket();
846 bool ok = tcp->RecvConnection(*newSocket);
847 gSocketManager.DropSocket(tcp);
848
849 // Make sure we can handle another socket before accepting it
850 if (!ok || gSocketManager.Num() > MAX_CONNECTS)
851 {
852 // Too many sockets, drop this one
853 gLog.warning(tr("Too many connected sockets, rejecting connection from %s."),
854 newSocket->getRemoteIpString().c_str());
855 delete newSocket;
856 }
857 else
858 {
859 gSocketManager.AddSocket(newSocket);
860 gSocketManager.DropSocket(newSocket);
861 }
862 }
863
864 // Message from connected socket--------------------------------------
865 else
866 {
867 DEBUG_THREADS("[MonitorSockets_tep] Data on TCP user socket.\n");
868
869 ssl_recv:
870
871 DcSocket* tcp = dynamic_cast<DcSocket*>(s);
872
873 // If tcp is NULL then the socket is no longer in the set, hence it
874 // must have been closed by us and we can ignore it.
875 if (tcp == NULL)
876 continue;
877
878 if (!tcp->RecvPacket())
879 {
880 int err = tcp->Error();
881 if (err == 0)
882 gLog.info(tr("Connection to %s was closed."), tcp->userId().toString().c_str());
883 else
884 gLog.info(tr("Connection to %s lost: %s."),
885 tcp->userId().toString().c_str(), tcp->errorStr().c_str());
886 if (tcp->userId().isValid())
887 {
888 Licq::UserWriteGuard u(tcp->userId());
889 if (u.isLocked() && u->Secure())
890 {
891 u->clearSocketDesc(tcp);
892 u->SetSecure(false);
893 Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
894 Licq::PluginSignal::SignalUser,
895 Licq::PluginSignal::UserSecurity, u->id(), 0));
896 }
897 }
898 gSocketManager.DropSocket(tcp);
899 gSocketManager.CloseSocket(nCurrentSocket);
900 gIcqProtocol.FailEvents(nCurrentSocket, err);
901
902 break;
903 }
904
905 // Save the bytes pending status of the socket
906 bool bPending = tcp->SSL_Pending();
907 bool r = true;
908
909 // Process the packet if the buffer is full
910 if (tcp->RecvBufferFull())
911 {
912 if (tcp->userId().protocolId() != ICQ_PPID)
913 r = gIcqProtocol.ProcessTcpHandshake(tcp);
914 else
915 r = gIcqProtocol.ProcessTcpPacket(tcp);
916 tcp->ClearRecvBuffer();
917 }
918
919 // Kill the socket if there was a problem
920 if (!r)
921 {
922 gLog.info(tr("Closing connection to %s."), tcp->userId().toString().c_str());
923 gSocketManager.DropSocket(tcp);
924 gSocketManager.CloseSocket(nCurrentSocket);
925 gIcqProtocol.FailEvents(nCurrentSocket, 0);
926 bPending = false;
927 }
928 else
929 {
930 gSocketManager.DropSocket(tcp);
931 }
932
933 // If there is more data pending then go again
934 if (bPending) goto ssl_recv;
935 }
936 }
937 }
938 return NULL;
939 }
940
UpdateUsers_tep(void *)941 void* LicqIcq::UpdateUsers_tep(void* /* p */)
942 {
943 pthread_detach(pthread_self());
944
945 struct timeval tv;
946
947 while (true)
948 {
949 if (gIcqProtocol.Status() == STATUS_ONLINE)
950 {
951 bool useBart;
952 bool autoInfo, autoInfoPlugins, autoStatusPlugins;
953 {
954 OwnerReadGuard o(gIcqProtocol.ownerId());
955 useBart = o->useBart();
956 autoInfo = o->autoUpdateInfo();
957 autoInfoPlugins = o->autoUpdateInfoPlugins();
958 autoStatusPlugins = o->autoUpdateStatusPlugins();
959 }
960
961 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
962 Licq::UserListGuard userList(gIcqProtocol.ownerId());
963 BOOST_FOREACH(Licq::User* user, **userList)
964 {
965 UserWriteGuard pUser(dynamic_cast<User*>(user));
966 bool bSent = false;
967 bool bBART = false;
968
969 if (autoInfo && !pUser->UserUpdated() &&
970 pUser->ClientTimestamp() != pUser->OurClientTimestamp()
971 && pUser->ClientTimestamp() != 0)
972 {
973 gIcqProtocol.icqRequestMetaInfo(pUser->id());
974 bSent = true;
975 }
976
977 if (useBart && autoInfo && pUser->buddyIconHash().size() > 0 &&
978 pUser->buddyIconHash() != pUser->ourBuddyIconHash())
979 {
980 unsigned long eventId = Licq::gProtocolManager.getNextEventId();
981 gIcqProtocol.m_xBARTService->SendEvent(pthread_self(), eventId, pUser->id(),
982 ICQ_SNACxBART_DOWNLOADxREQUEST, true);
983 bSent = true;
984 bBART = true;
985 }
986
987 if (pUser->isOnline() && !pUser->UserUpdated() &&
988 //Don't bother clients that we know don't support plugins
989 pUser->Version() >= 7 &&
990 //Old versions of Licq
991 (((pUser->ClientTimestamp() & 0xFFFF0000) != LICQ_WITHSSL &&
992 (pUser->ClientTimestamp() & 0xFFFF0000) != LICQ_WITHOUTSSL) ||
993 (pUser->ClientTimestamp() & 0xFFFF) > 1026) &&
994 pUser->ClientTimestamp() != 0xFFFFFF42 && //mICQ
995 pUser->ClientTimestamp() != 0xFFFFFFFF && //Miranda
996 pUser->ClientTimestamp() != 0xFFFFFF7F && //&RQ
997 pUser->ClientTimestamp() != 0xFFFFFFBE && //Alicq
998 pUser->ClientTimestamp() != 0x3B75AC09 && //Trillian
999 pUser->ClientTimestamp() != 0x3AA773EE && //libICQ2000 based clients
1000 pUser->ClientTimestamp() != 0x3BC1252C && //ICQ Interest Search
1001 pUser->ClientTimestamp() != 0x3B176B57 && //jcq2k
1002 pUser->ClientTimestamp() != 0x3BA76E2E && //SmartICQ
1003 pUser->ClientTimestamp() != 0x3C7D8CBC && //Vista
1004 pUser->ClientTimestamp() != 0x3CFE0688 && //Meca
1005 pUser->ClientTimestamp() != 0x3BFF8C98 //IGA
1006 )
1007 {
1008 if (autoInfoPlugins && pUser->ClientInfoTimestamp() != 0 &&
1009 pUser->ClientInfoTimestamp() != pUser->OurClientInfoTimestamp())
1010 {
1011 gLog.info(tr("Updating %s's info plugins."), pUser->getAlias().c_str());
1012 gIcqProtocol.icqRequestInfoPlugin(*pUser, true, PLUGIN_QUERYxINFO);
1013 gIcqProtocol.icqRequestInfoPlugin(*pUser, true, PLUGIN_PHONExBOOK);
1014 if (!bBART) // Send only if we didn't request BART already
1015 gIcqProtocol.icqRequestInfoPlugin(*pUser, true, PLUGIN_PICTURE);
1016 bSent = true;
1017 }
1018
1019 if (autoStatusPlugins && pUser->ClientStatusTimestamp() != 0 &&
1020 pUser->ClientStatusTimestamp() != pUser->OurClientStatusTimestamp())
1021 {
1022 gLog.info(tr("Updating %s's status plugins."), pUser->getAlias().c_str());
1023 gIcqProtocol.icqRequestStatusPlugin(*pUser, true, PLUGIN_QUERYxSTATUS);
1024 gIcqProtocol.icqRequestStatusPlugin(*pUser, true, PLUGIN_FILExSERVER);
1025 gIcqProtocol.icqRequestStatusPlugin(*pUser, true, PLUGIN_FOLLOWxME);
1026 gIcqProtocol.icqRequestStatusPlugin(*pUser, true, PLUGIN_ICQxPHONE);
1027 bSent = true;
1028 }
1029
1030 }
1031
1032 if (bSent)
1033 {
1034 pUser->SetUserUpdated(true);
1035 break;
1036 }
1037 }
1038 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1039 }
1040
1041 pthread_testcancel();
1042
1043 tv.tv_sec = IcqProtocol::UpdateFrequency;
1044 tv.tv_usec = 0;
1045 select(0, NULL, NULL, NULL, &tv);
1046
1047 pthread_testcancel();
1048 }
1049
1050 pthread_exit(NULL);
1051 }
1052