1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4 * $Id: tcplink.c 2509 2001-10-13 00:06:18Z warmenhoven $
6 * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and
7 * Bill Soudan <soudan@kde.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 #define EINPROGRESS WSAEINPROGRESS
33 #define ENETUNREACH WSAENETUNREACH
34 #define ECONNREFUSED WSAECONNREFUSED
35 #define ETIMEDOUT WSAETIMEDOUT
36 #define EOPNOTSUPP WSAEOPNOTSUPP
37 #define EAFNOSUPPORT WSAEAFNOSUPPORT
38 #define EWOULDBLOCK WSAEWOULDBLOCK
44 #include "stdpackets.h"
47 #include "chatsession.h"
48 #include "filesession.h"
50 #include "socketmanager.h"
52 icq_TCPLink
*icq_TCPLinkNew(icq_Link
*icqlink
)
54 icq_TCPLink
*p
=(icq_TCPLink
*)malloc(sizeof(icq_TCPLink
));
60 p
->type
=TCP_LINK_MESSAGE
;
62 p
->send_queue
=icq_ListNew();
63 p
->received_queue
=icq_ListNew();
69 p
->connect_timeout
= NULL
;
72 icq_ListEnqueue(icqlink
->d
->icq_TCPLinks
, p
);
77 int _icq_TCPLinkDelete(void *pv
, va_list data
)
79 icq_Packet
*p
=(icq_Packet
*)pv
;
80 icq_Link
*icqlink
=va_arg(data
, icq_Link
*);
82 /* notify the app the packet didn't make it */
84 invoke_callback(icqlink
, icq_RequestNotify
)(icqlink
, p
->id
,
85 ICQ_NOTIFY_FAILED
, 0, 0);
90 void icq_TCPLinkDelete(void *pv
)
92 icq_TCPLink
*p
=(icq_TCPLink
*)pv
;
94 /* process anything left in the received queue */
95 icq_TCPLinkProcessReceived(p
);
97 /* make sure we notify app that packets in send queue didn't make it */
98 (void)icq_ListTraverse(p
->send_queue
, _icq_TCPLinkDelete
, p
->icqlink
);
100 /* destruct all packets still waiting on queues */
101 icq_ListDelete(p
->send_queue
, icq_PacketDelete
);
102 icq_ListDelete(p
->received_queue
, icq_PacketDelete
);
104 /* if this is a chat or file link, delete the associated session as
105 * well, but make sure we unassociate ourself first so the session
106 * doesn't try to close us */
109 if(p
->type
==TCP_LINK_CHAT
)
111 icq_ChatSession
*psession
=p
->session
;
112 psession
->tcplink
=NULL
;
113 icq_ChatSessionClose(psession
);
116 if(p
->type
==TCP_LINK_FILE
) {
117 icq_FileSession
*psession
=p
->session
;
118 psession
->tcplink
=NULL
;
119 icq_FileSessionClose(psession
);
123 /* close the socket after we notify app so app can read errno if necessary */
126 icq_SocketDelete(p
->socket
);
129 if (p
->connect_timeout
)
131 icq_TimeoutDelete(p
->connect_timeout
);
137 void icq_TCPLinkClose(icq_TCPLink
*plink
)
139 icq_ListRemove(plink
->icqlink
->d
->icq_TCPLinks
, plink
);
140 icq_TCPLinkDelete(plink
);
143 int icq_TCPLinkProxyConnect(icq_TCPLink
*plink
, DWORD uin
, int port
)
145 struct sockaddr_in prsin
;
146 struct hostent
*host_struct
;
149 (void)uin
; (void)port
;
151 prsin
.sin_addr
.s_addr
= htonl(plink
->icqlink
->icq_ProxyIP
);
152 if(prsin
.sin_addr
.s_addr
== (unsigned long)-1)
154 prsin
.sin_addr
.s_addr
= inet_addr(plink
->icqlink
->icq_ProxyHost
);
155 if(prsin
.sin_addr
.s_addr
== (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */
157 host_struct
= gethostbyname(plink
->icqlink
->icq_ProxyHost
);
158 if(host_struct
== 0L)
160 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Can't find hostname: %s\n",
161 plink
->icqlink
->icq_ProxyHost
);
164 prsin
.sin_addr
= *((struct in_addr
*)host_struct
->h_addr
);
167 prsin
.sin_family
= AF_INET
; /* we're using the inet not appletalk*/
168 prsin
.sin_port
= htons(plink
->icqlink
->icq_ProxyPort
); /* port */
169 /* flags = fcntl(plink->socket, F_GETFL, 0); */
170 /* fcntl(plink->socket, F_SETFL, flags & (~O_NONBLOCK)); */
171 plink
->mode
|= TCP_LINK_SOCKS_CONNECTING
;
172 conct
= connect(plink
->socket
, (struct sockaddr
*) &prsin
, sizeof(prsin
));
173 if(conct
== -1) /* did we connect ?*/
175 if(errno
!= EINPROGRESS
)
178 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Connection refused\n");
186 int icq_TCPLinkProxyRequestAuthorization(icq_TCPLink
*plink
)
190 int hasName
= plink
->icqlink
->icq_ProxyName
&&
191 strlen(plink
->icqlink
->icq_ProxyName
);
192 int hasPass
= plink
->icqlink
->icq_ProxyPass
&&
193 strlen(plink
->icqlink
->icq_ProxyPass
);
194 int authEnabled
= hasName
&& hasPass
&& plink
->icqlink
->icq_ProxyAuth
;
196 plink
->mode
= (plink
->mode
& (~TCP_LINK_SOCKS_CONNECTING
));
197 buf
[0] = 5; /* protocol version */
198 buf
[1] = 1; /* number of methods */
199 buf
[2] = authEnabled
? 2 : 0; /* authentication method */
201 plink
->mode
|= authEnabled
? TCP_LINK_SOCKS_AUTHORIZATION
:
202 TCP_LINK_SOCKS_NOAUTHSTATUS
;
205 if(send(plink
->socket
, buf
, 3, 0) != 3)
208 if(write(plink
->socket
, buf
, 3) != 3)
214 int icq_TCPLinkProxyAuthorization(icq_TCPLink
*plink
)
219 plink
->mode
&= ~TCP_LINK_SOCKS_AUTHORIZATION
;
220 plink
->mode
|= TCP_LINK_SOCKS_AUTHSTATUS
;
223 res
= recv(plink
->socket
, buf
, 2, 0);
225 res
= read(plink
->socket
, buf
, 2);
227 if(res
!= 2 || buf
[0] != 5 || buf
[1] != 2) /* username/password authentication*/
229 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Authentication method incorrect\n");
230 icq_SocketDelete(plink
->socket
);
233 buf
[0] = 1; /* version of subnegotiation */
234 buf
[1] = strlen(plink
->icqlink
->icq_ProxyName
);
235 memcpy(&buf
[2], plink
->icqlink
->icq_ProxyName
, buf
[1]);
236 buf
[2+buf
[1]] = strlen(plink
->icqlink
->icq_ProxyPass
);
237 memcpy(&buf
[3+buf
[1]], plink
->icqlink
->icq_ProxyPass
, buf
[2+buf
[1]]);
239 if(send(plink
->socket
, buf
, buf
[1]+buf
[2+buf
[1]]+3, 0) != buf
[1] + buf
[2+buf
[1]]+3)
242 if(write(plink
->socket
, buf
, buf
[1]+buf
[2+buf
[1]]+3) != buf
[1] + buf
[2+buf
[1]]+3)
248 int icq_TCPLinkProxyAuthStatus(icq_TCPLink
*plink
)
253 plink
->mode
= (plink
->mode
& (~TCP_LINK_SOCKS_AUTHSTATUS
)) | TCP_LINK_SOCKS_CROSSCONNECT
;
255 res
= recv(plink
->socket
, buf
, 2, 0);
257 res
= read(plink
->socket
, buf
, 2);
259 if(res
!= 2 || buf
[0] != 1 || buf
[1] != 0)
261 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Authorization failure\n");
262 icq_SocketDelete(plink
->socket
);
268 int icq_TCPLinkProxyNoAuthStatus(icq_TCPLink
*plink
)
273 plink
->mode
= (plink
->mode
& (~TCP_LINK_SOCKS_NOAUTHSTATUS
)) | TCP_LINK_SOCKS_CROSSCONNECT
;
275 res
= recv(plink
->socket
, buf
, 2, 0);
277 res
= read(plink
->socket
, buf
, 2);
279 if(res
!= 2 || buf
[0] != 5 || buf
[1] != 0) /* no authentication required */
281 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Authentication method incorrect\n");
282 icq_SocketDelete(plink
->socket
);
288 int icq_TCPLinkProxyCrossConnect(icq_TCPLink
*plink
)
292 plink
->mode
= (plink
->mode
& ~(TCP_LINK_SOCKS_CROSSCONNECT
)) | TCP_LINK_SOCKS_CONNSTATUS
;
293 buf
[0] = 5; /* protocol version */
294 buf
[1] = 1; /* command connect */
295 buf
[2] = 0; /* reserved */
296 buf
[3] = 1; /* address type IP v4 */
297 memcpy(&buf
[4], &plink
->remote_address
.sin_addr
.s_addr
, 4);
298 memcpy(&buf
[8], &plink
->remote_address
.sin_port
, 2);
300 if(send(plink
->socket
, buf
, 10, 0) != 10)
303 if(write(plink
->socket
, buf
, 10) != 10)
309 int icq_TCPLinkProxyConnectStatus(icq_TCPLink
*plink
)
314 plink
->mode
= (plink
->mode
& (~TCP_LINK_SOCKS_CONNSTATUS
));
316 res
= recv(plink
->socket
, buf
, 10, 0);
318 res
= read(plink
->socket
, buf
, 10);
320 if(res
!= 10 || buf
[0] != 5 || buf
[1] != 0)
325 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] General SOCKS server failure\n");
329 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Connection not allowed by ruleset\n");
333 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Network unreachable\n");
337 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Host unreachable\n");
341 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Connection refused\n");
345 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] TTL expired\n");
349 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Command not supported\n");
353 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Address type not supported\n");
357 icq_FmtLog(plink
->icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Unknown SOCKS server failure\n");
361 icq_SocketDelete(plink
->socket
);
367 int icq_TCPLinkConnect(icq_TCPLink
*plink
, DWORD uin
, int port
)
369 icq_ContactItem
*pcontact
=icq_ContactFind(plink
->icqlink
, uin
);
379 /* these return values never and nowhere checked */
384 if((plink
->socket
=icq_SocketNew(AF_INET
, SOCK_STREAM
, 0)) < 0)
387 /* bzero(&(plink->remote_address), sizeof(plink->remote_address)); Win32 incompatible... */
388 memset(&(plink
->remote_address
), 0, sizeof(plink
->remote_address
));
389 plink
->remote_address
.sin_family
= AF_INET
;
391 /* if our IP is the same as the remote user's ip, connect to real_ip
392 instead since we're both probably behind a firewall */
393 icq_FmtLog(plink
->icqlink
, ICQ_LOG_MESSAGE
,
394 "local IP is %08X:%d, remote real IP is %08X:%d, remote IP is %08X:%d, port is %d\n",
395 plink
->icqlink
->icq_OurIP
,
396 plink
->icqlink
->icq_OurPort
,
397 pcontact
->remote_real_ip
,
398 pcontact
->remote_port
,
400 pcontact
->remote_port
,
403 if (plink
->icqlink
->icq_OurIP
== pcontact
->remote_ip
)
404 plink
->remote_address
.sin_addr
.s_addr
= htonl(pcontact
->remote_real_ip
);
406 plink
->remote_address
.sin_addr
.s_addr
= htonl(pcontact
->remote_ip
);
408 if(plink
->type
==TCP_LINK_MESSAGE
)
410 plink
->remote_address
.sin_port
= htons(pcontact
->remote_port
);
411 icq_FmtLog(plink
->icqlink
, ICQ_LOG_MESSAGE
,
412 "initiating message connect to %d (%s:%d)\n", uin
,
413 inet_ntoa(*((struct in_addr
*)(&(plink
->remote_address
.sin_addr
)))),
414 pcontact
->remote_port
);
418 plink
->remote_address
.sin_port
= htons(port
);
419 icq_FmtLog(plink
->icqlink
, ICQ_LOG_MESSAGE
,
420 "initiating file/chat connect to %d (%s:%d)\n", uin
,
421 inet_ntoa(*((struct in_addr
*)(&(plink
->remote_address
.sin_addr
)))),
425 /* set the socket to non-blocking */
428 ioctlsocket(plink
->socket
, FIONBIO
, &iosflag
);
430 flags
=fcntl(plink
->socket
, F_GETFL
, 0);
431 fcntl(plink
->socket
, F_SETFL
, flags
| O_NONBLOCK
);
434 if(!plink
->icqlink
->icq_UseProxy
)
435 result
=connect(plink
->socket
, (struct sockaddr
*)&(plink
->remote_address
),
436 sizeof(plink
->remote_address
));
437 else /* SOCKS proxy support */
438 result
=icq_TCPLinkProxyConnect(plink
, uin
, port
);
439 /* FIXME: Here we should check for errors on connection */
440 /* because of proxy support - it can't be checked */
441 /* by getsockopt() later in _handle_ready_sockets() */
444 plink
->mode
|=TCP_LINK_MODE_CONNECTING
;
446 plink
->remote_uin
=uin
;
448 /* Send the hello packet */
449 p
=icq_TCPCreateInitPacket(plink
);
450 icq_TCPLinkSend(plink
, p
);
452 #ifdef TCP_PACKET_TRACE
453 printf("hello packet queued for %lu\n", uin
);
454 #endif /* TCP_PACKET_TRACE */
456 icq_SocketSetHandler(plink
->socket
, ICQ_SOCKET_WRITE
,
457 (icq_SocketHandler
)icq_TCPLinkOnConnect
, plink
);
458 plink
->connect_timeout
=icq_TimeoutNew(TCP_LINK_CONNECT_TIMEOUT
,
459 (icq_TimeoutHandler
)icq_TCPLinkClose
, plink
);
464 icq_TCPLink
*icq_TCPLinkAccept(icq_TCPLink
*plink
)
472 size_t remote_length
;
473 icq_TCPLink
*pnewlink
=icq_TCPLinkNew(plink
->icqlink
);
477 remote_length
= sizeof(struct sockaddr_in
);
478 socket_fd
=icq_SocketAccept(plink
->socket
,
479 (struct sockaddr
*)&(plink
->remote_address
), &remote_length
);
481 icq_FmtLog(plink
->icqlink
, ICQ_LOG_MESSAGE
,
482 "accepting tcp connection from %s:%d\n",
483 inet_ntoa(*((struct in_addr
*)(&(plink
->remote_address
.sin_addr
)))),
484 ntohs(plink
->remote_address
.sin_port
));
486 /* FIXME: make sure accept succeeded */
488 pnewlink
->type
=plink
->type
;
489 pnewlink
->socket
=socket_fd
;
491 /* first packet sent on an icq tcp link is always the hello packet */
492 pnewlink
->mode
|=TCP_LINK_MODE_HELLOWAIT
;
494 /* install socket handler for new socket */
495 icq_SocketSetHandler(socket_fd
, ICQ_SOCKET_READ
,
496 (icq_SocketHandler
)icq_TCPLinkOnDataReceived
, pnewlink
);
499 /* set the socket to non-blocking */
502 ioctlsocket(pnewlink
->socket
, FIONBIO
, &iosflag
);
504 flags
=fcntl(pnewlink
->socket
, F_GETFL
, 0);
505 fcntl(pnewlink
->socket
, F_SETFL
, flags
| O_NONBLOCK
);
511 int icq_TCPLinkListen(icq_TCPLink
*plink
)
515 /* listening links have 0 uin */
518 /* create tcp listen socket */
519 if((plink
->socket
=icq_SocketNew(AF_INET
, SOCK_STREAM
, 0)) < 0)
522 /* must use memset, no bzero for Win32! */
523 memset(&plink
->socket_address
, 0, sizeof(struct sockaddr_in
));
524 plink
->socket_address
.sin_family
=AF_INET
;
525 plink
->socket_address
.sin_addr
.s_addr
=htonl(INADDR_ANY
);
526 plink
->socket_address
.sin_port
=0;
528 if(bind(plink
->socket
, (struct sockaddr
*)&plink
->socket_address
, sizeof(struct sockaddr_in
)) < 0)
531 if(listen(plink
->socket
, 5) < 0)
534 t
=sizeof(struct sockaddr_in
);
535 if(getsockname(plink
->socket
, (struct sockaddr
*)&plink
->socket_address
, &t
) < 0)
538 icq_FmtLog(plink
->icqlink
, ICQ_LOG_MESSAGE
,
539 "created tcp listening socket %d, local address=%s:%d\n",
541 inet_ntoa(*((struct in_addr
*)(&plink
->socket_address
.sin_addr
))),
542 ntohs(plink
->socket_address
.sin_port
));
544 plink
->mode
|=TCP_LINK_MODE_LISTEN
;
546 icq_SocketSetHandler(plink
->socket
, ICQ_SOCKET_READ
, (icq_SocketHandler
)icq_TCPLinkAccept
,
552 /* Doing Cyrillic translations for Chat dialog sessions */
553 void icq_ChatRusConv_n(const char to
[4], char *t_in
, int t_len
)
557 for(i
= j
= 0; i
< t_len
; ++i
)
559 if((((unsigned char)t_in
[i
]) < ' ') && (t_in
[i
] != '\r'))
562 icq_RusConv_n(to
, &t_in
[j
], i
- j
- 1);
565 case '\x07': /* Bell */
566 case '\x08': /* BackSpace */
567 case '\x03': /* Chat is active */
568 case '\x04': /* Chat is not active */
570 case '\x00': /* Foregroung color (RR GG BB ?? ) */
571 case '\x01': /* Background color (RR GG BB ?? ) */
572 case '\x11': /* Font style change (Bold - 1, Italic - 2, Underline - 4) */
573 case '\x12': /* Font size change */
576 case '\x10': /* Font family and encoding change */
577 i
+= t_in
[i
+1] + 2 + 2;
578 icq_RusConv_n(to
, &t_in
[i
+3], t_in
[i
+1]);
589 icq_RusConv_n(to
, &t_in
[j
], i
- j
);
592 void icq_TCPLinkOnDataReceived(icq_TCPLink
*plink
)
594 int process_count
=0, recv_result
=0;
595 char *buffer
=plink
->buffer
;
597 do { /* while recv_result > 0 */
601 /* append received data onto end of buffer */
602 if((recv_result
=recv(plink
->socket
, buffer
+plink
->buffer_count
,
603 icq_TCPLinkBufferSize
-plink
->buffer_count
, 0)) < 1)
605 /* either there was an error or the remote side has closed
606 * the connection - fall out of the loop */
610 plink
->buffer_count
+=recv_result
;
612 #ifdef TCP_BUFFER_TRACE
613 printf("received %d bytes from link %x, new buffer count %d\n",
614 recv_result
, plink
, plink
->buffer_count
);
616 hex_dump(plink
->buffer
, plink
->buffer_count
);
617 #endif /*TCP_BUFFER_TRACE*/
619 process_count
+=recv_result
;
621 /* don't do any packet processing if we're in raw mode */
622 if(plink
->mode
& TCP_LINK_MODE_RAW
) {
623 /* notify the app with the new data */
624 if(plink
->type
== TCP_LINK_CHAT
)
625 icq_ChatRusConv_n("wk", plink
->buffer
, plink
->buffer_count
);
626 invoke_callback(plink
->icqlink
, icq_ChatNotify
)(plink
->session
,
627 CHAT_NOTIFY_DATA
, plink
->buffer_count
, plink
->buffer
);
628 plink
->buffer_count
=0;
632 /* remove packets from the buffer until the buffer is empty
633 * or the remaining bytes do not equal a full packet */
634 while((unsigned)plink
->buffer_count
>sizeof(WORD
) && !done
)
636 WORD packet_size
=(*((WORD
*)buffer
));
638 /* warn if the buffer is too small to hold the whole packet */
639 if(packet_size
>icq_TCPLinkBufferSize
-sizeof(WORD
))
641 icq_FmtLog(plink
->icqlink
, ICQ_LOG_WARNING
, "tcplink buffer "
642 "overflow, packet size = %d, buffer size = %d, closing link\n",
643 packet_size
, icq_TCPLinkBufferSize
);
647 if(packet_size
+sizeof(WORD
) <= (unsigned)plink
->buffer_count
)
649 /* copy the packet into memory */
650 icq_Packet
*p
=icq_PacketNew();
651 icq_PacketAppend(p
, buffer
+sizeof(WORD
), packet_size
);
653 /* remove it from the buffer */
654 memcpy(buffer
, buffer
+packet_size
+sizeof(WORD
),
655 plink
->buffer_count
-packet_size
-sizeof(WORD
));
657 plink
->buffer_count
-=(packet_size
+sizeof(WORD
));
659 icq_TCPLinkOnPacketReceived(plink
, p
);
663 /* not enough bytes in buffer to form the complete packet.
664 * we're done for now */
667 } /* while packets remain in buffer */
669 } while (recv_result
> 0);
672 if (recv_result
<= 0 && WSAGetLastError()!=EWOULDBLOCK
) {
673 /* receive error - log it */
674 icq_FmtLog(plink
->icqlink
, ICQ_LOG_WARNING
, "recv failed from %d (%d),"
675 " closing link\n", plink
->remote_uin
, WSAGetLastError());
677 if (recv_result
<= 0 && errno
!=EWOULDBLOCK
) {
678 /* receive error - log it */
679 icq_FmtLog(plink
->icqlink
, ICQ_LOG_WARNING
, "recv failed from %d (%d-%s),"
680 " closing link\n", plink
->remote_uin
, errno
, strerror(errno
));
683 icq_TCPLinkClose(plink
);
687 icq_TCPLinkProcessReceived(plink
);
693 void icq_TCPLinkOnPacketReceived(icq_TCPLink
*plink
, icq_Packet
*p
)
697 printf("packet received! { length=%d }\n", p
->length
);
701 /* Stick packet on ready packet linked icq_List */
702 icq_ListEnqueue(plink
->received_queue
, p
);
705 void icq_TCPLinkOnConnect(icq_TCPLink
*plink
)
714 icq_TimeoutDelete(plink
->connect_timeout
);
715 plink
->connect_timeout
= NULL
;
717 /* check getsockopt */
722 getsockopt(plink
->socket
, SOL_SOCKET
, SO_ERROR
, (char *)&error
, &len
);
724 getsockopt(plink
->socket
, SOL_SOCKET
, SO_ERROR
, &error
, &len
);
727 if(!error
&& (plink
->mode
& (TCP_LINK_SOCKS_CONNECTING
| TCP_LINK_SOCKS_AUTHORIZATION
|
728 TCP_LINK_SOCKS_AUTHSTATUS
| TCP_LINK_SOCKS_NOAUTHSTATUS
|
729 TCP_LINK_SOCKS_CROSSCONNECT
| TCP_LINK_SOCKS_CONNSTATUS
)))
731 if(plink
->mode
& TCP_LINK_SOCKS_CONNECTING
)
732 error
= icq_TCPLinkProxyRequestAuthorization(plink
);
733 else if(plink
->mode
& TCP_LINK_SOCKS_AUTHORIZATION
)
734 error
= icq_TCPLinkProxyAuthorization(plink
);
735 else if(plink
->mode
& TCP_LINK_SOCKS_AUTHSTATUS
)
736 error
= icq_TCPLinkProxyAuthStatus(plink
);
737 else if(plink
->mode
& TCP_LINK_SOCKS_NOAUTHSTATUS
)
738 error
= icq_TCPLinkProxyNoAuthStatus(plink
);
739 else if(plink
->mode
& TCP_LINK_SOCKS_CROSSCONNECT
)
740 error
= icq_TCPLinkProxyCrossConnect(plink
);
741 else if(plink
->mode
& TCP_LINK_SOCKS_CONNSTATUS
)
742 error
= icq_TCPLinkProxyConnectStatus(plink
);
749 /* connection failed- close the link, which takes care
750 * of notifying the app about packets that didn't make it */
751 icq_FmtLog(plink
->icqlink
, ICQ_LOG_WARNING
, "connect failed to %d (%d-%s),"
752 " closing link\n", plink
->remote_uin
, error
, strerror(error
));
754 icq_TCPLinkClose(plink
);
758 if(plink
->mode
& (TCP_LINK_SOCKS_CONNECTING
| TCP_LINK_SOCKS_AUTHORIZATION
| TCP_LINK_SOCKS_AUTHSTATUS
| TCP_LINK_SOCKS_NOAUTHSTATUS
| TCP_LINK_SOCKS_CROSSCONNECT
| TCP_LINK_SOCKS_CONNSTATUS
))
760 icq_SocketSetHandler(plink
->socket
, ICQ_SOCKET_WRITE
, NULL
, NULL
);
761 icq_SocketSetHandler(plink
->socket
, ICQ_SOCKET_READ
,
762 (icq_SocketHandler
)icq_TCPLinkOnConnect
, plink
);
766 len
=sizeof(plink
->socket_address
);
767 getsockname(plink
->socket
, (struct sockaddr
*)&plink
->socket_address
, &len
);
769 icq_FmtLog(plink
->icqlink
, ICQ_LOG_MESSAGE
,
770 "connected to uin %d, socket=%d local address=%s:%d remote address=%s:%d\n",
771 plink
->remote_uin
, plink
->socket
,
772 inet_ntoa(*((struct in_addr
*)(&plink
->socket_address
.sin_addr
))),
773 ntohs(plink
->socket_address
.sin_port
),
774 inet_ntoa(*((struct in_addr
*)(&plink
->remote_address
.sin_addr
))),
775 ntohs(plink
->remote_address
.sin_port
));
777 plink
->mode
&= ~TCP_LINK_MODE_CONNECTING
;
779 icq_SocketSetHandler(plink
->socket
, ICQ_SOCKET_READ
,
780 (icq_SocketHandler
)icq_TCPLinkOnDataReceived
, plink
);
781 icq_SocketSetHandler(plink
->socket
, ICQ_SOCKET_WRITE
, NULL
, NULL
);
783 /* socket is now connected, notify each request that connection
784 * has been established and send pending data */
785 while(plink
->send_queue
->count
>0)
787 icq_Packet
*p
=icq_ListDequeue(plink
->send_queue
);
789 if(plink
->icqlink
->icq_RequestNotify
)
790 (*plink
->icqlink
->icq_RequestNotify
)(plink
->icqlink
, p
->id
, ICQ_NOTIFY_CONNECTED
, 0, 0);
791 icq_TCPLinkSend(plink
, p
);
794 /* yeah this probably shouldn't be here. oh well :) */
795 if(plink
->type
==TCP_LINK_CHAT
)
797 icq_ChatSessionSetStatus((icq_ChatSession
*)plink
->session
,
798 CHAT_STATUS_CONNECTED
);
799 icq_ChatSessionSetStatus((icq_ChatSession
*)plink
->session
,
800 CHAT_STATUS_WAIT_ALLINFO
);
803 if(plink
->type
==TCP_LINK_FILE
)
805 icq_FileSessionSetStatus((icq_FileSession
*)plink
->session
,
806 FILE_STATUS_CONNECTED
);
811 unsigned long icq_TCPLinkSendSeq(icq_TCPLink
*plink
, icq_Packet
*p
,
812 unsigned long sequence
)
814 /* append the next sequence number on the packet */
816 sequence
=plink
->icqlink
->d
->icq_TCPSequence
--;
819 icq_PacketAppend32(p
, sequence
);
821 /* if the link is currently connecting, queue the packets for
822 * later, else send immediately */
823 if(plink
->mode
& TCP_LINK_MODE_CONNECTING
) {
824 icq_ListInsert(plink
->send_queue
, 0, p
);
825 if(plink
->icqlink
->icq_RequestNotify
)
826 (*plink
->icqlink
->icq_RequestNotify
)(plink
->icqlink
, p
->id
, ICQ_NOTIFY_CONNECTING
, 0, 0);
828 icq_PacketSend(p
, plink
->socket
);
830 if(plink
->icqlink
->icq_RequestNotify
)
831 (*plink
->icqlink
->icq_RequestNotify
)(plink
->icqlink
, p
->id
, ICQ_NOTIFY_SENT
, 0, 0);
837 void icq_TCPLinkSend(icq_TCPLink
*plink
, icq_Packet
*p
)
839 /* if the link is currently connecting, queue the packets for
840 * later, else send immediately */
841 if(plink
->mode
& TCP_LINK_MODE_CONNECTING
) {
842 icq_ListInsert(plink
->send_queue
, 0, p
);
843 if(plink
->icqlink
->icq_RequestNotify
)
844 (*plink
->icqlink
->icq_RequestNotify
)(plink
->icqlink
, p
->id
, ICQ_NOTIFY_CONNECTING
, 0, 0);
846 icq_PacketSend(p
, plink
->socket
);
848 if(plink
->icqlink
->icq_RequestNotify
)
849 (*plink
->icqlink
->icq_RequestNotify
)(plink
->icqlink
, p
->id
, ICQ_NOTIFY_SENT
, 0, 0);
854 void icq_TCPLinkProcessReceived(icq_TCPLink
*plink
)
856 icq_List
*plist
=plink
->received_queue
;
857 while(plist
->count
>0)
860 icq_Packet
*p
=icq_ListDequeue(plist
);
862 if(plink
->mode
& TCP_LINK_MODE_HELLOWAIT
)
864 icq_TCPProcessHello(p
, plink
);
869 switch (plink
->type
) {
871 case TCP_LINK_MESSAGE
:
872 icq_TCPProcessPacket(p
, plink
);
876 icq_TCPProcessChatPacket(p
, plink
);
880 icq_TCPProcessFilePacket(p
, plink
);
891 int _icq_FindTCPLink(void *p
, va_list data
)
893 icq_TCPLink
*plink
=(icq_TCPLink
*)p
;
894 unsigned long uin
=va_arg(data
, unsigned long);
895 int type
=va_arg(data
, int);
897 return ( (plink
->remote_uin
== uin
) && (plink
->type
== type
) );
900 icq_TCPLink
*icq_FindTCPLink(icq_Link
*icqlink
, unsigned long uin
, int type
)
902 return icq_ListTraverse(icqlink
->d
->icq_TCPLinks
, _icq_FindTCPLink
, uin
, type
);