Mercurial > pidgin.yaz
annotate plugins/icq/tcplink.c @ 1402:65f4a0325022
[gaim-migrate @ 1412]
whoops. this should work better.
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Thu, 11 Jan 2001 08:02:35 +0000 |
parents | 0a766047b4fd |
children | 4c510ca3563f |
rev | line source |
---|---|
1152 | 1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 /* | |
1309
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
3 $Id: tcplink.c 1319 2000-12-19 10:08:29Z warmenhoven $ |
1152 | 4 $Log$ |
1309
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
5 Revision 1.2 2000/12/19 10:08:29 warmenhoven |
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
6 Yay, new icqlib |
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
7 |
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
8 Revision 1.40 2000/12/19 06:00:07 bills |
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
9 moved members from ICQLINK to ICQLINK_private struct |
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
10 |
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
11 Revision 1.39 2000/12/03 21:57:15 bills |
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
12 fixed bug #105068 |
1152 | 13 |
14 Revision 1.38 2000/07/09 22:19:35 bills | |
15 added new *Close functions, use *Close functions instead of *Delete | |
16 where correct, and misc cleanup | |
17 | |
18 Revision 1.37 2000/06/15 01:53:17 bills | |
19 added icq_TCPLinkSendSeq function | |
20 | |
21 Revision 1.36 2000/05/04 15:57:20 bills | |
22 Reworked file transfer notification, small bugfixes, and cleanups. | |
23 | |
24 Revision 1.35 2000/05/03 18:29:15 denis | |
25 Callbacks have been moved to the ICQLINK structure. | |
26 | |
27 Revision 1.34 2000/04/10 18:11:45 denis | |
28 ANSI cleanups. | |
29 | |
30 Revision 1.33 2000/04/10 16:36:04 denis | |
31 Some more Win32 compatibility from Guillaume Rosanis <grs@mail.com> | |
32 | |
33 Revision 1.32 2000/04/05 14:37:02 denis | |
34 Applied patch from "Guillaume R." <grs@mail.com> for basic Win32 | |
35 compatibility. | |
36 | |
37 Revision 1.31 2000/02/15 04:00:16 bills | |
38 new icq_ChatRusConv_n function | |
39 | |
40 Revision 1.30 2000/02/07 02:46:29 bills | |
41 implemented non-blocking TCP connects over SOCKS, cyrillic translation for chat | |
42 | |
43 Revision 1.29 2000/01/20 19:59:35 bills | |
44 fixed bug in icq_TCPLinkConnect that caused file/chat connection attempts | |
45 to go to the wrong port | |
46 | |
47 Revision 1.28 2000/01/16 03:59:10 bills | |
48 reworked list code so list_nodes don't need to be inside item structures, | |
49 removed strlist code and replaced with generic list calls | |
50 | |
51 Revision 1.27 1999/12/27 16:13:29 bills | |
52 fixed bug in icq_TCPOnDataReceived, removed flags variable ;) | |
53 | |
54 Revision 1.26 1999/12/27 10:56:10 denis | |
55 Unused "flags" variable commented out. | |
56 | |
57 Revision 1.25 1999/12/21 00:30:53 bills | |
58 added icq_TCPLinkProcessReceived to support processing receive queue | |
59 before delete (packets used to get dropped in this instance, oops), | |
60 reworked icq_TCPLinkOnDataReceived to handle quick, large streams of data, | |
61 changed icq_TCPLinkOnConnect and *Accept to make all sockets non-blocking. | |
62 | |
63 Revision 1.24 1999/12/14 03:33:34 bills | |
64 icq_TCPLinkConnect now uses real_ip when our IP is same as remote IP to make | |
65 connection, added code to implement connect timeout | |
66 | |
67 Revision 1.23 1999/11/30 09:57:44 bills | |
68 buffer overflow check added, tcplinks will now close if buffer overflows. | |
69 increased icq_TCPLinkBufferSize to 4096 to support file transfer packets | |
70 | |
71 Revision 1.22 1999/11/29 17:15:51 denis | |
72 Absence of socklen_t type fixed. | |
73 | |
74 Revision 1.21 1999/10/01 00:49:21 lord | |
75 some compilation problems are fixed. | |
76 | |
77 Revision 1.20 1999/09/29 20:26:41 bills | |
78 ack forgot the args :) | |
79 | |
80 Revision 1.19 1999/09/29 20:21:45 bills | |
81 renamed denis' new function | |
82 | |
83 Revision 1.18 1999/09/29 20:11:29 bills | |
84 renamed tcp_link* to icq_TCPLink*. many cleanups, added icq_TCPLinkOnConnect | |
85 | |
86 Revision 1.17 1999/09/29 17:10:05 denis | |
87 TCP code SOCKS-ification. Not finished. | |
88 | |
89 Revision 1.16 1999/07/18 20:21:34 bills | |
90 fixed fail notification bug introduced during ICQLINK changes, changed to | |
91 use new byte-order functions & contact list functions, added better log | |
92 messages | |
93 | |
94 Revision 1.15 1999/07/16 15:45:57 denis | |
95 Cleaned up. | |
96 | |
97 Revision 1.14 1999/07/16 12:02:58 denis | |
98 tcp_packet* functions renamed to icq_Packet* | |
99 Cleaned up. | |
100 | |
101 Revision 1.13 1999/07/12 15:13:36 cproch | |
102 - added definition of ICQLINK to hold session-specific global variabled | |
103 applications which have more than one connection are now possible | |
104 - changed nearly every function defintion to support ICQLINK parameter | |
105 | |
106 Revision 1.12 1999/07/03 06:33:51 lord | |
107 . byte order conversion macros added | |
108 . some compilation warnings removed | |
109 | |
110 Revision 1.11 1999/06/30 13:52:23 bills | |
111 implemented non-blocking connects | |
112 | |
113 Revision 1.10 1999/05/03 21:39:41 bills | |
114 removed exit calls | |
115 | |
116 Revision 1.9 1999/04/29 09:35:54 denis | |
117 Cleanups, warning removed | |
118 | |
119 Revision 1.8 1999/04/17 19:34:49 bills | |
120 fixed bug in icq_TCPLinkOnDataReceived, multiple packets that come in on | |
121 one recv call are now handled correctly. added icq_TCPLinkAccept and | |
122 icq_TCPLinkListen. started using mode and type structure entries. added | |
123 icq_TCPLinks list and icq_FindTCPLink function. changed received_queue and | |
124 send_queue to lists. | |
125 | |
126 Revision 1.7 1999/04/14 15:02:45 denis | |
127 Cleanups for "strict" compiling (-ansi -pedantic) | |
128 | |
129 Revision 1.6 1999/04/05 18:47:17 bills | |
130 initial chat support implemented | |
131 | |
132 Revision 1.5 1999/03/31 01:50:54 bills | |
133 wrapped up many tcp details- tcp code now handles incoming and outgoing | |
134 tcp messages and urls! | |
135 | |
136 Revision 1.4 1999/03/28 03:27:49 bills | |
137 fixed icq_TCPLinkConnect so it really connects to remote ip instead of | |
138 always my local test computer O:) | |
139 | |
140 Revision 1.3 1999/03/26 20:02:41 bills | |
141 fixed C++ comments, cleaned up | |
142 | |
143 Revision 1.2 1999/03/25 22:21:59 bills | |
144 added necessary includes | |
145 | |
146 Revision 1.1 1999/03/25 21:09:07 bills | |
147 tcp link functions | |
148 */ | |
149 | |
150 #include <stdlib.h> | |
151 | |
152 #ifndef _WIN32 | |
153 #include <unistd.h> | |
154 #endif | |
155 | |
156 #include <fcntl.h> | |
157 #include <stdarg.h> | |
158 #include <errno.h> | |
159 #include <sys/types.h> | |
160 | |
161 #ifdef _WIN32 | |
162 #include <winsock.h> | |
163 #define EINPROGRESS WSAEINPROGRESS | |
164 #define ENETUNREACH WSAENETUNREACH | |
165 #define ECONNREFUSED WSAECONNREFUSED | |
166 #define ETIMEDOUT WSAETIMEDOUT | |
167 #define EOPNOTSUPP WSAEOPNOTSUPP | |
168 #define EAFNOSUPPORT WSAEAFNOSUPPORT | |
169 #define EWOULDBLOCK WSAEWOULDBLOCK | |
170 #else | |
171 #include <sys/socket.h> | |
172 #include <netdb.h> | |
173 #endif | |
174 | |
175 #include "icqtypes.h" | |
176 #include "icq.h" | |
177 #include "icqlib.h" | |
178 #include "tcplink.h" | |
179 #include "stdpackets.h" | |
180 #include "util.h" | |
181 #include "tcp.h" | |
182 #include "errno.h" | |
183 #include "chatsession.h" | |
184 #include "filesession.h" | |
185 | |
186 icq_TCPLink *icq_TCPLinkNew(ICQLINK *link) | |
187 { | |
188 icq_TCPLink *p=(icq_TCPLink *)malloc(sizeof(icq_TCPLink)); | |
189 | |
190 p->socket=-1; | |
191 p->icqlink=link; | |
192 p->mode=0; | |
193 p->session=0L; | |
194 p->type=TCP_LINK_MESSAGE; | |
195 p->buffer_count=0; | |
196 p->send_queue=list_new(); | |
197 p->received_queue=list_new(); | |
198 p->id=0; | |
199 p->remote_uin=0; | |
200 p->remote_version=0; | |
201 p->flags=0; | |
202 p->proxy_status = 0; | |
203 | |
204 if(p) | |
1309
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
205 list_enqueue(link->d->icq_TCPLinks, p); |
1152 | 206 |
207 return p; | |
208 } | |
209 | |
210 int _icq_TCPLinkDelete(void *pv, va_list data) | |
211 { | |
212 icq_Packet *p=(icq_Packet *)pv; | |
213 ICQLINK *icqlink=va_arg(data, ICQLINK *); | |
214 | |
215 /* notify the app the packet didn't make it */ | |
216 if(p->id) | |
217 (*icqlink->icq_RequestNotify)(icqlink, p->id, ICQ_NOTIFY_FAILED, 0, 0); | |
218 | |
219 return 0; | |
220 } | |
221 | |
222 void icq_TCPLinkDelete(void *pv) | |
223 { | |
224 icq_TCPLink *p=(icq_TCPLink *)pv; | |
225 | |
226 /* process anything left in the received queue */ | |
227 icq_TCPLinkProcessReceived(p); | |
228 | |
229 /* make sure we notify app that packets in send queue didn't make it */ | |
230 (void)list_traverse(p->send_queue, _icq_TCPLinkDelete, p->icqlink); | |
231 | |
232 /* destruct all packets still waiting on queues */ | |
233 list_delete(p->send_queue, icq_PacketDelete); | |
234 list_delete(p->received_queue, icq_PacketDelete); | |
235 | |
236 /* notify app if this was a chat or file xfer session and there is an | |
237 * id assigned */ | |
238 if((p->type==TCP_LINK_CHAT || p->type==TCP_LINK_FILE) && p->id) | |
239 if(p->icqlink->icq_RequestNotify) | |
240 (*p->icqlink->icq_RequestNotify)(p->icqlink, p->id, ICQ_NOTIFY_SUCCESS, 0, 0); | |
241 | |
242 /* if this is a chat or file link, delete the associated session as | |
243 * well, but make sure we unassociate ourself first so the session | |
244 * doesn't try to close us */ | |
245 if(p->session) | |
246 { | |
247 if(p->type==TCP_LINK_CHAT) | |
248 { | |
249 icq_ChatSession *psession=p->session; | |
250 /*psession->tcplink=0L;*/ | |
251 icq_ChatSessionClose(psession); | |
252 } | |
253 | |
254 if(p->type==TCP_LINK_FILE) { | |
255 icq_FileSession *psession=p->session; | |
256 psession->tcplink=0L; | |
257 icq_FileSessionClose(psession); | |
258 } | |
259 } | |
260 | |
261 /* close the socket after we notify app so app can read errno if necessary */ | |
262 if (p->socket > -1) | |
263 { | |
264 #ifdef _WIN32 | |
265 closesocket(p->socket); | |
266 #else | |
267 close(p->socket); | |
268 #endif | |
269 } | |
270 | |
271 free(p); | |
272 } | |
273 | |
274 void icq_TCPLinkClose(icq_TCPLink *plink) | |
275 { | |
1309
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
276 list_remove(plink->icqlink->d->icq_TCPLinks, plink); |
1152 | 277 icq_TCPLinkDelete(plink); |
278 } | |
279 | |
280 int icq_TCPLinkProxyConnect(icq_TCPLink *plink, DWORD uin, int port) | |
281 { | |
282 struct sockaddr_in prsin; | |
283 struct hostent *host_struct; | |
284 int conct; | |
285 | |
286 (void)uin; (void)port; | |
287 | |
288 prsin.sin_addr.s_addr = htonl(plink->icqlink->icq_ProxyIP); | |
289 if(prsin.sin_addr.s_addr == (unsigned long)-1) | |
290 { | |
291 prsin.sin_addr.s_addr = inet_addr(plink->icqlink->icq_ProxyHost); | |
292 if(prsin.sin_addr.s_addr == (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */ | |
293 { | |
294 host_struct = gethostbyname(plink->icqlink->icq_ProxyHost); | |
295 if(host_struct == 0L) | |
296 { | |
297 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Can't find hostname: %s\n", | |
298 plink->icqlink->icq_ProxyHost); | |
299 return -1; | |
300 } | |
301 prsin.sin_addr = *((struct in_addr *)host_struct->h_addr); | |
302 } | |
303 } | |
304 prsin.sin_family = AF_INET; /* we're using the inet not appletalk*/ | |
305 prsin.sin_port = htons(plink->icqlink->icq_ProxyPort); /* port */ | |
306 /* flags = fcntl(plink->socket, F_GETFL, 0); */ | |
307 /* fcntl(plink->socket, F_SETFL, flags & (~O_NONBLOCK)); */ | |
308 plink->mode |= TCP_LINK_SOCKS_CONNECTING; | |
309 conct = connect(plink->socket, (struct sockaddr *) &prsin, sizeof(prsin)); | |
310 if(conct == -1) /* did we connect ?*/ | |
311 { | |
312 if(errno != EINPROGRESS) | |
313 { | |
314 conct = errno; | |
315 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); | |
316 return conct; | |
317 } | |
318 return 1; | |
319 } | |
320 return 0; | |
321 } | |
322 | |
323 int icq_TCPLinkProxyRequestAuthorization(icq_TCPLink *plink) | |
324 { | |
325 char buf[1024]; | |
326 | |
327 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_CONNECTING)); | |
328 buf[0] = 5; /* protocol version */ | |
329 buf[1] = 1; /* number of methods */ | |
330 if(!strlen(plink->icqlink->icq_ProxyName) || !strlen(plink->icqlink->icq_ProxyPass) || | |
331 !plink->icqlink->icq_ProxyAuth) | |
332 { | |
333 buf[2] = 0; /* no authorization required */ | |
334 plink->mode |= TCP_LINK_SOCKS_NOAUTHSTATUS; | |
335 } | |
336 else | |
337 { | |
338 buf[2] = 2; /* method username/password */ | |
339 plink->mode |= TCP_LINK_SOCKS_AUTHORIZATION; | |
340 } | |
341 #ifdef _WIN32 | |
342 if(send(plink->socket, buf, 3, 0) != 3) | |
343 return errno; | |
344 #else | |
345 if(write(plink->socket, buf, 3) != 3) | |
346 return errno; | |
347 #endif | |
348 return 0; | |
349 } | |
350 | |
351 int icq_TCPLinkProxyAuthorization(icq_TCPLink *plink) | |
352 { | |
353 int res; | |
354 char buf[1024]; | |
355 | |
356 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_AUTHORIZATION)) | TCP_LINK_SOCKS_AUTHSTATUS; | |
357 #ifdef _WIN32 | |
358 res = recv(plink->socket, buf, 2, 0); | |
359 #else | |
360 res = read(plink->socket, buf, 2); | |
361 #endif | |
362 if(res != 2 || buf[0] != 5 || buf[1] != 2) /* username/password authentication*/ | |
363 { | |
364 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); | |
365 #ifdef _WIN32 | |
366 closesocket(plink->socket); | |
367 #else | |
368 close(plink->socket); | |
369 #endif | |
370 return -1; | |
371 } | |
372 buf[0] = 1; /* version of subnegotiation */ | |
373 buf[1] = strlen(plink->icqlink->icq_ProxyName); | |
374 memcpy(&buf[2], plink->icqlink->icq_ProxyName, buf[1]); | |
375 buf[2+buf[1]] = strlen(plink->icqlink->icq_ProxyPass); | |
376 memcpy(&buf[3+buf[1]], plink->icqlink->icq_ProxyPass, buf[2+buf[1]]); | |
377 #ifdef _WIN32 | |
378 if(send(plink->socket, buf, buf[1]+buf[2+buf[1]]+3, 0) != buf[1] + buf[2+buf[1]]+3) | |
379 return errno; | |
380 #else | |
381 if(write(plink->socket, buf, buf[1]+buf[2+buf[1]]+3) != buf[1] + buf[2+buf[1]]+3) | |
382 return errno; | |
383 #endif | |
384 return 0; | |
385 } | |
386 | |
387 int icq_TCPLinkProxyAuthStatus(icq_TCPLink *plink) | |
388 { | |
389 int res; | |
390 char buf[20]; | |
391 | |
392 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_AUTHSTATUS)) | TCP_LINK_SOCKS_CROSSCONNECT; | |
393 #ifdef _WIN32 | |
394 res = recv(plink->socket, buf, 2, 0); | |
395 #else | |
396 res = read(plink->socket, buf, 2); | |
397 #endif | |
398 if(res != 2 || buf[0] != 1 || buf[1] != 0) | |
399 { | |
400 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authorization failure\n"); | |
401 #ifdef _WIN32 | |
402 closesocket(plink->socket); | |
403 #else | |
404 close(plink->socket); | |
405 #endif | |
406 return -1; | |
407 } | |
408 return 0; | |
409 } | |
410 | |
411 int icq_TCPLinkProxyNoAuthStatus(icq_TCPLink *plink) | |
412 { | |
413 int res; | |
414 char buf[20]; | |
415 | |
416 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_NOAUTHSTATUS)) | TCP_LINK_SOCKS_CROSSCONNECT; | |
417 #ifdef _WIN32 | |
418 res = recv(plink->socket, buf, 2, 0); | |
419 #else | |
420 res = read(plink->socket, buf, 2); | |
421 #endif | |
422 if(res != 2 || buf[0] != 5 || buf[1] != 0) /* no authentication required */ | |
423 { | |
424 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); | |
425 #ifdef _WIN32 | |
426 closesocket(plink->socket); | |
427 #else | |
428 close(plink->socket); | |
429 #endif | |
430 return -1; | |
431 } | |
432 return 0; | |
433 } | |
434 | |
435 int icq_TCPLinkProxyCrossConnect(icq_TCPLink *plink) | |
436 { | |
437 char buf[20]; | |
438 | |
439 plink->mode = (plink->mode & ~(TCP_LINK_SOCKS_CROSSCONNECT)) | TCP_LINK_SOCKS_CONNSTATUS; | |
440 buf[0] = 5; /* protocol version */ | |
441 buf[1] = 1; /* command connect */ | |
442 buf[2] = 0; /* reserved */ | |
443 buf[3] = 1; /* address type IP v4 */ | |
444 memcpy(&buf[4], &plink->remote_address.sin_addr.s_addr, 4); | |
445 memcpy(&buf[8], &plink->remote_address.sin_port, 2); | |
446 #ifdef _WIN32 | |
447 if(send(plink->socket, buf, 10, 0) != 10) | |
448 return errno; | |
449 #else | |
450 if(write(plink->socket, buf, 10) != 10) | |
451 return errno; | |
452 #endif | |
453 return 0; | |
454 } | |
455 | |
456 int icq_TCPLinkProxyConnectStatus(icq_TCPLink *plink) | |
457 { | |
458 int res; | |
459 char buf[1024]; | |
460 | |
461 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_CONNSTATUS)); | |
462 #ifdef _WIN32 | |
463 res = recv(plink->socket, buf, 10, 0); | |
464 #else | |
465 res = read(plink->socket, buf, 10); | |
466 #endif | |
467 if(res != 10 || buf[0] != 5 || buf[1] != 0) | |
468 { | |
469 switch(buf[1]) | |
470 { | |
471 case 1: | |
472 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] General SOCKS server failure\n"); | |
473 res = EFAULT; | |
474 break; | |
475 case 2: | |
476 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection not allowed by ruleset\n"); | |
477 res = EACCES; | |
478 break; | |
479 case 3: | |
480 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Network unreachable\n"); | |
481 res = ENETUNREACH; | |
482 break; | |
483 case 4: | |
484 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Host unreachable\n"); | |
485 res = ENETUNREACH; | |
486 break; | |
487 case 5: | |
488 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); | |
489 res = ECONNREFUSED; | |
490 break; | |
491 case 6: | |
492 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] TTL expired\n"); | |
493 res = ETIMEDOUT; | |
494 break; | |
495 case 7: | |
496 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Command not supported\n"); | |
497 res = EOPNOTSUPP; | |
498 break; | |
499 case 8: | |
500 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Address type not supported\n"); | |
501 res = EAFNOSUPPORT; | |
502 break; | |
503 default: | |
504 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Unknown SOCKS server failure\n"); | |
505 res = EFAULT; | |
506 break; | |
507 } | |
508 #ifdef _WIN32 | |
509 closesocket(plink->socket); | |
510 #else | |
511 close(plink->socket); | |
512 #endif | |
513 return res; | |
514 } | |
515 return 0; | |
516 } | |
517 | |
518 int icq_TCPLinkConnect(icq_TCPLink *plink, DWORD uin, int port) | |
519 { | |
520 icq_ContactItem *pcontact=icq_ContactFind(plink->icqlink, uin); | |
521 icq_Packet *p; | |
522 int result; | |
523 | |
524 #ifndef _WIN32 | |
525 int flags; | |
526 #else | |
527 u_long iosflag; | |
528 #endif | |
529 | |
530 /* these return values never and nowhere checked */ | |
531 /* denis. */ | |
532 if(!pcontact) | |
533 return -2; | |
534 | |
535 if((plink->socket=socket(AF_INET, SOCK_STREAM, 0)) < 0) | |
536 return -3; | |
537 | |
538 /* bzero(&(plink->remote_address), sizeof(plink->remote_address)); Win32 incompatible... */ | |
539 memset(&(plink->remote_address), 0, sizeof(plink->remote_address)); | |
540 plink->remote_address.sin_family = AF_INET; | |
541 | |
542 /* if our IP is the same as the remote user's ip, connect to real_ip | |
543 instead since we're both probably behind a firewall */ | |
544 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
545 "local IP is %08X:%d, remote real IP is %08X:%d, remote IP is %08X:%d, port is %d\n", | |
546 plink->icqlink->icq_OurIP, | |
547 plink->icqlink->icq_OurPort, | |
548 pcontact->remote_real_ip, | |
549 pcontact->remote_port, | |
550 pcontact->remote_ip, | |
551 pcontact->remote_port, | |
552 port | |
553 ); | |
554 if (plink->icqlink->icq_OurIP == pcontact->remote_ip) | |
555 plink->remote_address.sin_addr.s_addr = htonl(pcontact->remote_real_ip); | |
556 else | |
557 plink->remote_address.sin_addr.s_addr = htonl(pcontact->remote_ip); | |
558 | |
559 if(plink->type==TCP_LINK_MESSAGE) | |
560 { | |
561 plink->remote_address.sin_port = htons(pcontact->remote_port); | |
562 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
563 "initiating message connect to %d (%s:%d)\n", uin, | |
564 inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), | |
565 pcontact->remote_port); | |
566 } | |
567 else | |
568 { | |
569 plink->remote_address.sin_port = htons(port); | |
570 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
571 "initiating file/chat connect to %d (%s:%d)\n", uin, | |
572 inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), | |
573 port); | |
574 } | |
575 | |
576 /* set the socket to non-blocking */ | |
577 #ifdef _WIN32 | |
578 iosflag = TRUE; | |
579 ioctlsocket(plink->socket, FIONBIO, &iosflag); | |
580 #else | |
581 flags=fcntl(plink->socket, F_GETFL, 0); | |
582 fcntl(plink->socket, F_SETFL, flags | O_NONBLOCK); | |
583 #endif | |
584 | |
585 if(!plink->icqlink->icq_UseProxy) | |
586 result=connect(plink->socket, (struct sockaddr *)&(plink->remote_address), | |
587 sizeof(plink->remote_address)); | |
588 else /* SOCKS proxy support */ | |
589 result=icq_TCPLinkProxyConnect(plink, uin, port); | |
590 /* FIXME: Here we should check for errors on connection */ | |
591 /* because of proxy support - it can't be checked */ | |
592 /* by getsockopt() later in _handle_ready_sockets() */ | |
593 /* denis. */ | |
594 | |
595 plink->mode|=TCP_LINK_MODE_CONNECTING; | |
596 | |
597 plink->remote_uin=uin; | |
598 | |
599 plink->connect_time=time(0L); | |
600 | |
601 /* Send the hello packet */ | |
602 p=icq_TCPCreateInitPacket(plink); | |
603 icq_TCPLinkSend(plink, p); | |
604 | |
605 #ifdef TCP_PACKET_TRACE | |
606 printf("hello packet queued for %lu\n", uin); | |
607 #endif /* TCP_PACKET_TRACE */ | |
608 | |
609 return 1; | |
610 } | |
611 | |
612 icq_TCPLink *icq_TCPLinkAccept(icq_TCPLink *plink) | |
613 { | |
614 #ifdef _WIN32 | |
615 u_long iosflag; | |
616 #else | |
617 int flags; | |
618 #endif | |
619 int socket; | |
620 size_t remote_length; | |
621 icq_TCPLink *pnewlink=icq_TCPLinkNew( plink->icqlink ); | |
622 | |
623 if(pnewlink) | |
624 { | |
625 socket=accept(plink->socket, (struct sockaddr *)&(plink->remote_address), | |
626 &remote_length); | |
627 | |
628 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
629 "accepting tcp connection from %s:%d\n", | |
630 inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), | |
631 ntohs(plink->remote_address.sin_port)); | |
632 | |
633 /* FIXME: make sure accept succeeded */ | |
634 | |
635 pnewlink->type=plink->type; | |
636 pnewlink->socket=socket; | |
637 | |
638 /* first packet sent on an icq tcp link is always the hello packet */ | |
639 pnewlink->mode|=TCP_LINK_MODE_HELLOWAIT; | |
640 } | |
641 | |
642 /* set the socket to non-blocking */ | |
643 #ifdef _WIN32 | |
644 iosflag = TRUE; | |
645 ioctlsocket(plink->socket, FIONBIO, &iosflag); | |
646 #else | |
647 flags=fcntl(pnewlink->socket, F_GETFL, 0); | |
648 fcntl(pnewlink->socket, F_SETFL, flags | O_NONBLOCK); | |
649 #endif | |
650 | |
651 return pnewlink; | |
652 } | |
653 | |
654 int icq_TCPLinkListen(icq_TCPLink *plink) | |
655 { | |
656 unsigned int t; | |
657 | |
658 /* listening links have 0 uin */ | |
659 plink->remote_uin=0; | |
660 | |
661 /* create tcp listen socket */ | |
662 if((plink->socket=socket(AF_INET, SOCK_STREAM, 0)) < 0) | |
663 return -1; | |
664 | |
665 /* must use memset, no bzero for Win32! */ | |
666 memset(&plink->socket_address, 0, sizeof(struct sockaddr_in)); | |
667 plink->socket_address.sin_family=AF_INET; | |
668 plink->socket_address.sin_addr.s_addr=htonl(INADDR_ANY); | |
669 plink->socket_address.sin_port=0; | |
670 | |
671 if(bind(plink->socket, (struct sockaddr *)&plink->socket_address, sizeof(struct sockaddr_in)) < 0) | |
672 return -2; | |
673 | |
674 if(listen(plink->socket, 5) < 0) | |
675 return -3; | |
676 | |
677 t=sizeof(struct sockaddr_in); | |
678 if(getsockname(plink->socket, (struct sockaddr *)&plink->socket_address, &t) < 0) | |
679 return -4; | |
680 | |
681 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
682 "created tcp listening socket %d, local address=%s:%d\n", | |
683 plink->socket, | |
684 inet_ntoa(*((struct in_addr *)(&plink->socket_address.sin_addr))), | |
685 ntohs(plink->socket_address.sin_port)); | |
686 | |
687 plink->mode|=TCP_LINK_MODE_LISTEN; | |
688 | |
689 return 0; | |
690 } | |
691 | |
692 /* Doing Cyrillic translations for Chat dialog sessions */ | |
693 void icq_ChatRusConv_n(const char to[4], char *t_in, int t_len) | |
694 { | |
695 int i, j; | |
696 | |
697 for(i = j = 0; i < t_len; ++i) | |
698 { | |
699 if((((unsigned char)t_in[i]) < ' ') && (t_in[i] != '\r')) | |
700 { | |
701 if(i - 1 > j) | |
702 icq_RusConv_n(to, &t_in[j], i - j - 1); | |
703 switch(t_in[i]) | |
704 { | |
705 case '\x07': /* Bell */ | |
706 case '\x08': /* BackSpace */ | |
707 case '\x03': /* Chat is active */ | |
708 case '\x04': /* Chat is not active */ | |
709 break; | |
710 case '\x00': /* Foregroung color (RR GG BB ?? ) */ | |
711 case '\x01': /* Background color (RR GG BB ?? ) */ | |
712 case '\x11': /* Font style change (Bold - 1, Italic - 2, Underline - 4) */ | |
713 case '\x12': /* Font size change */ | |
714 i += 4; | |
715 break; | |
716 case '\x10': /* Font family and encoding change */ | |
717 i += t_in[i+1] + 2 + 2; | |
718 icq_RusConv_n(to, &t_in[i+3], t_in[i+1]); | |
719 break; | |
720 } | |
721 j = i + 1; | |
722 } | |
723 } | |
724 if(i > t_len) | |
725 i = t_len; | |
726 if(j > t_len) | |
727 j = t_len; | |
728 if(i > j) | |
729 icq_RusConv_n(to, &t_in[j], i - j); | |
730 } | |
731 | |
732 int icq_TCPLinkOnDataReceived(icq_TCPLink *plink) | |
733 { | |
734 int process_count=0, recv_result=0; | |
735 char *buffer=plink->buffer; | |
736 | |
737 do { /* while recv_result > 0 */ | |
738 | |
739 int done=0; | |
740 | |
741 /* append received data onto end of buffer */ | |
742 if((recv_result=recv(plink->socket, buffer+plink->buffer_count, | |
743 icq_TCPLinkBufferSize-plink->buffer_count, 0)) < 1) | |
744 { | |
745 /* either there was an error or the remote side has closed | |
746 * the connection - fall out of the loop */ | |
747 continue; | |
748 }; | |
749 | |
750 plink->buffer_count+=recv_result; | |
751 | |
752 #ifdef TCP_BUFFER_TRACE | |
753 printf("received %d bytes from link %x, new buffer count %d\n", | |
754 recv_result, plink, plink->buffer_count); | |
755 | |
756 hex_dump(plink->buffer, plink->buffer_count); | |
757 #endif /*TCP_BUFFER_TRACE*/ | |
758 | |
759 process_count+=recv_result; | |
760 | |
761 /* don't do any packet processing if we're in raw mode */ | |
762 if(plink->mode & TCP_LINK_MODE_RAW) { | |
763 /* notify the app with the new data */ | |
764 if(plink->type == TCP_LINK_CHAT) | |
765 icq_ChatRusConv_n("wk", plink->buffer, plink->buffer_count); | |
766 if(plink->icqlink->icq_RequestNotify) | |
767 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, plink->id, ICQ_NOTIFY_CHATDATA, | |
768 plink->buffer_count, plink->buffer); | |
769 plink->buffer_count=0; | |
770 continue; | |
771 } | |
772 | |
773 /* remove packets from the buffer until the buffer is empty | |
774 * or the remaining bytes do not equal a full packet */ | |
775 while((unsigned)plink->buffer_count>sizeof(WORD) && !done) | |
776 { | |
777 WORD packet_size=(*((WORD *)buffer)); | |
778 | |
779 /* warn if the buffer is too small to hold the whole packet */ | |
780 if(packet_size>icq_TCPLinkBufferSize-sizeof(WORD)) | |
781 { | |
782 icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "tcplink buffer " | |
783 "overflow, packet size = %d, buffer size = %d, closing link\n", | |
784 packet_size, icq_TCPLinkBufferSize); | |
785 return 0; | |
786 } | |
787 | |
788 if(packet_size+sizeof(WORD) <= (unsigned)plink->buffer_count) | |
789 { | |
790 /* copy the packet into memory */ | |
791 icq_Packet *p=icq_PacketNew(); | |
792 icq_PacketAppend(p, buffer+sizeof(WORD), packet_size); | |
793 | |
794 /* remove it from the buffer */ | |
795 memcpy(buffer, buffer+packet_size+sizeof(WORD), | |
796 plink->buffer_count-packet_size-sizeof(WORD)); | |
797 | |
798 plink->buffer_count-=(packet_size+sizeof(WORD)); | |
799 | |
800 icq_TCPLinkOnPacketReceived(plink, p); | |
801 } | |
802 else | |
803 { | |
804 /* not enough bytes in buffer to form the complete packet. | |
805 * we're done for now */ | |
806 done=1; | |
807 } | |
808 } /* while packets remain in buffer */ | |
809 | |
810 } while (recv_result > 0); | |
811 | |
812 if (recv_result < 0 && errno!=EWOULDBLOCK) { | |
813 | |
814 /* receive error - log it */ | |
815 icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "recv failed from %d (%d-%s)," | |
816 " closing link\n", plink->remote_uin, errno, strerror(errno)); | |
817 | |
818 } | |
819 | |
820 return process_count; | |
821 } | |
822 | |
823 void icq_TCPLinkOnPacketReceived(icq_TCPLink *plink, icq_Packet *p) | |
824 { | |
825 | |
826 #ifdef TCP_RAW_TRACE | |
827 printf("packet received! { length=%d }\n", p->length); | |
828 icq_PacketDump(p); | |
829 #endif | |
830 | |
831 /* Stick packet on ready packet linked list */ | |
832 list_enqueue(plink->received_queue, p); | |
833 } | |
834 | |
835 void icq_TCPLinkOnConnect(icq_TCPLink *plink) | |
836 { | |
837 #ifdef _WIN32 | |
838 int len; | |
839 #else | |
840 size_t len; | |
841 #endif | |
842 int error; | |
843 | |
844 /* check getsockopt */ | |
845 len=sizeof(error); | |
846 | |
847 #ifdef _WIN32 | |
848 getsockopt(plink->socket, SOL_SOCKET, SO_ERROR, (char *)&error, &len); | |
849 #else | |
850 getsockopt(plink->socket, SOL_SOCKET, SO_ERROR, &error, &len); | |
851 #endif | |
852 if(!error && (plink->mode & (TCP_LINK_SOCKS_CONNECTING | TCP_LINK_SOCKS_AUTHORIZATION | | |
853 TCP_LINK_SOCKS_AUTHSTATUS | TCP_LINK_SOCKS_NOAUTHSTATUS | | |
854 TCP_LINK_SOCKS_CROSSCONNECT | TCP_LINK_SOCKS_CONNSTATUS))) | |
855 { | |
856 if(plink->mode & TCP_LINK_SOCKS_CONNECTING) | |
857 error = icq_TCPLinkProxyRequestAuthorization(plink); | |
858 else if(plink->mode & TCP_LINK_SOCKS_AUTHORIZATION) | |
859 error = icq_TCPLinkProxyAuthorization(plink); | |
860 else if(plink->mode & TCP_LINK_SOCKS_AUTHSTATUS) | |
861 error = icq_TCPLinkProxyAuthStatus(plink); | |
862 else if(plink->mode & TCP_LINK_SOCKS_NOAUTHSTATUS) | |
863 error = icq_TCPLinkProxyNoAuthStatus(plink); | |
864 else if(plink->mode & TCP_LINK_SOCKS_CROSSCONNECT) | |
865 error = icq_TCPLinkProxyCrossConnect(plink); | |
866 else if(plink->mode & TCP_LINK_SOCKS_CONNSTATUS) | |
867 error = icq_TCPLinkProxyConnectStatus(plink); | |
868 else | |
869 error = EINVAL; | |
870 } | |
871 | |
872 if(error) | |
873 { | |
874 /* connection failed- close the link, which takes care | |
875 * of notifying the app about packets that didn't make it */ | |
876 icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "connect failed to %d (%d-%s)," | |
877 " closing link\n", plink->remote_uin, error, strerror(error)); | |
878 | |
879 icq_TCPLinkClose(plink); | |
880 return; | |
881 } | |
882 | |
883 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)) | |
884 return; | |
885 | |
886 len=sizeof(plink->socket_address); | |
887 getsockname(plink->socket, (struct sockaddr *)&plink->socket_address, &len); | |
888 | |
889 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
890 "connected to uin %d, socket=%d local address=%s:%d remote address=%s:%d\n", | |
891 plink->remote_uin, plink->socket, | |
892 inet_ntoa(*((struct in_addr *)(&plink->socket_address.sin_addr))), | |
893 ntohs(plink->socket_address.sin_port), | |
894 inet_ntoa(*((struct in_addr *)(&plink->remote_address.sin_addr))), | |
895 ntohs(plink->remote_address.sin_port)); | |
896 | |
897 plink->mode&= ~TCP_LINK_MODE_CONNECTING; | |
898 | |
899 /* socket is now connected, notify each request that connection | |
900 * has been established and send pending data */ | |
901 while(plink->send_queue->count>0) | |
902 { | |
903 icq_Packet *p=list_dequeue(plink->send_queue); | |
904 if(p->id) | |
905 if(plink->icqlink->icq_RequestNotify) | |
906 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTED, 0, 0); | |
907 icq_TCPLinkSend(plink, p); | |
908 } | |
909 | |
910 /* yeah this probably shouldn't be here. oh well :) */ | |
911 if(plink->type==TCP_LINK_CHAT) | |
912 { | |
913 icq_ChatSessionSetStatus((icq_ChatSession *)plink->session, | |
914 CHAT_STATUS_CONNECTED); | |
915 icq_ChatSessionSetStatus((icq_ChatSession *)plink->session, | |
916 CHAT_STATUS_WAIT_ALLINFO); | |
917 } | |
918 | |
919 if(plink->type==TCP_LINK_FILE) | |
920 { | |
921 icq_FileSessionSetStatus((icq_FileSession *)plink->session, | |
922 FILE_STATUS_CONNECTED); | |
923 } | |
924 | |
925 } | |
926 | |
927 unsigned long icq_TCPLinkSendSeq(icq_TCPLink *plink, icq_Packet *p, | |
928 unsigned long sequence) | |
929 { | |
930 /* append the next sequence number on the packet */ | |
931 if (!sequence) | |
1309
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
932 sequence=plink->icqlink->d->icq_TCPSequence--; |
1152 | 933 p->id=sequence; |
934 icq_PacketEnd(p); | |
935 icq_PacketAppend32(p, sequence); | |
936 | |
937 /* if the link is currently connecting, queue the packets for | |
938 * later, else send immediately */ | |
939 if(plink->mode & TCP_LINK_MODE_CONNECTING) { | |
940 list_insert(plink->send_queue, 0, p); | |
941 if(plink->icqlink->icq_RequestNotify) | |
942 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTING, 0, 0); | |
943 } else { | |
944 icq_PacketSend(p, plink->socket); | |
945 if(p->id) | |
946 if(plink->icqlink->icq_RequestNotify) | |
947 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_SENT, 0, 0); | |
948 icq_PacketDelete(p); | |
949 } | |
950 return sequence; | |
951 } | |
952 | |
953 void icq_TCPLinkSend(icq_TCPLink *plink, icq_Packet *p) | |
954 { | |
955 /* if the link is currently connecting, queue the packets for | |
956 * later, else send immediately */ | |
957 if(plink->mode & TCP_LINK_MODE_CONNECTING) { | |
958 list_insert(plink->send_queue, 0, p); | |
959 if(plink->icqlink->icq_RequestNotify) | |
960 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTING, 0, 0); | |
961 } else { | |
962 icq_PacketSend(p, plink->socket); | |
963 if(p->id) | |
964 if(plink->icqlink->icq_RequestNotify) | |
965 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_SENT, 0, 0); | |
966 icq_PacketDelete(p); | |
967 } | |
968 } | |
969 | |
970 void icq_TCPLinkProcessReceived(icq_TCPLink *plink) | |
971 { | |
972 list *plist=plink->received_queue; | |
973 while(plist->count>0) | |
974 | |
975 { | |
976 icq_Packet *p=list_dequeue(plist); | |
977 | |
978 if(plink->mode & TCP_LINK_MODE_HELLOWAIT) | |
979 { | |
980 icq_TCPProcessHello(p, plink); | |
981 } | |
982 else | |
983 { | |
984 | |
985 switch (plink->type) { | |
986 | |
987 case TCP_LINK_MESSAGE: | |
988 icq_TCPProcessPacket(p, plink); | |
989 break; | |
990 | |
991 case TCP_LINK_CHAT: | |
992 icq_TCPProcessChatPacket(p, plink); | |
993 break; | |
994 | |
995 case TCP_LINK_FILE: | |
996 icq_TCPProcessFilePacket(p, plink); | |
997 break; | |
998 | |
999 } | |
1000 } | |
1001 | |
1002 icq_PacketDelete(p); | |
1003 } | |
1004 | |
1005 } | |
1006 | |
1007 int _icq_FindTCPLink(void *p, va_list data) | |
1008 { | |
1009 icq_TCPLink *plink=(icq_TCPLink *)p; | |
1010 unsigned long uin=va_arg(data, unsigned long); | |
1011 int type=va_arg(data, int); | |
1012 | |
1013 return ( (plink->remote_uin == uin ) && (plink->type == type) ); | |
1014 } | |
1015 | |
1016 icq_TCPLink *icq_FindTCPLink(ICQLINK *link, unsigned long uin, int type) | |
1017 { | |
1309
0a766047b4fd
[gaim-migrate @ 1319]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1152
diff
changeset
|
1018 return list_traverse(link->d->icq_TCPLinks, _icq_FindTCPLink, uin, type); |
1152 | 1019 } |