| |
1 /* $Id: dcc.c 16856 2006-08-19 01:13:25Z evands $ */ |
| |
2 |
| |
3 /* |
| |
4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> |
| |
5 * Tomasz Chiliński <chilek@chilan.com> |
| |
6 * |
| |
7 * This program is free software; you can redistribute it and/or modify |
| |
8 * it under the terms of the GNU Lesser General Public License Version |
| |
9 * 2.1 as published by the Free Software Foundation. |
| |
10 * |
| |
11 * This program is distributed in the hope that it will be useful, |
| |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
14 * GNU Lesser General Public License for more details. |
| |
15 * |
| |
16 * You should have received a copy of the GNU Lesser General Public |
| |
17 * License along with this program; if not, write to the Free Software |
| |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, |
| |
19 * USA. |
| |
20 */ |
| |
21 |
| |
22 #include <sys/types.h> |
| |
23 #include <sys/stat.h> |
| |
24 #ifndef _WIN32 |
| |
25 #include <sys/ioctl.h> |
| |
26 #include <sys/socket.h> |
| |
27 #include <netinet/in.h> |
| |
28 #include <arpa/inet.h> |
| |
29 #ifdef sun |
| |
30 # include <sys/filio.h> |
| |
31 #endif |
| |
32 #endif |
| |
33 |
| |
34 #include <ctype.h> |
| |
35 #include <errno.h> |
| |
36 #include <fcntl.h> |
| |
37 #include <stdarg.h> |
| |
38 #include <string.h> |
| |
39 #include <stdio.h> |
| |
40 #include <stdlib.h> |
| |
41 #include <unistd.h> |
| |
42 |
| |
43 #include "compat.h" |
| |
44 #include "libgadu.h" |
| |
45 |
| |
46 #ifndef GG_DEBUG_DISABLE |
| |
47 /* |
| |
48 * gg_dcc_debug_data() // funkcja wewnętrzna |
| |
49 * |
| |
50 * wyświetla zrzut pakietu w hexie. |
| |
51 * |
| |
52 * - prefix - prefiks zrzutu pakietu |
| |
53 * - fd - deskryptor gniazda |
| |
54 * - buf - bufor z danymi |
| |
55 * - size - rozmiar danych |
| |
56 */ |
| |
57 static void gg_dcc_debug_data(const char *prefix, int fd, const void *buf, unsigned int size) |
| |
58 { |
| |
59 unsigned int i; |
| |
60 |
| |
61 gg_debug(GG_DEBUG_MISC, "++ gg_dcc %s (fd=%d,len=%d)", prefix, fd, size); |
| |
62 |
| |
63 for (i = 0; i < size; i++) |
| |
64 gg_debug(GG_DEBUG_MISC, " %.2x", ((unsigned char*) buf)[i]); |
| |
65 |
| |
66 gg_debug(GG_DEBUG_MISC, "\n"); |
| |
67 } |
| |
68 #else |
| |
69 #define gg_dcc_debug_data(a,b,c,d) do { } while (0) |
| |
70 #endif |
| |
71 |
| |
72 /* |
| |
73 * gg_dcc_request() |
| |
74 * |
| |
75 * wysyła informację o tym, że dany klient powinien się z nami połączyć. |
| |
76 * wykorzystywane, kiedy druga strona, której chcemy coś wysłać jest za |
| |
77 * maskaradą. |
| |
78 * |
| |
79 * - sess - struktura opisująca sesję GG |
| |
80 * - uin - numerek odbiorcy |
| |
81 * |
| |
82 * patrz gg_send_message_ctcp(). |
| |
83 */ |
| |
84 int gg_dcc_request(struct gg_session *sess, uin_t uin) |
| |
85 { |
| |
86 return gg_send_message_ctcp(sess, GG_CLASS_CTCP, uin, (const unsigned char *)"\002", 1); |
| |
87 } |
| |
88 |
| |
89 /* |
| |
90 * gg_dcc_fill_filetime() // funkcja wewnętrzna |
| |
91 * |
| |
92 * zamienia czas w postaci unixowej na windowsowy. |
| |
93 * |
| |
94 * - unix - czas w postaci unixowej |
| |
95 * - filetime - czas w postaci windowsowej |
| |
96 */ |
| |
97 static void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft) |
| |
98 { |
| |
99 #ifdef __GG_LIBGADU_HAVE_LONG_LONG |
| |
100 unsigned long long tmp; |
| |
101 |
| |
102 tmp = ut; |
| |
103 tmp += 11644473600LL; |
| |
104 tmp *= 10000000LL; |
| |
105 |
| |
106 #ifndef __GG_LIBGADU_BIGENDIAN |
| |
107 ft[0] = (uint32_t) tmp; |
| |
108 ft[1] = (uint32_t) (tmp >> 32); |
| |
109 #else |
| |
110 ft[0] = gg_fix32((uint32_t) (tmp >> 32)); |
| |
111 ft[1] = gg_fix32((uint32_t) tmp); |
| |
112 #endif |
| |
113 |
| |
114 #endif |
| |
115 } |
| |
116 |
| |
117 /* |
| |
118 * gg_dcc_fill_file_info() |
| |
119 * |
| |
120 * wypełnia pola struct gg_dcc niezbędne do wysłania pliku. |
| |
121 * |
| |
122 * - d - struktura opisująca połączenie DCC |
| |
123 * - filename - nazwa pliku |
| |
124 * |
| |
125 * 0, -1. |
| |
126 */ |
| |
127 int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename) |
| |
128 { |
| |
129 return gg_dcc_fill_file_info2(d, filename, filename); |
| |
130 } |
| |
131 |
| |
132 /* |
| |
133 * gg_dcc_fill_file_info2() |
| |
134 * |
| |
135 * wypełnia pola struct gg_dcc niezbędne do wysłania pliku. |
| |
136 * |
| |
137 * - d - struktura opisująca połączenie DCC |
| |
138 * - filename - nazwa pliku |
| |
139 * - local_filename - nazwa na lokalnym systemie plików |
| |
140 * |
| |
141 * 0, -1. |
| |
142 */ |
| |
143 int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename) |
| |
144 { |
| |
145 struct stat st; |
| |
146 const char *name, *ext, *p; |
| |
147 unsigned char *q; |
| |
148 int i, j; |
| |
149 |
| |
150 gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_fill_file_info2(%p, \"%s\", \"%s\");\n", d, filename, local_filename); |
| |
151 |
| |
152 if (!d || d->type != GG_SESSION_DCC_SEND) { |
| |
153 gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() invalid arguments\n"); |
| |
154 errno = EINVAL; |
| |
155 return -1; |
| |
156 } |
| |
157 |
| |
158 if (stat(local_filename, &st) == -1) { |
| |
159 gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() stat() failed (%s)\n", strerror(errno)); |
| |
160 return -1; |
| |
161 } |
| |
162 |
| |
163 if ((st.st_mode & S_IFDIR)) { |
| |
164 gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() that's a directory\n"); |
| |
165 errno = EINVAL; |
| |
166 return -1; |
| |
167 } |
| |
168 |
| |
169 if ((d->file_fd = open(local_filename, O_RDONLY)) == -1) { |
| |
170 gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() open() failed (%s)\n", strerror(errno)); |
| |
171 return -1; |
| |
172 } |
| |
173 |
| |
174 memset(&d->file_info, 0, sizeof(d->file_info)); |
| |
175 |
| |
176 if (!(st.st_mode & S_IWUSR)) |
| |
177 d->file_info.mode |= gg_fix32(GG_DCC_FILEATTR_READONLY); |
| |
178 |
| |
179 gg_dcc_fill_filetime(st.st_atime, d->file_info.atime); |
| |
180 gg_dcc_fill_filetime(st.st_mtime, d->file_info.mtime); |
| |
181 gg_dcc_fill_filetime(st.st_ctime, d->file_info.ctime); |
| |
182 |
| |
183 d->file_info.size = gg_fix32(st.st_size); |
| |
184 d->file_info.mode = gg_fix32(0x20); /* FILE_ATTRIBUTE_ARCHIVE */ |
| |
185 |
| |
186 if (!(name = strrchr(filename, '/'))) |
| |
187 name = filename; |
| |
188 else |
| |
189 name++; |
| |
190 |
| |
191 if (!(ext = strrchr(name, '.'))) |
| |
192 ext = name + strlen(name); |
| |
193 |
| |
194 for (i = 0, p = name; i < 8 && p < ext; i++, p++) |
| |
195 d->file_info.short_filename[i] = toupper(name[i]); |
| |
196 |
| |
197 if (i == 8 && p < ext) { |
| |
198 d->file_info.short_filename[6] = '~'; |
| |
199 d->file_info.short_filename[7] = '1'; |
| |
200 } |
| |
201 |
| |
202 if (strlen(ext) > 0) { |
| |
203 for (j = 0; *ext && j < 4; j++, p++) |
| |
204 d->file_info.short_filename[i + j] = toupper(ext[j]); |
| |
205 } |
| |
206 |
| |
207 for (q = d->file_info.short_filename; *q; q++) { |
| |
208 if (*q == 185) { |
| |
209 *q = 165; |
| |
210 } else if (*q == 230) { |
| |
211 *q = 198; |
| |
212 } else if (*q == 234) { |
| |
213 *q = 202; |
| |
214 } else if (*q == 179) { |
| |
215 *q = 163; |
| |
216 } else if (*q == 241) { |
| |
217 *q = 209; |
| |
218 } else if (*q == 243) { |
| |
219 *q = 211; |
| |
220 } else if (*q == 156) { |
| |
221 *q = 140; |
| |
222 } else if (*q == 159) { |
| |
223 *q = 143; |
| |
224 } else if (*q == 191) { |
| |
225 *q = 175; |
| |
226 } |
| |
227 } |
| |
228 |
| |
229 gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() short name \"%s\", dos name \"%s\"\n", name, d->file_info.short_filename); |
| |
230 strncpy((char *)d->file_info.filename, name, sizeof(d->file_info.filename) - 1); |
| |
231 |
| |
232 return 0; |
| |
233 } |
| |
234 |
| |
235 /* |
| |
236 * gg_dcc_transfer() // funkcja wewnętrzna |
| |
237 * |
| |
238 * inicjuje proces wymiany pliku z danym klientem. |
| |
239 * |
| |
240 * - ip - adres ip odbiorcy |
| |
241 * - port - port odbiorcy |
| |
242 * - my_uin - własny numer |
| |
243 * - peer_uin - numer obiorcy |
| |
244 * - type - rodzaj wymiany (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_GET) |
| |
245 * |
| |
246 * zaalokowana struct gg_dcc lub NULL jeśli wystąpił błąd. |
| |
247 */ |
| |
248 static struct gg_dcc *gg_dcc_transfer(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin, int type) |
| |
249 { |
| |
250 struct gg_dcc *d = NULL; |
| |
251 struct in_addr addr; |
| |
252 |
| |
253 addr.s_addr = ip; |
| |
254 |
| |
255 gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_transfer(%s, %d, %ld, %ld, %s);\n", inet_ntoa(addr), port, my_uin, peer_uin, (type == GG_SESSION_DCC_SEND) ? "SEND" : "GET"); |
| |
256 |
| |
257 if (!ip || ip == INADDR_NONE || !port || !my_uin || !peer_uin) { |
| |
258 gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() invalid arguments\n"); |
| |
259 errno = EINVAL; |
| |
260 return NULL; |
| |
261 } |
| |
262 |
| |
263 if (!(d = (void*) calloc(1, sizeof(*d)))) { |
| |
264 gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() not enough memory\n"); |
| |
265 return NULL; |
| |
266 } |
| |
267 |
| |
268 d->check = GG_CHECK_WRITE; |
| |
269 d->state = GG_STATE_CONNECTING; |
| |
270 d->type = type; |
| |
271 d->timeout = GG_DEFAULT_TIMEOUT; |
| |
272 d->file_fd = -1; |
| |
273 d->active = 1; |
| |
274 d->fd = -1; |
| |
275 d->uin = my_uin; |
| |
276 d->peer_uin = peer_uin; |
| |
277 |
| |
278 if ((d->fd = gg_connect(&addr, port, 1)) == -1) { |
| |
279 gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() connection failed\n"); |
| |
280 free(d); |
| |
281 return NULL; |
| |
282 } |
| |
283 |
| |
284 return d; |
| |
285 } |
| |
286 |
| |
287 /* |
| |
288 * gg_dcc_get_file() |
| |
289 * |
| |
290 * inicjuje proces odbierania pliku od danego klienta, gdy ten wysłał do |
| |
291 * nas żądanie połączenia. |
| |
292 * |
| |
293 * - ip - adres ip odbiorcy |
| |
294 * - port - port odbiorcy |
| |
295 * - my_uin - własny numer |
| |
296 * - peer_uin - numer obiorcy |
| |
297 * |
| |
298 * zaalokowana struct gg_dcc lub NULL jeśli wystąpił błąd. |
| |
299 */ |
| |
300 struct gg_dcc *gg_dcc_get_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) |
| |
301 { |
| |
302 gg_debug(GG_DEBUG_MISC, "// gg_dcc_get_file() handing over to gg_dcc_transfer()\n"); |
| |
303 |
| |
304 return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_GET); |
| |
305 } |
| |
306 |
| |
307 /* |
| |
308 * gg_dcc_send_file() |
| |
309 * |
| |
310 * inicjuje proces wysyłania pliku do danego klienta. |
| |
311 * |
| |
312 * - ip - adres ip odbiorcy |
| |
313 * - port - port odbiorcy |
| |
314 * - my_uin - własny numer |
| |
315 * - peer_uin - numer obiorcy |
| |
316 * |
| |
317 * zaalokowana struct gg_dcc lub NULL jeśli wystąpił błąd. |
| |
318 */ |
| |
319 struct gg_dcc *gg_dcc_send_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) |
| |
320 { |
| |
321 gg_debug(GG_DEBUG_MISC, "// gg_dcc_send_file() handing over to gg_dcc_transfer()\n"); |
| |
322 |
| |
323 return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_SEND); |
| |
324 } |
| |
325 |
| |
326 /* |
| |
327 * gg_dcc_voice_chat() |
| |
328 * |
| |
329 * próbuje nawiązać połączenie głosowe. |
| |
330 * |
| |
331 * - ip - adres ip odbiorcy |
| |
332 * - port - port odbiorcy |
| |
333 * - my_uin - własny numer |
| |
334 * - peer_uin - numer obiorcy |
| |
335 * |
| |
336 * zaalokowana struct gg_dcc lub NULL jeśli wystąpił błąd. |
| |
337 */ |
| |
338 struct gg_dcc *gg_dcc_voice_chat(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) |
| |
339 { |
| |
340 gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_chat() handing over to gg_dcc_transfer()\n"); |
| |
341 |
| |
342 return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_VOICE); |
| |
343 } |
| |
344 |
| |
345 /* |
| |
346 * gg_dcc_set_type() |
| |
347 * |
| |
348 * po zdarzeniu GG_EVENT_DCC_CALLBACK należy ustawić typ połączenia za |
| |
349 * pomocą tej funkcji. |
| |
350 * |
| |
351 * - d - struktura opisująca połączenie |
| |
352 * - type - typ połączenia (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_VOICE) |
| |
353 */ |
| |
354 void gg_dcc_set_type(struct gg_dcc *d, int type) |
| |
355 { |
| |
356 d->type = type; |
| |
357 d->state = (type == GG_SESSION_DCC_SEND) ? GG_STATE_SENDING_FILE_INFO : GG_STATE_SENDING_VOICE_REQUEST; |
| |
358 } |
| |
359 |
| |
360 /* |
| |
361 * gg_dcc_callback() // funkcja wewnętrzna |
| |
362 * |
| |
363 * wywoływana z struct gg_dcc->callback, odpala gg_dcc_watch_fd i umieszcza |
| |
364 * rezultat w struct gg_dcc->event. |
| |
365 * |
| |
366 * - d - structura opisująca połączenie |
| |
367 * |
| |
368 * 0, -1. |
| |
369 */ |
| |
370 static int gg_dcc_callback(struct gg_dcc *d) |
| |
371 { |
| |
372 struct gg_event *e = gg_dcc_watch_fd(d); |
| |
373 |
| |
374 d->event = e; |
| |
375 |
| |
376 return (e != NULL) ? 0 : -1; |
| |
377 } |
| |
378 |
| |
379 /* |
| |
380 * gg_dcc_socket_create() |
| |
381 * |
| |
382 * tworzy gniazdo dla bezpośredniej komunikacji między klientami. |
| |
383 * |
| |
384 * - uin - własny numer |
| |
385 * - port - preferowany port, jeśli równy 0 lub -1, próbuje domyślnego |
| |
386 * |
| |
387 * zaalokowana struct gg_dcc, którą poźniej należy zwolnić funkcją |
| |
388 * gg_dcc_free(), albo NULL jeśli wystąpił błąd. |
| |
389 */ |
| |
390 struct gg_dcc *gg_dcc_socket_create(uin_t uin, uint16_t port) |
| |
391 { |
| |
392 struct gg_dcc *c; |
| |
393 struct sockaddr_in sin; |
| |
394 int sock, bound = 0, errno2; |
| |
395 |
| |
396 gg_debug(GG_DEBUG_FUNCTION, "** gg_create_dcc_socket(%d, %d);\n", uin, port); |
| |
397 |
| |
398 if (!uin) { |
| |
399 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() invalid arguments\n"); |
| |
400 errno = EINVAL; |
| |
401 return NULL; |
| |
402 } |
| |
403 |
| |
404 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { |
| |
405 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() can't create socket (%s)\n", strerror(errno)); |
| |
406 return NULL; |
| |
407 } |
| |
408 |
| |
409 if (!port) |
| |
410 port = GG_DEFAULT_DCC_PORT; |
| |
411 |
| |
412 while (!bound) { |
| |
413 sin.sin_family = AF_INET; |
| |
414 sin.sin_addr.s_addr = INADDR_ANY; |
| |
415 sin.sin_port = htons(port); |
| |
416 |
| |
417 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() trying port %d\n", port); |
| |
418 if (!bind(sock, (struct sockaddr*) &sin, sizeof(sin))) |
| |
419 bound = 1; |
| |
420 else { |
| |
421 if (++port == 65535) { |
| |
422 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() no free port found\n"); |
| |
423 close(sock); |
| |
424 return NULL; |
| |
425 } |
| |
426 } |
| |
427 } |
| |
428 |
| |
429 if (listen(sock, 10)) { |
| |
430 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() unable to listen (%s)\n", strerror(errno)); |
| |
431 errno2 = errno; |
| |
432 close(sock); |
| |
433 errno = errno2; |
| |
434 return NULL; |
| |
435 } |
| |
436 |
| |
437 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() bound to port %d\n", port); |
| |
438 |
| |
439 if (!(c = malloc(sizeof(*c)))) { |
| |
440 gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() not enough memory for struct\n"); |
| |
441 close(sock); |
| |
442 return NULL; |
| |
443 } |
| |
444 memset(c, 0, sizeof(*c)); |
| |
445 |
| |
446 c->port = c->id = port; |
| |
447 c->fd = sock; |
| |
448 c->type = GG_SESSION_DCC_SOCKET; |
| |
449 c->uin = uin; |
| |
450 c->timeout = -1; |
| |
451 c->state = GG_STATE_LISTENING; |
| |
452 c->check = GG_CHECK_READ; |
| |
453 c->callback = gg_dcc_callback; |
| |
454 c->destroy = gg_dcc_free; |
| |
455 |
| |
456 return c; |
| |
457 } |
| |
458 |
| |
459 /* |
| |
460 * gg_dcc_voice_send() |
| |
461 * |
| |
462 * wysyła ramkę danych dla rozmowy głosowej. |
| |
463 * |
| |
464 * - d - struktura opisująca połączenie dcc |
| |
465 * - buf - bufor z danymi |
| |
466 * - length - rozmiar ramki |
| |
467 * |
| |
468 * 0, -1. |
| |
469 */ |
| |
470 int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length) |
| |
471 { |
| |
472 struct packet_s { |
| |
473 uint8_t type; |
| |
474 uint32_t length; |
| |
475 } GG_PACKED; |
| |
476 struct packet_s packet; |
| |
477 |
| |
478 gg_debug(GG_DEBUG_FUNCTION, "++ gg_dcc_voice_send(%p, %p, %d);\n", d, buf, length); |
| |
479 if (!d || !buf || length < 0 || d->type != GG_SESSION_DCC_VOICE) { |
| |
480 gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() invalid argument\n"); |
| |
481 errno = EINVAL; |
| |
482 return -1; |
| |
483 } |
| |
484 |
| |
485 packet.type = 0x03; /* XXX */ |
| |
486 packet.length = gg_fix32(length); |
| |
487 |
| |
488 if (write(d->fd, &packet, sizeof(packet)) < (signed)sizeof(packet)) { |
| |
489 gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() write() failed\n"); |
| |
490 return -1; |
| |
491 } |
| |
492 gg_dcc_debug_data("write", d->fd, &packet, sizeof(packet)); |
| |
493 |
| |
494 if (write(d->fd, buf, length) < length) { |
| |
495 gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() write() failed\n"); |
| |
496 return -1; |
| |
497 } |
| |
498 gg_dcc_debug_data("write", d->fd, buf, length); |
| |
499 |
| |
500 return 0; |
| |
501 } |
| |
502 |
| |
503 #define gg_read(fd, buf, size) \ |
| |
504 { \ |
| |
505 int tmp = read(fd, buf, size); \ |
| |
506 \ |
| |
507 if (tmp < (int) size) { \ |
| |
508 if (tmp == -1) { \ |
| |
509 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); \ |
| |
510 } else if (tmp == 0) { \ |
| |
511 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed, connection broken\n"); \ |
| |
512 } else { \ |
| |
513 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (%d bytes, %d needed)\n", tmp, size); \ |
| |
514 } \ |
| |
515 e->type = GG_EVENT_DCC_ERROR; \ |
| |
516 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \ |
| |
517 return e; \ |
| |
518 } \ |
| |
519 gg_dcc_debug_data("read", fd, buf, size); \ |
| |
520 } |
| |
521 |
| |
522 #define gg_write(fd, buf, size) \ |
| |
523 { \ |
| |
524 int tmp; \ |
| |
525 gg_dcc_debug_data("write", fd, buf, size); \ |
| |
526 tmp = write(fd, buf, size); \ |
| |
527 if (tmp < (int) size) { \ |
| |
528 if (tmp == -1) { \ |
| |
529 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno)); \ |
| |
530 } else { \ |
| |
531 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%d needed, %d done)\n", size, tmp); \ |
| |
532 } \ |
| |
533 e->type = GG_EVENT_DCC_ERROR; \ |
| |
534 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; \ |
| |
535 return e; \ |
| |
536 } \ |
| |
537 } |
| |
538 |
| |
539 /* |
| |
540 * gg_dcc_watch_fd() |
| |
541 * |
| |
542 * funkcja, którą należy wywołać, gdy coś się zmieni na gg_dcc->fd. |
| |
543 * |
| |
544 * - h - struktura zwrócona przez gg_create_dcc_socket() |
| |
545 * |
| |
546 * zaalokowana struct gg_event lub NULL, jeśli zabrakło pamięci na nią. |
| |
547 */ |
| |
548 struct gg_event *gg_dcc_watch_fd(struct gg_dcc *h) |
| |
549 { |
| |
550 struct gg_event *e; |
| |
551 int foo; |
| |
552 |
| |
553 gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_watch_fd(%p);\n", h); |
| |
554 |
| |
555 if (!h || (h->type != GG_SESSION_DCC && h->type != GG_SESSION_DCC_SOCKET && h->type != GG_SESSION_DCC_SEND && h->type != GG_SESSION_DCC_GET && h->type != GG_SESSION_DCC_VOICE)) { |
| |
556 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid argument\n"); |
| |
557 errno = EINVAL; |
| |
558 return NULL; |
| |
559 } |
| |
560 |
| |
561 if (!(e = (void*) calloc(1, sizeof(*e)))) { |
| |
562 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() not enough memory\n"); |
| |
563 return NULL; |
| |
564 } |
| |
565 |
| |
566 e->type = GG_EVENT_NONE; |
| |
567 |
| |
568 if (h->type == GG_SESSION_DCC_SOCKET) { |
| |
569 struct sockaddr_in sin; |
| |
570 struct gg_dcc *c; |
| |
571 int fd; |
| |
572 socklen_t sin_len = sizeof(sin); |
| |
573 int one = 1; |
| |
574 |
| |
575 if ((fd = accept(h->fd, (struct sockaddr*) &sin, &sin_len)) == -1) { |
| |
576 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't accept() new connection (errno=%d, %s)\n", errno, strerror(errno)); |
| |
577 return e; |
| |
578 } |
| |
579 |
| |
580 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() new direct connection from %s:%d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); |
| |
581 |
| |
582 #ifdef FIONBIO |
| |
583 if (ioctl(fd, FIONBIO, &one) == -1) { |
| |
584 #else |
| |
585 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { |
| |
586 #endif |
| |
587 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't set nonblocking (errno=%d, %s)\n", errno, strerror(errno)); |
| |
588 close(fd); |
| |
589 e->type = GG_EVENT_DCC_ERROR; |
| |
590 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; |
| |
591 return e; |
| |
592 } |
| |
593 |
| |
594 if (!(c = (void*) calloc(1, sizeof(*c)))) { |
| |
595 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() not enough memory for client data\n"); |
| |
596 |
| |
597 free(e); |
| |
598 close(fd); |
| |
599 return NULL; |
| |
600 } |
| |
601 |
| |
602 c->fd = fd; |
| |
603 c->check = GG_CHECK_READ; |
| |
604 c->state = GG_STATE_READING_UIN_1; |
| |
605 c->type = GG_SESSION_DCC; |
| |
606 c->timeout = GG_DEFAULT_TIMEOUT; |
| |
607 c->file_fd = -1; |
| |
608 c->remote_addr = sin.sin_addr.s_addr; |
| |
609 c->remote_port = ntohs(sin.sin_port); |
| |
610 |
| |
611 e->type = GG_EVENT_DCC_NEW; |
| |
612 e->event.dcc_new = c; |
| |
613 |
| |
614 return e; |
| |
615 } else { |
| |
616 struct gg_dcc_tiny_packet tiny; |
| |
617 struct gg_dcc_small_packet small; |
| |
618 struct gg_dcc_big_packet big; |
| |
619 int size, tmp, res; |
| |
620 socklen_t res_size = sizeof(res); |
| |
621 unsigned int utmp; |
| |
622 char buf[1024], ack[] = "UDAG"; |
| |
623 |
| |
624 struct gg_dcc_file_info_packet { |
| |
625 struct gg_dcc_big_packet big; |
| |
626 struct gg_file_info file_info; |
| |
627 } GG_PACKED; |
| |
628 struct gg_dcc_file_info_packet file_info_packet; |
| |
629 |
| |
630 switch (h->state) { |
| |
631 case GG_STATE_READING_UIN_1: |
| |
632 case GG_STATE_READING_UIN_2: |
| |
633 { |
| |
634 uin_t uin; |
| |
635 |
| |
636 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_READING_UIN_%d\n", (h->state == GG_STATE_READING_UIN_1) ? 1 : 2); |
| |
637 |
| |
638 gg_read(h->fd, &uin, sizeof(uin)); |
| |
639 |
| |
640 if (h->state == GG_STATE_READING_UIN_1) { |
| |
641 h->state = GG_STATE_READING_UIN_2; |
| |
642 h->check = GG_CHECK_READ; |
| |
643 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
644 h->peer_uin = gg_fix32(uin); |
| |
645 } else { |
| |
646 h->state = GG_STATE_SENDING_ACK; |
| |
647 h->check = GG_CHECK_WRITE; |
| |
648 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
649 h->uin = gg_fix32(uin); |
| |
650 e->type = GG_EVENT_DCC_CLIENT_ACCEPT; |
| |
651 } |
| |
652 |
| |
653 return e; |
| |
654 } |
| |
655 |
| |
656 case GG_STATE_SENDING_ACK: |
| |
657 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_SENDING_ACK\n"); |
| |
658 |
| |
659 gg_write(h->fd, ack, 4); |
| |
660 |
| |
661 h->state = GG_STATE_READING_TYPE; |
| |
662 h->check = GG_CHECK_READ; |
| |
663 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
664 |
| |
665 return e; |
| |
666 |
| |
667 case GG_STATE_READING_TYPE: |
| |
668 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_TYPE\n"); |
| |
669 |
| |
670 gg_read(h->fd, &small, sizeof(small)); |
| |
671 |
| |
672 small.type = gg_fix32(small.type); |
| |
673 |
| |
674 switch (small.type) { |
| |
675 case 0x0003: /* XXX */ |
| |
676 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() callback\n"); |
| |
677 h->type = GG_SESSION_DCC_SEND; |
| |
678 h->state = GG_STATE_SENDING_FILE_INFO; |
| |
679 h->check = GG_CHECK_WRITE; |
| |
680 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
681 |
| |
682 e->type = GG_EVENT_DCC_CALLBACK; |
| |
683 |
| |
684 break; |
| |
685 |
| |
686 case 0x0002: /* XXX */ |
| |
687 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() dialin\n"); |
| |
688 h->type = GG_SESSION_DCC_GET; |
| |
689 h->state = GG_STATE_READING_REQUEST; |
| |
690 h->check = GG_CHECK_READ; |
| |
691 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
692 h->incoming = 1; |
| |
693 |
| |
694 break; |
| |
695 |
| |
696 default: |
| |
697 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown dcc type (%.4x) from %ld\n", small.type, h->peer_uin); |
| |
698 e->type = GG_EVENT_DCC_ERROR; |
| |
699 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; |
| |
700 } |
| |
701 |
| |
702 return e; |
| |
703 |
| |
704 case GG_STATE_READING_REQUEST: |
| |
705 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_REQUEST\n"); |
| |
706 |
| |
707 gg_read(h->fd, &small, sizeof(small)); |
| |
708 |
| |
709 small.type = gg_fix32(small.type); |
| |
710 |
| |
711 switch (small.type) { |
| |
712 case 0x0001: /* XXX */ |
| |
713 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() file transfer request\n"); |
| |
714 h->state = GG_STATE_READING_FILE_INFO; |
| |
715 h->check = GG_CHECK_READ; |
| |
716 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
717 break; |
| |
718 |
| |
719 case 0x0003: /* XXX */ |
| |
720 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() voice chat request\n"); |
| |
721 h->state = GG_STATE_SENDING_VOICE_ACK; |
| |
722 h->check = GG_CHECK_WRITE; |
| |
723 h->timeout = GG_DCC_TIMEOUT_VOICE_ACK; |
| |
724 h->type = GG_SESSION_DCC_VOICE; |
| |
725 e->type = GG_EVENT_DCC_NEED_VOICE_ACK; |
| |
726 |
| |
727 break; |
| |
728 |
| |
729 default: |
| |
730 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown dcc request (%.4x) from %ld\n", small.type, h->peer_uin); |
| |
731 e->type = GG_EVENT_DCC_ERROR; |
| |
732 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; |
| |
733 } |
| |
734 |
| |
735 return e; |
| |
736 |
| |
737 case GG_STATE_READING_FILE_INFO: |
| |
738 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_INFO\n"); |
| |
739 |
| |
740 gg_read(h->fd, &file_info_packet, sizeof(file_info_packet)); |
| |
741 |
| |
742 memcpy(&h->file_info, &file_info_packet.file_info, sizeof(h->file_info)); |
| |
743 |
| |
744 h->file_info.mode = gg_fix32(h->file_info.mode); |
| |
745 h->file_info.size = gg_fix32(h->file_info.size); |
| |
746 |
| |
747 h->state = GG_STATE_SENDING_FILE_ACK; |
| |
748 h->check = GG_CHECK_WRITE; |
| |
749 h->timeout = GG_DCC_TIMEOUT_FILE_ACK; |
| |
750 |
| |
751 e->type = GG_EVENT_DCC_NEED_FILE_ACK; |
| |
752 |
| |
753 return e; |
| |
754 |
| |
755 case GG_STATE_SENDING_FILE_ACK: |
| |
756 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_ACK\n"); |
| |
757 |
| |
758 big.type = gg_fix32(0x0006); /* XXX */ |
| |
759 big.dunno1 = gg_fix32(h->offset); |
| |
760 big.dunno2 = 0; |
| |
761 |
| |
762 gg_write(h->fd, &big, sizeof(big)); |
| |
763 |
| |
764 h->state = GG_STATE_READING_FILE_HEADER; |
| |
765 h->chunk_size = sizeof(big); |
| |
766 h->chunk_offset = 0; |
| |
767 if (!(h->chunk_buf = malloc(sizeof(big)))) { |
| |
768 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n"); |
| |
769 free(e); |
| |
770 return NULL; |
| |
771 } |
| |
772 h->check = GG_CHECK_READ; |
| |
773 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
774 |
| |
775 return e; |
| |
776 |
| |
777 case GG_STATE_SENDING_VOICE_ACK: |
| |
778 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_ACK\n"); |
| |
779 |
| |
780 tiny.type = 0x01; /* XXX */ |
| |
781 |
| |
782 gg_write(h->fd, &tiny, sizeof(tiny)); |
| |
783 |
| |
784 h->state = GG_STATE_READING_VOICE_HEADER; |
| |
785 h->check = GG_CHECK_READ; |
| |
786 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
787 |
| |
788 h->offset = 0; |
| |
789 |
| |
790 return e; |
| |
791 |
| |
792 case GG_STATE_READING_FILE_HEADER: |
| |
793 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_HEADER\n"); |
| |
794 |
| |
795 tmp = read(h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); |
| |
796 |
| |
797 if (tmp == -1) { |
| |
798 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); |
| |
799 e->type = GG_EVENT_DCC_ERROR; |
| |
800 e->event.dcc_error = GG_ERROR_DCC_NET; |
| |
801 return e; |
| |
802 } |
| |
803 |
| |
804 gg_dcc_debug_data("read", h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); |
| |
805 |
| |
806 h->chunk_offset += tmp; |
| |
807 |
| |
808 if (h->chunk_offset < h->chunk_size) |
| |
809 return e; |
| |
810 |
| |
811 memcpy(&big, h->chunk_buf, sizeof(big)); |
| |
812 free(h->chunk_buf); |
| |
813 h->chunk_buf = NULL; |
| |
814 |
| |
815 big.type = gg_fix32(big.type); |
| |
816 h->chunk_size = gg_fix32(big.dunno1); |
| |
817 h->chunk_offset = 0; |
| |
818 |
| |
819 if (big.type == 0x0005) { /* XXX */ |
| |
820 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() transfer refused\n"); |
| |
821 e->type = GG_EVENT_DCC_ERROR; |
| |
822 e->event.dcc_error = GG_ERROR_DCC_REFUSED; |
| |
823 return e; |
| |
824 } |
| |
825 |
| |
826 if (h->chunk_size == 0) { |
| |
827 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() empty chunk, EOF\n"); |
| |
828 e->type = GG_EVENT_DCC_DONE; |
| |
829 return e; |
| |
830 } |
| |
831 |
| |
832 h->state = GG_STATE_GETTING_FILE; |
| |
833 h->check = GG_CHECK_READ; |
| |
834 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
835 h->established = 1; |
| |
836 |
| |
837 return e; |
| |
838 |
| |
839 case GG_STATE_READING_VOICE_HEADER: |
| |
840 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_HEADER\n"); |
| |
841 |
| |
842 gg_read(h->fd, &tiny, sizeof(tiny)); |
| |
843 |
| |
844 switch (tiny.type) { |
| |
845 case 0x03: /* XXX */ |
| |
846 h->state = GG_STATE_READING_VOICE_SIZE; |
| |
847 h->check = GG_CHECK_READ; |
| |
848 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
849 h->established = 1; |
| |
850 break; |
| |
851 case 0x04: /* XXX */ |
| |
852 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() peer breaking connection\n"); |
| |
853 /* XXX zwracać odpowiedni event */ |
| |
854 default: |
| |
855 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown request (%.2x)\n", tiny.type); |
| |
856 e->type = GG_EVENT_DCC_ERROR; |
| |
857 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; |
| |
858 } |
| |
859 |
| |
860 return e; |
| |
861 |
| |
862 case GG_STATE_READING_VOICE_SIZE: |
| |
863 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_SIZE\n"); |
| |
864 |
| |
865 gg_read(h->fd, &small, sizeof(small)); |
| |
866 |
| |
867 small.type = gg_fix32(small.type); |
| |
868 |
| |
869 if (small.type < 16 || small.type > sizeof(buf)) { |
| |
870 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid voice frame size (%d)\n", small.type); |
| |
871 e->type = GG_EVENT_DCC_ERROR; |
| |
872 e->event.dcc_error = GG_ERROR_DCC_NET; |
| |
873 |
| |
874 return e; |
| |
875 } |
| |
876 |
| |
877 h->chunk_size = small.type; |
| |
878 h->chunk_offset = 0; |
| |
879 |
| |
880 if (!(h->voice_buf = malloc(h->chunk_size))) { |
| |
881 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory for voice frame\n"); |
| |
882 return NULL; |
| |
883 } |
| |
884 |
| |
885 h->state = GG_STATE_READING_VOICE_DATA; |
| |
886 h->check = GG_CHECK_READ; |
| |
887 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
888 |
| |
889 return e; |
| |
890 |
| |
891 case GG_STATE_READING_VOICE_DATA: |
| |
892 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_DATA\n"); |
| |
893 |
| |
894 tmp = read(h->fd, h->voice_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); |
| |
895 if (tmp < 1) { |
| |
896 if (tmp == -1) { |
| |
897 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); |
| |
898 } else { |
| |
899 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed, connection broken\n"); |
| |
900 } |
| |
901 e->type = GG_EVENT_DCC_ERROR; |
| |
902 e->event.dcc_error = GG_ERROR_DCC_NET; |
| |
903 return e; |
| |
904 } |
| |
905 |
| |
906 gg_dcc_debug_data("read", h->fd, h->voice_buf + h->chunk_offset, tmp); |
| |
907 |
| |
908 h->chunk_offset += tmp; |
| |
909 |
| |
910 if (h->chunk_offset >= h->chunk_size) { |
| |
911 e->type = GG_EVENT_DCC_VOICE_DATA; |
| |
912 e->event.dcc_voice_data.data = h->voice_buf; |
| |
913 e->event.dcc_voice_data.length = h->chunk_size; |
| |
914 h->state = GG_STATE_READING_VOICE_HEADER; |
| |
915 h->voice_buf = NULL; |
| |
916 } |
| |
917 |
| |
918 h->check = GG_CHECK_READ; |
| |
919 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
920 |
| |
921 return e; |
| |
922 |
| |
923 case GG_STATE_CONNECTING: |
| |
924 { |
| |
925 uin_t uins[2]; |
| |
926 |
| |
927 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_CONNECTING\n"); |
| |
928 |
| |
929 res = 0; |
| |
930 if ((foo = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size)) || res) { |
| |
931 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() connection failed (fd=%d,errno=%d(%s),foo=%d,res=%d(%s))\n", h->fd, errno, strerror(errno), foo, res, strerror(res)); |
| |
932 e->type = GG_EVENT_DCC_ERROR; |
| |
933 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; |
| |
934 return e; |
| |
935 } |
| |
936 |
| |
937 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() connected, sending uins\n"); |
| |
938 |
| |
939 uins[0] = gg_fix32(h->uin); |
| |
940 uins[1] = gg_fix32(h->peer_uin); |
| |
941 |
| |
942 gg_write(h->fd, uins, sizeof(uins)); |
| |
943 |
| |
944 h->state = GG_STATE_READING_ACK; |
| |
945 h->check = GG_CHECK_READ; |
| |
946 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
947 |
| |
948 return e; |
| |
949 } |
| |
950 |
| |
951 case GG_STATE_READING_ACK: |
| |
952 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_ACK\n"); |
| |
953 |
| |
954 gg_read(h->fd, buf, 4); |
| |
955 |
| |
956 if (strncmp(buf, ack, 4)) { |
| |
957 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() did't get ack\n"); |
| |
958 |
| |
959 e->type = GG_EVENT_DCC_ERROR; |
| |
960 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; |
| |
961 return e; |
| |
962 } |
| |
963 |
| |
964 h->check = GG_CHECK_WRITE; |
| |
965 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
966 h->state = GG_STATE_SENDING_REQUEST; |
| |
967 |
| |
968 return e; |
| |
969 |
| |
970 case GG_STATE_SENDING_VOICE_REQUEST: |
| |
971 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_REQUEST\n"); |
| |
972 |
| |
973 small.type = gg_fix32(0x0003); |
| |
974 |
| |
975 gg_write(h->fd, &small, sizeof(small)); |
| |
976 |
| |
977 h->state = GG_STATE_READING_VOICE_ACK; |
| |
978 h->check = GG_CHECK_READ; |
| |
979 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
980 |
| |
981 return e; |
| |
982 |
| |
983 case GG_STATE_SENDING_REQUEST: |
| |
984 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_REQUEST\n"); |
| |
985 |
| |
986 small.type = (h->type == GG_SESSION_DCC_GET) ? gg_fix32(0x0003) : gg_fix32(0x0002); /* XXX */ |
| |
987 |
| |
988 gg_write(h->fd, &small, sizeof(small)); |
| |
989 |
| |
990 switch (h->type) { |
| |
991 case GG_SESSION_DCC_GET: |
| |
992 h->state = GG_STATE_READING_REQUEST; |
| |
993 h->check = GG_CHECK_READ; |
| |
994 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
995 break; |
| |
996 |
| |
997 case GG_SESSION_DCC_SEND: |
| |
998 h->state = GG_STATE_SENDING_FILE_INFO; |
| |
999 h->check = GG_CHECK_WRITE; |
| |
1000 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
1001 |
| |
1002 if (h->file_fd == -1) |
| |
1003 e->type = GG_EVENT_DCC_NEED_FILE_INFO; |
| |
1004 break; |
| |
1005 |
| |
1006 case GG_SESSION_DCC_VOICE: |
| |
1007 h->state = GG_STATE_SENDING_VOICE_REQUEST; |
| |
1008 h->check = GG_CHECK_WRITE; |
| |
1009 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
1010 break; |
| |
1011 } |
| |
1012 |
| |
1013 return e; |
| |
1014 |
| |
1015 case GG_STATE_SENDING_FILE_INFO: |
| |
1016 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_INFO\n"); |
| |
1017 |
| |
1018 if (h->file_fd == -1) { |
| |
1019 e->type = GG_EVENT_DCC_NEED_FILE_INFO; |
| |
1020 return e; |
| |
1021 } |
| |
1022 |
| |
1023 small.type = gg_fix32(0x0001); /* XXX */ |
| |
1024 |
| |
1025 gg_write(h->fd, &small, sizeof(small)); |
| |
1026 |
| |
1027 file_info_packet.big.type = gg_fix32(0x0003); /* XXX */ |
| |
1028 file_info_packet.big.dunno1 = 0; |
| |
1029 file_info_packet.big.dunno2 = 0; |
| |
1030 |
| |
1031 memcpy(&file_info_packet.file_info, &h->file_info, sizeof(h->file_info)); |
| |
1032 |
| |
1033 /* zostają teraz u nas, więc odwracamy z powrotem */ |
| |
1034 h->file_info.size = gg_fix32(h->file_info.size); |
| |
1035 h->file_info.mode = gg_fix32(h->file_info.mode); |
| |
1036 |
| |
1037 gg_write(h->fd, &file_info_packet, sizeof(file_info_packet)); |
| |
1038 |
| |
1039 h->state = GG_STATE_READING_FILE_ACK; |
| |
1040 h->check = GG_CHECK_READ; |
| |
1041 h->timeout = GG_DCC_TIMEOUT_FILE_ACK; |
| |
1042 |
| |
1043 return e; |
| |
1044 |
| |
1045 case GG_STATE_READING_FILE_ACK: |
| |
1046 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_ACK\n"); |
| |
1047 |
| |
1048 gg_read(h->fd, &big, sizeof(big)); |
| |
1049 |
| |
1050 /* XXX sprawdzać wynik */ |
| |
1051 h->offset = gg_fix32(big.dunno1); |
| |
1052 |
| |
1053 h->state = GG_STATE_SENDING_FILE_HEADER; |
| |
1054 h->check = GG_CHECK_WRITE; |
| |
1055 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
1056 |
| |
1057 e->type = GG_EVENT_DCC_ACK; |
| |
1058 |
| |
1059 return e; |
| |
1060 |
| |
1061 case GG_STATE_READING_VOICE_ACK: |
| |
1062 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_ACK\n"); |
| |
1063 |
| |
1064 gg_read(h->fd, &tiny, sizeof(tiny)); |
| |
1065 |
| |
1066 if (tiny.type != 0x01) { |
| |
1067 gg_debug(GG_DEBUG_MISC, "// invalid reply (%.2x), connection refused\n", tiny.type); |
| |
1068 e->type = GG_EVENT_DCC_ERROR; |
| |
1069 e->event.dcc_error = GG_ERROR_DCC_REFUSED; |
| |
1070 return e; |
| |
1071 } |
| |
1072 |
| |
1073 h->state = GG_STATE_READING_VOICE_HEADER; |
| |
1074 h->check = GG_CHECK_READ; |
| |
1075 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
1076 |
| |
1077 e->type = GG_EVENT_DCC_ACK; |
| |
1078 |
| |
1079 return e; |
| |
1080 |
| |
1081 case GG_STATE_SENDING_FILE_HEADER: |
| |
1082 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_HEADER\n"); |
| |
1083 |
| |
1084 h->chunk_offset = 0; |
| |
1085 |
| |
1086 if ((h->chunk_size = h->file_info.size - h->offset) > 4096) { |
| |
1087 h->chunk_size = 4096; |
| |
1088 big.type = gg_fix32(0x0003); /* XXX */ |
| |
1089 } else |
| |
1090 big.type = gg_fix32(0x0002); /* XXX */ |
| |
1091 |
| |
1092 big.dunno1 = gg_fix32(h->chunk_size); |
| |
1093 big.dunno2 = 0; |
| |
1094 |
| |
1095 gg_write(h->fd, &big, sizeof(big)); |
| |
1096 |
| |
1097 h->state = GG_STATE_SENDING_FILE; |
| |
1098 h->check = GG_CHECK_WRITE; |
| |
1099 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
1100 h->established = 1; |
| |
1101 |
| |
1102 return e; |
| |
1103 |
| |
1104 case GG_STATE_SENDING_FILE: |
| |
1105 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE\n"); |
| |
1106 |
| |
1107 if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf)) |
| |
1108 utmp = sizeof(buf); |
| |
1109 |
| |
1110 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset=%d, size=%d\n", h->offset, h->file_info.size); |
| |
1111 |
| |
1112 /* koniec pliku? */ |
| |
1113 if (h->file_info.size == 0) { |
| |
1114 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof on empty file\n"); |
| |
1115 e->type = GG_EVENT_DCC_DONE; |
| |
1116 |
| |
1117 return e; |
| |
1118 } |
| |
1119 |
| |
1120 lseek(h->file_fd, h->offset, SEEK_SET); |
| |
1121 |
| |
1122 size = read(h->file_fd, buf, utmp); |
| |
1123 |
| |
1124 /* błąd */ |
| |
1125 if (size == -1) { |
| |
1126 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno, strerror(errno)); |
| |
1127 |
| |
1128 e->type = GG_EVENT_DCC_ERROR; |
| |
1129 e->event.dcc_error = GG_ERROR_DCC_FILE; |
| |
1130 |
| |
1131 return e; |
| |
1132 } |
| |
1133 |
| |
1134 /* koniec pliku? */ |
| |
1135 if (size == 0) { |
| |
1136 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof\n"); |
| |
1137 e->type = GG_EVENT_DCC_ERROR; |
| |
1138 e->event.dcc_error = GG_ERROR_DCC_EOF; |
| |
1139 |
| |
1140 return e; |
| |
1141 } |
| |
1142 |
| |
1143 /* jeśli wczytaliśmy więcej, utnijmy. */ |
| |
1144 if (h->offset + size > h->file_info.size) { |
| |
1145 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() too much (read=%d, ofs=%d, size=%d)\n", size, h->offset, h->file_info.size); |
| |
1146 size = h->file_info.size - h->offset; |
| |
1147 |
| |
1148 if (size < 1) { |
| |
1149 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() reached EOF after cutting\n"); |
| |
1150 e->type = GG_EVENT_DCC_DONE; |
| |
1151 return e; |
| |
1152 } |
| |
1153 } |
| |
1154 |
| |
1155 tmp = write(h->fd, buf, size); |
| |
1156 |
| |
1157 if (tmp == -1) { |
| |
1158 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%s)\n", strerror(errno)); |
| |
1159 e->type = GG_EVENT_DCC_ERROR; |
| |
1160 e->event.dcc_error = GG_ERROR_DCC_NET; |
| |
1161 return e; |
| |
1162 } |
| |
1163 |
| |
1164 h->offset += size; |
| |
1165 |
| |
1166 if (h->offset >= h->file_info.size) { |
| |
1167 e->type = GG_EVENT_DCC_DONE; |
| |
1168 return e; |
| |
1169 } |
| |
1170 |
| |
1171 h->chunk_offset += size; |
| |
1172 |
| |
1173 if (h->chunk_offset >= h->chunk_size) { |
| |
1174 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n"); |
| |
1175 h->state = GG_STATE_SENDING_FILE_HEADER; |
| |
1176 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
1177 } else { |
| |
1178 h->state = GG_STATE_SENDING_FILE; |
| |
1179 h->timeout = GG_DCC_TIMEOUT_SEND; |
| |
1180 } |
| |
1181 |
| |
1182 h->check = GG_CHECK_WRITE; |
| |
1183 |
| |
1184 return e; |
| |
1185 |
| |
1186 case GG_STATE_GETTING_FILE: |
| |
1187 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_GETTING_FILE\n"); |
| |
1188 |
| |
1189 if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf)) |
| |
1190 utmp = sizeof(buf); |
| |
1191 |
| |
1192 size = read(h->fd, buf, utmp); |
| |
1193 |
| |
1194 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() ofs=%d, size=%d, read()=%d\n", h->offset, h->file_info.size, size); |
| |
1195 |
| |
1196 /* błąd */ |
| |
1197 if (size == -1) { |
| |
1198 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno, strerror(errno)); |
| |
1199 |
| |
1200 e->type = GG_EVENT_DCC_ERROR; |
| |
1201 e->event.dcc_error = GG_ERROR_DCC_NET; |
| |
1202 |
| |
1203 return e; |
| |
1204 } |
| |
1205 |
| |
1206 /* koniec? */ |
| |
1207 if (size == 0) { |
| |
1208 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof\n"); |
| |
1209 e->type = GG_EVENT_DCC_ERROR; |
| |
1210 e->event.dcc_error = GG_ERROR_DCC_EOF; |
| |
1211 |
| |
1212 return e; |
| |
1213 } |
| |
1214 |
| |
1215 tmp = write(h->file_fd, buf, size); |
| |
1216 |
| |
1217 if (tmp == -1 || tmp < size) { |
| |
1218 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%d:fd=%d:res=%d:%s)\n", tmp, h->file_fd, size, strerror(errno)); |
| |
1219 e->type = GG_EVENT_DCC_ERROR; |
| |
1220 e->event.dcc_error = GG_ERROR_DCC_NET; |
| |
1221 return e; |
| |
1222 } |
| |
1223 |
| |
1224 h->offset += size; |
| |
1225 |
| |
1226 if (h->offset >= h->file_info.size) { |
| |
1227 e->type = GG_EVENT_DCC_DONE; |
| |
1228 return e; |
| |
1229 } |
| |
1230 |
| |
1231 h->chunk_offset += size; |
| |
1232 |
| |
1233 if (h->chunk_offset >= h->chunk_size) { |
| |
1234 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n"); |
| |
1235 h->state = GG_STATE_READING_FILE_HEADER; |
| |
1236 h->timeout = GG_DEFAULT_TIMEOUT; |
| |
1237 h->chunk_offset = 0; |
| |
1238 h->chunk_size = sizeof(big); |
| |
1239 if (!(h->chunk_buf = malloc(sizeof(big)))) { |
| |
1240 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n"); |
| |
1241 free(e); |
| |
1242 return NULL; |
| |
1243 } |
| |
1244 } else { |
| |
1245 h->state = GG_STATE_GETTING_FILE; |
| |
1246 h->timeout = GG_DCC_TIMEOUT_GET; |
| |
1247 } |
| |
1248 |
| |
1249 h->check = GG_CHECK_READ; |
| |
1250 |
| |
1251 return e; |
| |
1252 |
| |
1253 default: |
| |
1254 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_???\n"); |
| |
1255 e->type = GG_EVENT_DCC_ERROR; |
| |
1256 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; |
| |
1257 |
| |
1258 return e; |
| |
1259 } |
| |
1260 } |
| |
1261 |
| |
1262 return e; |
| |
1263 } |
| |
1264 |
| |
1265 #undef gg_read |
| |
1266 #undef gg_write |
| |
1267 |
| |
1268 /* |
| |
1269 * gg_dcc_free() |
| |
1270 * |
| |
1271 * zwalnia pamięć po strukturze połączenia dcc. |
| |
1272 * |
| |
1273 * - d - zwalniana struktura |
| |
1274 */ |
| |
1275 void gg_dcc_free(struct gg_dcc *d) |
| |
1276 { |
| |
1277 gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d); |
| |
1278 |
| |
1279 if (!d) |
| |
1280 return; |
| |
1281 |
| |
1282 if (d->fd != -1) |
| |
1283 close(d->fd); |
| |
1284 |
| |
1285 if (d->chunk_buf) { |
| |
1286 free(d->chunk_buf); |
| |
1287 d->chunk_buf = NULL; |
| |
1288 } |
| |
1289 |
| |
1290 free(d); |
| |
1291 } |
| |
1292 |
| |
1293 /* |
| |
1294 * Local variables: |
| |
1295 * c-indentation-style: k&r |
| |
1296 * c-basic-offset: 8 |
| |
1297 * indent-tabs-mode: notnil |
| |
1298 * End: |
| |
1299 * |
| |
1300 * vim: shiftwidth=8: |
| |
1301 */ |