Mercurial > pidgin
annotate src/protocols/gg/lib/dcc.c @ 11851:3bfb2cffcef2
[gaim-migrate @ 14142]
inspired by Richard Stellingwerff's patch 1339606, this workaround for
annoying visible borders on tab close buttons is no longer required with
at least gtk 2.6 (if someone can confirm if it was fixed in 2.4 we could
remove it there too)
committer: Tailor Script <tailor@pidgin.im>
| author | Stu Tomlinson <stu@nosnilmot.com> |
|---|---|
| date | Thu, 27 Oct 2005 15:15:52 +0000 |
| parents | 3c536224f0d0 |
| children | 9cbc5967fbfd |
| rev | line source |
|---|---|
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1 /* $Id: dcc.c 13801 2005-09-14 19:10:39Z datallah $ */ |
| 11360 | 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> | |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
24 #ifndef _WIN32 |
| 11360 | 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 | |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
32 #endif |
| 11360 | 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, "\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 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(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, sin_len = sizeof(sin), one = 1; | |
| 572 | |
| 573 if ((fd = accept(h->fd, (struct sockaddr*) &sin, &sin_len)) == -1) { | |
| 574 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't accept() new connection (errno=%d, %s)\n", errno, strerror(errno)); | |
| 575 return e; | |
| 576 } | |
| 577 | |
| 578 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)); | |
| 579 | |
| 580 #ifdef FIONBIO | |
| 581 if (ioctl(fd, FIONBIO, &one) == -1) { | |
| 582 #else | |
| 583 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { | |
| 584 #endif | |
| 585 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't set nonblocking (errno=%d, %s)\n", errno, strerror(errno)); | |
| 586 close(fd); | |
| 587 e->type = GG_EVENT_DCC_ERROR; | |
| 588 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; | |
| 589 return e; | |
| 590 } | |
| 591 | |
| 592 if (!(c = (void*) calloc(1, sizeof(*c)))) { | |
| 593 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() not enough memory for client data\n"); | |
| 594 | |
| 595 free(e); | |
| 596 close(fd); | |
| 597 return NULL; | |
| 598 } | |
| 599 | |
| 600 c->fd = fd; | |
| 601 c->check = GG_CHECK_READ; | |
| 602 c->state = GG_STATE_READING_UIN_1; | |
| 603 c->type = GG_SESSION_DCC; | |
| 604 c->timeout = GG_DEFAULT_TIMEOUT; | |
| 605 c->file_fd = -1; | |
| 606 c->remote_addr = sin.sin_addr.s_addr; | |
| 607 c->remote_port = ntohs(sin.sin_port); | |
| 608 | |
| 609 e->type = GG_EVENT_DCC_NEW; | |
| 610 e->event.dcc_new = c; | |
| 611 | |
| 612 return e; | |
| 613 } else { | |
| 614 struct gg_dcc_tiny_packet tiny; | |
| 615 struct gg_dcc_small_packet small; | |
| 616 struct gg_dcc_big_packet big; | |
| 617 int size, tmp, res, res_size = sizeof(res); | |
| 618 unsigned int utmp; | |
| 619 char buf[1024], ack[] = "UDAG"; | |
| 620 | |
| 621 struct gg_dcc_file_info_packet { | |
| 622 struct gg_dcc_big_packet big; | |
| 623 struct gg_file_info file_info; | |
| 624 } GG_PACKED; | |
| 625 struct gg_dcc_file_info_packet file_info_packet; | |
| 626 | |
| 627 switch (h->state) { | |
| 628 case GG_STATE_READING_UIN_1: | |
| 629 case GG_STATE_READING_UIN_2: | |
| 630 { | |
| 631 uin_t uin; | |
| 632 | |
| 633 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_READING_UIN_%d\n", (h->state == GG_STATE_READING_UIN_1) ? 1 : 2); | |
| 634 | |
| 635 gg_read(h->fd, &uin, sizeof(uin)); | |
| 636 | |
| 637 if (h->state == GG_STATE_READING_UIN_1) { | |
| 638 h->state = GG_STATE_READING_UIN_2; | |
| 639 h->check = GG_CHECK_READ; | |
| 640 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 641 h->peer_uin = gg_fix32(uin); | |
| 642 } else { | |
| 643 h->state = GG_STATE_SENDING_ACK; | |
| 644 h->check = GG_CHECK_WRITE; | |
| 645 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 646 h->uin = gg_fix32(uin); | |
| 647 e->type = GG_EVENT_DCC_CLIENT_ACCEPT; | |
| 648 } | |
| 649 | |
| 650 return e; | |
| 651 } | |
| 652 | |
| 653 case GG_STATE_SENDING_ACK: | |
| 654 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_SENDING_ACK\n"); | |
| 655 | |
| 656 gg_write(h->fd, ack, 4); | |
| 657 | |
| 658 h->state = GG_STATE_READING_TYPE; | |
| 659 h->check = GG_CHECK_READ; | |
| 660 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 661 | |
| 662 return e; | |
| 663 | |
| 664 case GG_STATE_READING_TYPE: | |
| 665 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_TYPE\n"); | |
| 666 | |
| 667 gg_read(h->fd, &small, sizeof(small)); | |
| 668 | |
| 669 small.type = gg_fix32(small.type); | |
| 670 | |
| 671 switch (small.type) { | |
| 672 case 0x0003: /* XXX */ | |
| 673 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() callback\n"); | |
| 674 h->type = GG_SESSION_DCC_SEND; | |
| 675 h->state = GG_STATE_SENDING_FILE_INFO; | |
| 676 h->check = GG_CHECK_WRITE; | |
| 677 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 678 | |
| 679 e->type = GG_EVENT_DCC_CALLBACK; | |
| 680 | |
| 681 break; | |
| 682 | |
| 683 case 0x0002: /* XXX */ | |
| 684 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() dialin\n"); | |
| 685 h->type = GG_SESSION_DCC_GET; | |
| 686 h->state = GG_STATE_READING_REQUEST; | |
| 687 h->check = GG_CHECK_READ; | |
| 688 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 689 h->incoming = 1; | |
| 690 | |
| 691 break; | |
| 692 | |
| 693 default: | |
| 694 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown dcc type (%.4x) from %ld\n", small.type, h->peer_uin); | |
| 695 e->type = GG_EVENT_DCC_ERROR; | |
| 696 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; | |
| 697 } | |
| 698 | |
| 699 return e; | |
| 700 | |
| 701 case GG_STATE_READING_REQUEST: | |
| 702 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_REQUEST\n"); | |
| 703 | |
| 704 gg_read(h->fd, &small, sizeof(small)); | |
| 705 | |
| 706 small.type = gg_fix32(small.type); | |
| 707 | |
| 708 switch (small.type) { | |
| 709 case 0x0001: /* XXX */ | |
| 710 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() file transfer request\n"); | |
| 711 h->state = GG_STATE_READING_FILE_INFO; | |
| 712 h->check = GG_CHECK_READ; | |
| 713 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 714 break; | |
| 715 | |
| 716 case 0x0003: /* XXX */ | |
| 717 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() voice chat request\n"); | |
| 718 h->state = GG_STATE_SENDING_VOICE_ACK; | |
| 719 h->check = GG_CHECK_WRITE; | |
| 720 h->timeout = GG_DCC_TIMEOUT_VOICE_ACK; | |
| 721 h->type = GG_SESSION_DCC_VOICE; | |
| 722 e->type = GG_EVENT_DCC_NEED_VOICE_ACK; | |
| 723 | |
| 724 break; | |
| 725 | |
| 726 default: | |
| 727 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown dcc request (%.4x) from %ld\n", small.type, h->peer_uin); | |
| 728 e->type = GG_EVENT_DCC_ERROR; | |
| 729 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; | |
| 730 } | |
| 731 | |
| 732 return e; | |
| 733 | |
| 734 case GG_STATE_READING_FILE_INFO: | |
| 735 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_INFO\n"); | |
| 736 | |
| 737 gg_read(h->fd, &file_info_packet, sizeof(file_info_packet)); | |
| 738 | |
| 739 memcpy(&h->file_info, &file_info_packet.file_info, sizeof(h->file_info)); | |
| 740 | |
| 741 h->file_info.mode = gg_fix32(h->file_info.mode); | |
| 742 h->file_info.size = gg_fix32(h->file_info.size); | |
| 743 | |
| 744 h->state = GG_STATE_SENDING_FILE_ACK; | |
| 745 h->check = GG_CHECK_WRITE; | |
| 746 h->timeout = GG_DCC_TIMEOUT_FILE_ACK; | |
| 747 | |
| 748 e->type = GG_EVENT_DCC_NEED_FILE_ACK; | |
| 749 | |
| 750 return e; | |
| 751 | |
| 752 case GG_STATE_SENDING_FILE_ACK: | |
| 753 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_ACK\n"); | |
| 754 | |
| 755 big.type = gg_fix32(0x0006); /* XXX */ | |
| 756 big.dunno1 = gg_fix32(h->offset); | |
| 757 big.dunno2 = 0; | |
| 758 | |
| 759 gg_write(h->fd, &big, sizeof(big)); | |
| 760 | |
| 761 h->state = GG_STATE_READING_FILE_HEADER; | |
| 762 h->chunk_size = sizeof(big); | |
| 763 h->chunk_offset = 0; | |
| 764 if (!(h->chunk_buf = malloc(sizeof(big)))) { | |
| 765 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n"); | |
| 766 free(e); | |
| 767 return NULL; | |
| 768 } | |
| 769 h->check = GG_CHECK_READ; | |
| 770 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 771 | |
| 772 return e; | |
| 773 | |
| 774 case GG_STATE_SENDING_VOICE_ACK: | |
| 775 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_ACK\n"); | |
| 776 | |
| 777 tiny.type = 0x01; /* XXX */ | |
| 778 | |
| 779 gg_write(h->fd, &tiny, sizeof(tiny)); | |
| 780 | |
| 781 h->state = GG_STATE_READING_VOICE_HEADER; | |
| 782 h->check = GG_CHECK_READ; | |
| 783 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 784 | |
| 785 h->offset = 0; | |
| 786 | |
| 787 return e; | |
| 788 | |
| 789 case GG_STATE_READING_FILE_HEADER: | |
| 790 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_HEADER\n"); | |
| 791 | |
| 792 tmp = read(h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); | |
| 793 | |
| 794 if (tmp == -1) { | |
| 795 gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); | |
| 796 e->type = GG_EVENT_DCC_ERROR; | |
| 797 e->event.dcc_error = GG_ERROR_DCC_NET; | |
| 798 return e; | |
| 799 } | |
| 800 | |
| 801 gg_dcc_debug_data("read", h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); | |
| 802 | |
| 803 h->chunk_offset += tmp; | |
| 804 | |
| 805 if (h->chunk_offset < h->chunk_size) | |
| 806 return e; | |
| 807 | |
| 808 memcpy(&big, h->chunk_buf, sizeof(big)); | |
| 809 free(h->chunk_buf); | |
| 810 h->chunk_buf = NULL; | |
| 811 | |
| 812 big.type = gg_fix32(big.type); | |
| 813 h->chunk_size = gg_fix32(big.dunno1); | |
| 814 h->chunk_offset = 0; | |
| 815 | |
| 816 if (big.type == 0x0005) { /* XXX */ | |
| 817 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() transfer refused\n"); | |
| 818 e->type = GG_EVENT_DCC_ERROR; | |
| 819 e->event.dcc_error = GG_ERROR_DCC_REFUSED; | |
| 820 return e; | |
| 821 } | |
| 822 | |
| 823 if (h->chunk_size == 0) { | |
| 824 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() empty chunk, EOF\n"); | |
| 825 e->type = GG_EVENT_DCC_DONE; | |
| 826 return e; | |
| 827 } | |
| 828 | |
| 829 h->state = GG_STATE_GETTING_FILE; | |
| 830 h->check = GG_CHECK_READ; | |
| 831 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 832 h->established = 1; | |
| 833 | |
| 834 return e; | |
| 835 | |
| 836 case GG_STATE_READING_VOICE_HEADER: | |
| 837 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_HEADER\n"); | |
| 838 | |
| 839 gg_read(h->fd, &tiny, sizeof(tiny)); | |
| 840 | |
| 841 switch (tiny.type) { | |
| 842 case 0x03: /* XXX */ | |
| 843 h->state = GG_STATE_READING_VOICE_SIZE; | |
| 844 h->check = GG_CHECK_READ; | |
| 845 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 846 h->established = 1; | |
| 847 break; | |
| 848 case 0x04: /* XXX */ | |
| 849 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() peer breaking connection\n"); | |
| 850 /* XXX zwracać odpowiedni event */ | |
| 851 default: | |
| 852 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown request (%.2x)\n", tiny.type); | |
| 853 e->type = GG_EVENT_DCC_ERROR; | |
| 854 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; | |
| 855 } | |
| 856 | |
| 857 return e; | |
| 858 | |
| 859 case GG_STATE_READING_VOICE_SIZE: | |
| 860 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_SIZE\n"); | |
| 861 | |
| 862 gg_read(h->fd, &small, sizeof(small)); | |
| 863 | |
| 864 small.type = gg_fix32(small.type); | |
| 865 | |
| 866 if (small.type < 16 || small.type > sizeof(buf)) { | |
| 867 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid voice frame size (%d)\n", small.type); | |
| 868 e->type = GG_EVENT_DCC_ERROR; | |
| 869 e->event.dcc_error = GG_ERROR_DCC_NET; | |
| 870 | |
| 871 return e; | |
| 872 } | |
| 873 | |
| 874 h->chunk_size = small.type; | |
| 875 h->chunk_offset = 0; | |
| 876 | |
| 877 if (!(h->voice_buf = malloc(h->chunk_size))) { | |
| 878 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory for voice frame\n"); | |
| 879 return NULL; | |
| 880 } | |
| 881 | |
| 882 h->state = GG_STATE_READING_VOICE_DATA; | |
| 883 h->check = GG_CHECK_READ; | |
| 884 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 885 | |
| 886 return e; | |
| 887 | |
| 888 case GG_STATE_READING_VOICE_DATA: | |
| 889 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_DATA\n"); | |
| 890 | |
| 891 tmp = read(h->fd, h->voice_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); | |
| 892 if (tmp < 1) { | |
| 893 if (tmp == -1) { | |
| 894 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed (errno=%d, %s)\n", errno, strerror(errno)); | |
| 895 } else { | |
| 896 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed, connection broken\n"); | |
| 897 } | |
| 898 e->type = GG_EVENT_DCC_ERROR; | |
| 899 e->event.dcc_error = GG_ERROR_DCC_NET; | |
| 900 return e; | |
| 901 } | |
| 902 | |
| 903 gg_dcc_debug_data("read", h->fd, h->voice_buf + h->chunk_offset, tmp); | |
| 904 | |
| 905 h->chunk_offset += tmp; | |
| 906 | |
| 907 if (h->chunk_offset >= h->chunk_size) { | |
| 908 e->type = GG_EVENT_DCC_VOICE_DATA; | |
| 909 e->event.dcc_voice_data.data = h->voice_buf; | |
| 910 e->event.dcc_voice_data.length = h->chunk_size; | |
| 911 h->state = GG_STATE_READING_VOICE_HEADER; | |
| 912 h->voice_buf = NULL; | |
| 913 } | |
| 914 | |
| 915 h->check = GG_CHECK_READ; | |
| 916 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 917 | |
| 918 return e; | |
| 919 | |
| 920 case GG_STATE_CONNECTING: | |
| 921 { | |
| 922 uin_t uins[2]; | |
| 923 | |
| 924 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_CONNECTING\n"); | |
| 925 | |
| 926 res = 0; | |
| 927 if ((foo = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size)) || res) { | |
| 928 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)); | |
| 929 e->type = GG_EVENT_DCC_ERROR; | |
| 930 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; | |
| 931 return e; | |
| 932 } | |
| 933 | |
| 934 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() connected, sending uins\n"); | |
| 935 | |
| 936 uins[0] = gg_fix32(h->uin); | |
| 937 uins[1] = gg_fix32(h->peer_uin); | |
| 938 | |
| 939 gg_write(h->fd, uins, sizeof(uins)); | |
| 940 | |
| 941 h->state = GG_STATE_READING_ACK; | |
| 942 h->check = GG_CHECK_READ; | |
| 943 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 944 | |
| 945 return e; | |
| 946 } | |
| 947 | |
| 948 case GG_STATE_READING_ACK: | |
| 949 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_ACK\n"); | |
| 950 | |
| 951 gg_read(h->fd, buf, 4); | |
| 952 | |
| 953 if (strncmp(buf, ack, 4)) { | |
| 954 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() did't get ack\n"); | |
| 955 | |
| 956 e->type = GG_EVENT_DCC_ERROR; | |
| 957 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; | |
| 958 return e; | |
| 959 } | |
| 960 | |
| 961 h->check = GG_CHECK_WRITE; | |
| 962 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 963 h->state = GG_STATE_SENDING_REQUEST; | |
| 964 | |
| 965 return e; | |
| 966 | |
| 967 case GG_STATE_SENDING_VOICE_REQUEST: | |
| 968 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_REQUEST\n"); | |
| 969 | |
| 970 small.type = gg_fix32(0x0003); | |
| 971 | |
| 972 gg_write(h->fd, &small, sizeof(small)); | |
| 973 | |
| 974 h->state = GG_STATE_READING_VOICE_ACK; | |
| 975 h->check = GG_CHECK_READ; | |
| 976 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 977 | |
| 978 return e; | |
| 979 | |
| 980 case GG_STATE_SENDING_REQUEST: | |
| 981 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_REQUEST\n"); | |
| 982 | |
| 983 small.type = (h->type == GG_SESSION_DCC_GET) ? gg_fix32(0x0003) : gg_fix32(0x0002); /* XXX */ | |
| 984 | |
| 985 gg_write(h->fd, &small, sizeof(small)); | |
| 986 | |
| 987 switch (h->type) { | |
| 988 case GG_SESSION_DCC_GET: | |
| 989 h->state = GG_STATE_READING_REQUEST; | |
| 990 h->check = GG_CHECK_READ; | |
| 991 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 992 break; | |
| 993 | |
| 994 case GG_SESSION_DCC_SEND: | |
| 995 h->state = GG_STATE_SENDING_FILE_INFO; | |
| 996 h->check = GG_CHECK_WRITE; | |
| 997 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 998 | |
| 999 if (h->file_fd == -1) | |
| 1000 e->type = GG_EVENT_DCC_NEED_FILE_INFO; | |
| 1001 break; | |
| 1002 | |
| 1003 case GG_SESSION_DCC_VOICE: | |
| 1004 h->state = GG_STATE_SENDING_VOICE_REQUEST; | |
| 1005 h->check = GG_CHECK_WRITE; | |
| 1006 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 1007 break; | |
| 1008 } | |
| 1009 | |
| 1010 return e; | |
| 1011 | |
| 1012 case GG_STATE_SENDING_FILE_INFO: | |
| 1013 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_INFO\n"); | |
| 1014 | |
| 1015 if (h->file_fd == -1) { | |
| 1016 e->type = GG_EVENT_DCC_NEED_FILE_INFO; | |
| 1017 return e; | |
| 1018 } | |
| 1019 | |
| 1020 small.type = gg_fix32(0x0001); /* XXX */ | |
| 1021 | |
| 1022 gg_write(h->fd, &small, sizeof(small)); | |
| 1023 | |
| 1024 file_info_packet.big.type = gg_fix32(0x0003); /* XXX */ | |
| 1025 file_info_packet.big.dunno1 = 0; | |
| 1026 file_info_packet.big.dunno2 = 0; | |
| 1027 | |
| 1028 memcpy(&file_info_packet.file_info, &h->file_info, sizeof(h->file_info)); | |
| 1029 | |
| 1030 /* zostają teraz u nas, więc odwracamy z powrotem */ | |
| 1031 h->file_info.size = gg_fix32(h->file_info.size); | |
| 1032 h->file_info.mode = gg_fix32(h->file_info.mode); | |
| 1033 | |
| 1034 gg_write(h->fd, &file_info_packet, sizeof(file_info_packet)); | |
| 1035 | |
| 1036 h->state = GG_STATE_READING_FILE_ACK; | |
| 1037 h->check = GG_CHECK_READ; | |
| 1038 h->timeout = GG_DCC_TIMEOUT_FILE_ACK; | |
| 1039 | |
| 1040 return e; | |
| 1041 | |
| 1042 case GG_STATE_READING_FILE_ACK: | |
| 1043 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_ACK\n"); | |
| 1044 | |
| 1045 gg_read(h->fd, &big, sizeof(big)); | |
| 1046 | |
| 1047 /* XXX sprawdzać wynik */ | |
| 1048 h->offset = gg_fix32(big.dunno1); | |
| 1049 | |
| 1050 h->state = GG_STATE_SENDING_FILE_HEADER; | |
| 1051 h->check = GG_CHECK_WRITE; | |
| 1052 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 1053 | |
| 1054 e->type = GG_EVENT_DCC_ACK; | |
| 1055 | |
| 1056 return e; | |
| 1057 | |
| 1058 case GG_STATE_READING_VOICE_ACK: | |
| 1059 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_ACK\n"); | |
| 1060 | |
| 1061 gg_read(h->fd, &tiny, sizeof(tiny)); | |
| 1062 | |
| 1063 if (tiny.type != 0x01) { | |
| 1064 gg_debug(GG_DEBUG_MISC, "// invalid reply (%.2x), connection refused\n", tiny.type); | |
| 1065 e->type = GG_EVENT_DCC_ERROR; | |
| 1066 e->event.dcc_error = GG_ERROR_DCC_REFUSED; | |
| 1067 return e; | |
| 1068 } | |
| 1069 | |
| 1070 h->state = GG_STATE_READING_VOICE_HEADER; | |
| 1071 h->check = GG_CHECK_READ; | |
| 1072 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 1073 | |
| 1074 e->type = GG_EVENT_DCC_ACK; | |
| 1075 | |
| 1076 return e; | |
| 1077 | |
| 1078 case GG_STATE_SENDING_FILE_HEADER: | |
| 1079 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_HEADER\n"); | |
| 1080 | |
| 1081 h->chunk_offset = 0; | |
| 1082 | |
| 1083 if ((h->chunk_size = h->file_info.size - h->offset) > 4096) { | |
| 1084 h->chunk_size = 4096; | |
| 1085 big.type = gg_fix32(0x0003); /* XXX */ | |
| 1086 } else | |
| 1087 big.type = gg_fix32(0x0002); /* XXX */ | |
| 1088 | |
| 1089 big.dunno1 = gg_fix32(h->chunk_size); | |
| 1090 big.dunno2 = 0; | |
| 1091 | |
| 1092 gg_write(h->fd, &big, sizeof(big)); | |
| 1093 | |
| 1094 h->state = GG_STATE_SENDING_FILE; | |
| 1095 h->check = GG_CHECK_WRITE; | |
| 1096 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 1097 h->established = 1; | |
| 1098 | |
| 1099 return e; | |
| 1100 | |
| 1101 case GG_STATE_SENDING_FILE: | |
| 1102 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE\n"); | |
| 1103 | |
| 1104 if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf)) | |
| 1105 utmp = sizeof(buf); | |
| 1106 | |
| 1107 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset=%d, size=%d\n", h->offset, h->file_info.size); | |
| 1108 | |
| 1109 /* koniec pliku? */ | |
| 1110 if (h->file_info.size == 0) { | |
| 1111 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof on empty file\n"); | |
| 1112 e->type = GG_EVENT_DCC_DONE; | |
| 1113 | |
| 1114 return e; | |
| 1115 } | |
| 1116 | |
| 1117 lseek(h->file_fd, h->offset, SEEK_SET); | |
| 1118 | |
| 1119 size = read(h->file_fd, buf, utmp); | |
| 1120 | |
| 1121 /* błąd */ | |
| 1122 if (size == -1) { | |
| 1123 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno, strerror(errno)); | |
| 1124 | |
| 1125 e->type = GG_EVENT_DCC_ERROR; | |
| 1126 e->event.dcc_error = GG_ERROR_DCC_FILE; | |
| 1127 | |
| 1128 return e; | |
| 1129 } | |
| 1130 | |
| 1131 /* koniec pliku? */ | |
| 1132 if (size == 0) { | |
| 1133 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof\n"); | |
| 1134 e->type = GG_EVENT_DCC_ERROR; | |
| 1135 e->event.dcc_error = GG_ERROR_DCC_EOF; | |
| 1136 | |
| 1137 return e; | |
| 1138 } | |
| 1139 | |
| 1140 /* jeśli wczytaliśmy więcej, utnijmy. */ | |
| 1141 if (h->offset + size > h->file_info.size) { | |
| 1142 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); | |
| 1143 size = h->file_info.size - h->offset; | |
| 1144 | |
| 1145 if (size < 1) { | |
| 1146 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() reached EOF after cutting\n"); | |
| 1147 e->type = GG_EVENT_DCC_DONE; | |
| 1148 return e; | |
| 1149 } | |
| 1150 } | |
| 1151 | |
| 1152 tmp = write(h->fd, buf, size); | |
| 1153 | |
| 1154 if (tmp == -1) { | |
| 1155 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%s)\n", strerror(errno)); | |
| 1156 e->type = GG_EVENT_DCC_ERROR; | |
| 1157 e->event.dcc_error = GG_ERROR_DCC_NET; | |
| 1158 return e; | |
| 1159 } | |
| 1160 | |
| 1161 h->offset += size; | |
| 1162 | |
| 1163 if (h->offset >= h->file_info.size) { | |
| 1164 e->type = GG_EVENT_DCC_DONE; | |
| 1165 return e; | |
| 1166 } | |
| 1167 | |
| 1168 h->chunk_offset += size; | |
| 1169 | |
| 1170 if (h->chunk_offset >= h->chunk_size) { | |
| 1171 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n"); | |
| 1172 h->state = GG_STATE_SENDING_FILE_HEADER; | |
| 1173 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 1174 } else { | |
| 1175 h->state = GG_STATE_SENDING_FILE; | |
| 1176 h->timeout = GG_DCC_TIMEOUT_SEND; | |
| 1177 } | |
| 1178 | |
| 1179 h->check = GG_CHECK_WRITE; | |
| 1180 | |
| 1181 return e; | |
| 1182 | |
| 1183 case GG_STATE_GETTING_FILE: | |
| 1184 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_GETTING_FILE\n"); | |
| 1185 | |
| 1186 if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf)) | |
| 1187 utmp = sizeof(buf); | |
| 1188 | |
| 1189 size = read(h->fd, buf, utmp); | |
| 1190 | |
| 1191 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() ofs=%d, size=%d, read()=%d\n", h->offset, h->file_info.size, size); | |
| 1192 | |
| 1193 /* błąd */ | |
| 1194 if (size == -1) { | |
| 1195 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno, strerror(errno)); | |
| 1196 | |
| 1197 e->type = GG_EVENT_DCC_ERROR; | |
| 1198 e->event.dcc_error = GG_ERROR_DCC_NET; | |
| 1199 | |
| 1200 return e; | |
| 1201 } | |
| 1202 | |
| 1203 /* koniec? */ | |
| 1204 if (size == 0) { | |
| 1205 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof\n"); | |
| 1206 e->type = GG_EVENT_DCC_ERROR; | |
| 1207 e->event.dcc_error = GG_ERROR_DCC_EOF; | |
| 1208 | |
| 1209 return e; | |
| 1210 } | |
| 1211 | |
| 1212 tmp = write(h->file_fd, buf, size); | |
| 1213 | |
| 1214 if (tmp == -1 || tmp < size) { | |
| 1215 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)); | |
| 1216 e->type = GG_EVENT_DCC_ERROR; | |
| 1217 e->event.dcc_error = GG_ERROR_DCC_NET; | |
| 1218 return e; | |
| 1219 } | |
| 1220 | |
| 1221 h->offset += size; | |
| 1222 | |
| 1223 if (h->offset >= h->file_info.size) { | |
| 1224 e->type = GG_EVENT_DCC_DONE; | |
| 1225 return e; | |
| 1226 } | |
| 1227 | |
| 1228 h->chunk_offset += size; | |
| 1229 | |
| 1230 if (h->chunk_offset >= h->chunk_size) { | |
| 1231 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n"); | |
| 1232 h->state = GG_STATE_READING_FILE_HEADER; | |
| 1233 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 1234 h->chunk_offset = 0; | |
| 1235 h->chunk_size = sizeof(big); | |
| 1236 if (!(h->chunk_buf = malloc(sizeof(big)))) { | |
| 1237 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory\n"); | |
| 1238 free(e); | |
| 1239 return NULL; | |
| 1240 } | |
| 1241 } else { | |
| 1242 h->state = GG_STATE_GETTING_FILE; | |
| 1243 h->timeout = GG_DCC_TIMEOUT_GET; | |
| 1244 } | |
| 1245 | |
| 1246 h->check = GG_CHECK_READ; | |
| 1247 | |
| 1248 return e; | |
| 1249 | |
| 1250 default: | |
| 1251 gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_???\n"); | |
| 1252 e->type = GG_EVENT_DCC_ERROR; | |
| 1253 e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; | |
| 1254 | |
| 1255 return e; | |
| 1256 } | |
| 1257 } | |
| 1258 | |
| 1259 return e; | |
| 1260 } | |
| 1261 | |
| 1262 #undef gg_read | |
| 1263 #undef gg_write | |
| 1264 | |
| 1265 /* | |
| 1266 * gg_dcc_free() | |
| 1267 * | |
| 1268 * zwalnia pamięć po strukturze połączenia dcc. | |
| 1269 * | |
| 1270 * - d - zwalniana struktura | |
| 1271 */ | |
| 1272 void gg_dcc_free(struct gg_dcc *d) | |
| 1273 { | |
| 1274 gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d); | |
| 1275 | |
| 1276 if (!d) | |
| 1277 return; | |
| 1278 | |
| 1279 if (d->fd != -1) | |
| 1280 close(d->fd); | |
| 1281 | |
| 1282 if (d->chunk_buf) { | |
| 1283 free(d->chunk_buf); | |
| 1284 d->chunk_buf = NULL; | |
| 1285 } | |
| 1286 | |
| 1287 free(d); | |
| 1288 } | |
| 1289 | |
| 1290 /* | |
| 1291 * Local variables: | |
| 1292 * c-indentation-style: k&r | |
| 1293 * c-basic-offset: 8 | |
| 1294 * indent-tabs-mode: notnil | |
| 1295 * End: | |
| 1296 * | |
| 1297 * vim: shiftwidth=8: | |
| 1298 */ |
