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