session.c (22351B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #include "defs.h" 21 22 #include <glib.h> 23 #include <glib/gi18n.h> 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 #include <time.h> 30 #include <errno.h> 31 32 #include "session.h" 33 #include "utils.h" 34 #include "log.h" 35 36 static gint session_connect_cb (SockInfo *sock, 37 gpointer data); 38 static gint session_close (Session *session); 39 40 static gboolean session_timeout_cb (gpointer data); 41 42 static gboolean session_recv_msg_idle_cb (gpointer data); 43 static gboolean session_recv_data_idle_cb (gpointer data); 44 45 static gboolean session_read_msg_cb (SockInfo *source, 46 GIOCondition condition, 47 gpointer data); 48 static gboolean session_read_data_cb (SockInfo *source, 49 GIOCondition condition, 50 gpointer data); 51 static gboolean session_write_msg_cb (SockInfo *source, 52 GIOCondition condition, 53 gpointer data); 54 static gboolean session_write_data_cb (SockInfo *source, 55 GIOCondition condition, 56 gpointer data); 57 58 59 void session_init(Session *session, const void *prefs_account, gboolean is_smtp) 60 { 61 session->type = SESSION_UNKNOWN; 62 session->sock = NULL; 63 session->server = NULL; 64 session->port = 0; 65 session->ssl_type = SSL_NONE; 66 session->use_tls_sni = TRUE; 67 session->nonblocking = TRUE; 68 session->state = SESSION_READY; 69 session->last_access_time = time(NULL); 70 71 session->tv_prev = g_date_time_new_now_local(); 72 73 session->conn_id = 0; 74 75 session->io_tag = 0; 76 77 session->read_buf_p = session->read_buf; 78 session->read_buf_len = 0; 79 80 session->read_msg_buf = g_string_sized_new(1024); 81 session->read_data_buf = g_byte_array_new(); 82 83 session->write_buf = NULL; 84 session->write_buf_p = NULL; 85 session->write_buf_len = 0; 86 87 session->write_data = NULL; 88 session->write_data_p = NULL; 89 session->write_data_len = 0; 90 91 session->timeout_tag = 0; 92 session->timeout_interval = 0; 93 94 session->data = NULL; 95 session->account = prefs_account; 96 session->is_smtp = is_smtp; 97 98 session->ping_tag = -1; 99 } 100 101 /*! 102 *\brief Set up parent and child process 103 * Childloop: Read commands from parent, 104 * send to server, get answer, pass to parent 105 * 106 *\param session Contains session information 107 * server to connect to 108 * port to connect to 109 * 110 *\return 0 : success 111 * -1 : pipe / fork errors (parent) 112 * 1 : connection error (child) 113 */ 114 gint session_connect(Session *session, const gchar *server, gushort port) 115 { 116 session->server = g_strdup(server); 117 session->port = port; 118 119 #ifdef G_OS_UNIX 120 session->conn_id = sock_connect_async(server, port, session_connect_cb, 121 session); 122 if (session->conn_id < 0) { 123 g_warning("can't connect to server"); 124 session_close(session); 125 if (session->connect_finished) 126 session->connect_finished(session, FALSE); 127 return -1; 128 } 129 130 return 0; 131 #else 132 SockInfo *sock; 133 134 sock = sock_connect(server, port); 135 if (sock == NULL) { 136 g_warning("can't connect to server"); 137 session_close(session); 138 if (session->connect_finished) 139 session->connect_finished(session, FALSE); 140 return -1; 141 } 142 sock->is_smtp = session->is_smtp; 143 144 return session_connect_cb(sock, session); 145 #endif 146 } 147 148 static gint session_connect_cb(SockInfo *sock, gpointer data) 149 { 150 Session *session = SESSION(data); 151 152 session->conn_id = 0; 153 154 if (!sock) { 155 g_warning("can't connect to server"); 156 session->state = SESSION_ERROR; 157 if (session->connect_finished) 158 session->connect_finished(session, FALSE); 159 return -1; 160 } 161 162 session->sock = sock; 163 sock->account = session->account; 164 sock->is_smtp = session->is_smtp; 165 sock->ssl_cert_auto_accept = TRUE; 166 167 sock->gnutls_priority = session->gnutls_priority; 168 sock->use_tls_sni = session->use_tls_sni; 169 170 if (session->ssl_type == SSL_TUNNEL) { 171 sock_set_nonblocking_mode(sock, FALSE); 172 if (!ssl_init_socket(sock)) { 173 g_warning("can't initialize TLS"); 174 log_error(LOG_PROTOCOL, _("TLS handshake failed\n")); 175 session->state = SESSION_ERROR; 176 if (session->connect_finished) 177 session->connect_finished(session, FALSE); 178 return -1; 179 } 180 } 181 182 /* we could have gotten a timeout while waiting for user input in 183 * an SSL certificate dialog */ 184 if (session->state == SESSION_TIMEOUT) { 185 if (session->connect_finished) 186 session->connect_finished(session, FALSE); 187 return -1; 188 } 189 190 sock_set_nonblocking_mode(sock, session->nonblocking); 191 192 debug_print("session (%p): connected\n", session); 193 194 session->state = SESSION_RECV; 195 session->io_tag = sock_add_watch(session->sock, G_IO_IN, 196 session_read_msg_cb, 197 session); 198 199 if (session->connect_finished) 200 session->connect_finished(session, TRUE); 201 return 0; 202 } 203 204 /*! 205 *\brief child and parent: send DISCONNECT message to other process 206 * 207 *\param session Contains session information 208 * 209 *\return 0 : success 210 */ 211 gint session_disconnect(Session *session) 212 { 213 session_close(session); 214 return 0; 215 } 216 217 /*! 218 *\brief parent ? 219 * 220 *\param session Contains session information 221 */ 222 void session_destroy(Session *session) 223 { 224 cm_return_if_fail(session != NULL); 225 cm_return_if_fail(session->destroy != NULL); 226 227 session_register_ping(session, NULL); 228 229 session_close(session); 230 session->destroy(session); 231 g_free(session->server); 232 g_string_free(session->read_msg_buf, TRUE); 233 g_byte_array_free(session->read_data_buf, TRUE); 234 g_free(session->read_data_terminator); 235 g_free(session->write_buf); 236 g_free(session->gnutls_priority); 237 g_date_time_unref(session->tv_prev); 238 debug_print("session (%p): destroyed\n", session); 239 240 g_free(session); 241 } 242 243 gboolean session_is_running(Session *session) 244 { 245 return (session->state == SESSION_READY || 246 session->state == SESSION_SEND || 247 session->state == SESSION_RECV); 248 } 249 250 gboolean session_is_connected(Session *session) 251 { 252 return (session->state == SESSION_SEND || 253 session->state == SESSION_RECV); 254 } 255 256 void session_set_access_time(Session *session) 257 { 258 session->last_access_time = time(NULL); 259 } 260 261 void session_set_timeout(Session *session, guint interval) 262 { 263 if (session->timeout_tag > 0) 264 g_source_remove(session->timeout_tag); 265 266 session->timeout_interval = interval; 267 if (interval > 0) { 268 if (interval % 1000 == 0) 269 session->timeout_tag = 270 g_timeout_add_seconds(interval/1000, session_timeout_cb, session); 271 else 272 session->timeout_tag = 273 g_timeout_add(interval, session_timeout_cb, session); 274 } else 275 session->timeout_tag = 0; 276 } 277 278 static gboolean session_timeout_cb(gpointer data) 279 { 280 Session *session = SESSION(data); 281 282 g_warning("session timeout"); 283 284 if (session->io_tag > 0) { 285 g_source_remove(session->io_tag); 286 session->io_tag = 0; 287 } 288 289 session->timeout_tag = 0; 290 session->state = SESSION_TIMEOUT; 291 292 return FALSE; 293 } 294 295 void session_set_recv_message_notify(Session *session, 296 RecvMsgNotify notify_func, gpointer data) 297 { 298 session->recv_msg_notify = notify_func; 299 session->recv_msg_notify_data = data; 300 } 301 302 void session_set_recv_data_progressive_notify 303 (Session *session, 304 RecvDataProgressiveNotify notify_func, 305 gpointer data) 306 { 307 session->recv_data_progressive_notify = notify_func, 308 session->recv_data_progressive_notify_data = data; 309 } 310 311 void session_set_recv_data_notify(Session *session, RecvDataNotify notify_func, 312 gpointer data) 313 { 314 session->recv_data_notify = notify_func; 315 session->recv_data_notify_data = data; 316 } 317 318 void session_set_send_data_progressive_notify 319 (Session *session, 320 SendDataProgressiveNotify notify_func, 321 gpointer data) 322 { 323 session->send_data_progressive_notify = notify_func; 324 session->send_data_progressive_notify_data = data; 325 } 326 327 void session_set_send_data_notify(Session *session, SendDataNotify notify_func, 328 gpointer data) 329 { 330 session->send_data_notify = notify_func; 331 session->send_data_notify_data = data; 332 } 333 334 /*! 335 *\brief child and parent cleanup (child closes first) 336 * 337 *\param session Contains session information 338 * 339 *\return 0 : success 340 */ 341 static gint session_close(Session *session) 342 { 343 cm_return_val_if_fail(session != NULL, -1); 344 345 #ifdef G_OS_UNIX 346 if (session->conn_id > 0) { 347 sock_connect_async_cancel(session->conn_id); 348 session->conn_id = 0; 349 debug_print("session (%p): connection cancelled\n", session); 350 } 351 #endif 352 353 session_set_timeout(session, 0); 354 355 if (session->io_tag > 0) { 356 g_source_remove(session->io_tag); 357 session->io_tag = 0; 358 } 359 360 if (session->sock) { 361 sock_close(session->sock, TRUE); 362 session->sock = NULL; 363 session->state = SESSION_DISCONNECTED; 364 debug_print("session (%p): closed\n", session); 365 } 366 367 return 0; 368 } 369 370 gint session_start_tls(Session *session) 371 { 372 gboolean nb_mode; 373 374 nb_mode = sock_is_nonblocking_mode(session->sock); 375 376 session->sock->ssl_cert_auto_accept = session->ssl_cert_auto_accept; 377 session->sock->gnutls_priority = session->gnutls_priority; 378 session->sock->use_tls_sni = session->use_tls_sni; 379 380 if (nb_mode) 381 sock_set_nonblocking_mode(session->sock, FALSE); 382 383 if (!ssl_init_socket(session->sock)) { 384 g_warning("couldn't start STARTTLS session"); 385 if (nb_mode) 386 sock_set_nonblocking_mode(session->sock, session->nonblocking); 387 return -1; 388 } 389 390 if (0 < session->read_buf_len) { 391 g_warning("protocol violation: suffix data after STARTTLS detected"); 392 if (nb_mode) 393 sock_set_nonblocking_mode(session->sock, session->nonblocking); 394 return -1; 395 } 396 397 if (nb_mode) 398 sock_set_nonblocking_mode(session->sock, session->nonblocking); 399 400 return 0; 401 } 402 403 gint session_send_msg(Session *session, const gchar *msg) 404 { 405 gboolean ret; 406 407 cm_return_val_if_fail(session->write_buf == NULL, -1); 408 cm_return_val_if_fail(msg != NULL, -1); 409 410 session->state = SESSION_SEND; 411 session->write_buf = g_strconcat((strlen(msg) > 0 ? msg : ""), "\r\n", NULL); 412 session->write_buf_p = session->write_buf; 413 session->write_buf_len = strlen(msg) + 2; 414 415 ret = session_write_msg_cb(session->sock, G_IO_OUT, session); 416 417 if (ret == TRUE) 418 session->io_tag = sock_add_watch(session->sock, G_IO_OUT, 419 session_write_msg_cb, session); 420 else if (session->state == SESSION_ERROR) 421 return -1; 422 423 return 0; 424 } 425 426 gint session_recv_msg(Session *session) 427 { 428 cm_return_val_if_fail(session->read_msg_buf->len == 0, -1); 429 430 session->state = SESSION_RECV; 431 432 if (session->read_buf_len > 0) 433 g_idle_add(session_recv_msg_idle_cb, session); 434 else 435 session->io_tag = sock_add_watch(session->sock, G_IO_IN, 436 session_read_msg_cb, session); 437 438 return 0; 439 } 440 441 static gboolean session_recv_msg_idle_cb(gpointer data) 442 { 443 Session *session = SESSION(data); 444 gboolean ret; 445 446 ret = session_read_msg_cb(session->sock, G_IO_IN, session); 447 448 if (ret == TRUE) 449 session->io_tag = sock_add_watch(session->sock, G_IO_IN, 450 session_read_msg_cb, session); 451 452 return FALSE; 453 } 454 455 /*! 456 *\brief parent (child?): send data to other process 457 * 458 *\param session Contains session information 459 * data Data to send 460 * size Bytes to send 461 * 462 *\return 0 : success 463 * -1 : error 464 */ 465 gint session_send_data(Session *session, const guchar *data, guint size) 466 { 467 gboolean ret; 468 469 cm_return_val_if_fail(session->write_data == NULL, -1); 470 cm_return_val_if_fail(data != NULL, -1); 471 cm_return_val_if_fail(size != 0, -1); 472 473 session->state = SESSION_SEND; 474 475 session->write_data = data; 476 session->write_data_p = session->write_data; 477 session->write_data_len = size; 478 g_date_time_unref(session->tv_prev); 479 session->tv_prev = g_date_time_new_now_local(); 480 481 ret = session_write_data_cb(session->sock, G_IO_OUT, session); 482 483 if (ret == TRUE) 484 session->io_tag = sock_add_watch(session->sock, G_IO_OUT, 485 session_write_data_cb, 486 session); 487 else if (session->state == SESSION_ERROR) 488 return -1; 489 490 return 0; 491 } 492 493 gint session_recv_data(Session *session, guint size, const gchar *terminator) 494 { 495 cm_return_val_if_fail(session->read_data_buf->len == 0, -1); 496 497 session->state = SESSION_RECV; 498 499 g_free(session->read_data_terminator); 500 session->read_data_terminator = g_strdup(terminator); 501 g_date_time_unref(session->tv_prev); 502 session->tv_prev = g_date_time_new_now_local(); 503 504 if (session->read_buf_len > 0) 505 g_idle_add(session_recv_data_idle_cb, session); 506 else 507 session->io_tag = sock_add_watch(session->sock, G_IO_IN, 508 session_read_data_cb, session); 509 510 return 0; 511 } 512 513 static gboolean session_recv_data_idle_cb(gpointer data) 514 { 515 Session *session = SESSION(data); 516 gboolean ret; 517 518 ret = session_read_data_cb(session->sock, G_IO_IN, session); 519 520 if (ret == TRUE) 521 session->io_tag = sock_add_watch(session->sock, G_IO_IN, 522 session_read_data_cb, session); 523 524 return FALSE; 525 } 526 527 static gboolean session_read_msg_cb(SockInfo *source, GIOCondition condition, 528 gpointer data) 529 { 530 Session *session = SESSION(data); 531 gchar buf[SESSION_BUFFSIZE]; 532 gint line_len; 533 gchar *newline; 534 gchar *msg; 535 gint ret; 536 537 cm_return_val_if_fail(condition == G_IO_IN, FALSE); 538 539 session_set_timeout(session, session->timeout_interval); 540 541 if (session->read_buf_len == 0) { 542 gint read_len = -1; 543 544 if (session->sock) 545 read_len = sock_read(session->sock, session->read_buf, 546 SESSION_BUFFSIZE - 1); 547 548 if (read_len == -1 && session->state == SESSION_DISCONNECTED) { 549 g_warning("sock_read: session disconnected"); 550 if (session->io_tag > 0) { 551 g_source_remove(session->io_tag); 552 session->io_tag = 0; 553 } 554 return FALSE; 555 } 556 557 if (read_len == 0) { 558 g_warning("sock_read: received EOF"); 559 session->state = SESSION_EOF; 560 return FALSE; 561 } 562 563 if (read_len < 0) { 564 switch (errno) { 565 case EAGAIN: 566 return TRUE; 567 default: 568 g_warning("sock_read: %s", g_strerror(errno)); 569 session->state = SESSION_ERROR; 570 return FALSE; 571 } 572 } 573 574 session->read_buf_len = read_len; 575 } 576 577 if ((newline = memchr(session->read_buf_p, '\n', session->read_buf_len)) 578 != NULL) 579 line_len = newline - session->read_buf_p + 1; 580 else 581 line_len = session->read_buf_len; 582 583 if (line_len == 0) 584 return TRUE; 585 586 memcpy(buf, session->read_buf_p, line_len); 587 buf[line_len] = '\0'; 588 589 g_string_append(session->read_msg_buf, buf); 590 591 session->read_buf_len -= line_len; 592 if (session->read_buf_len == 0) 593 session->read_buf_p = session->read_buf; 594 else 595 session->read_buf_p += line_len; 596 597 /* incomplete read */ 598 if (buf[line_len - 1] != '\n') 599 return TRUE; 600 601 /* complete */ 602 if (session->io_tag > 0) { 603 g_source_remove(session->io_tag); 604 session->io_tag = 0; 605 } 606 607 /* callback */ 608 msg = g_strdup(session->read_msg_buf->str); 609 strretchomp(msg); 610 g_string_truncate(session->read_msg_buf, 0); 611 612 ret = session->recv_msg(session, msg); 613 session->recv_msg_notify(session, msg, session->recv_msg_notify_data); 614 615 g_free(msg); 616 617 if (ret < 0) 618 session->state = SESSION_ERROR; 619 620 return FALSE; 621 } 622 623 static gboolean session_read_data_cb(SockInfo *source, GIOCondition condition, 624 gpointer data) 625 { 626 Session *session = SESSION(data); 627 GByteArray *data_buf; 628 gint terminator_len; 629 gboolean complete = FALSE; 630 guint data_len; 631 gint ret; 632 633 cm_return_val_if_fail(condition == G_IO_IN, FALSE); 634 635 session_set_timeout(session, session->timeout_interval); 636 637 if (session->read_buf_len == 0) { 638 gint read_len; 639 640 read_len = sock_read(session->sock, session->read_buf, 641 SESSION_BUFFSIZE); 642 643 if (read_len == 0) { 644 g_warning("sock_read: received EOF"); 645 session->state = SESSION_EOF; 646 return FALSE; 647 } 648 649 if (read_len < 0) { 650 switch (errno) { 651 case EAGAIN: 652 return TRUE; 653 default: 654 g_warning("sock_read: %s", g_strerror(errno)); 655 session->state = SESSION_ERROR; 656 return FALSE; 657 } 658 } 659 660 session->read_buf_len = read_len; 661 } 662 663 data_buf = session->read_data_buf; 664 terminator_len = strlen(session->read_data_terminator); 665 666 if (session->read_buf_len == 0) 667 return TRUE; 668 669 g_byte_array_append(data_buf, session->read_buf_p, 670 session->read_buf_len); 671 672 session->read_buf_len = 0; 673 session->read_buf_p = session->read_buf; 674 675 /* check if data is terminated */ 676 if (data_buf->len >= terminator_len) { 677 if (memcmp(data_buf->data, session->read_data_terminator, 678 terminator_len) == 0) 679 complete = TRUE; 680 else if (data_buf->len >= terminator_len + 2 && 681 memcmp(data_buf->data + data_buf->len - 682 (terminator_len + 2), "\r\n", 2) == 0 && 683 memcmp(data_buf->data + data_buf->len - 684 terminator_len, session->read_data_terminator, 685 terminator_len) == 0) 686 complete = TRUE; 687 } 688 689 /* incomplete read */ 690 if (!complete) { 691 GDateTime *tv_cur = g_date_time_new_now_local(); 692 693 GTimeSpan ts = g_date_time_difference(tv_cur, session->tv_prev); 694 if (1000 - ts < 0 || ts > UI_REFRESH_INTERVAL) { 695 session->recv_data_progressive_notify 696 (session, data_buf->len, 0, 697 session->recv_data_progressive_notify_data); 698 g_date_time_unref(session->tv_prev); 699 session->tv_prev = g_date_time_new_now_local(); 700 } 701 g_date_time_unref(tv_cur); 702 return TRUE; 703 } 704 705 /* complete */ 706 if (session->io_tag > 0) { 707 g_source_remove(session->io_tag); 708 session->io_tag = 0; 709 } 710 711 data_len = data_buf->len - terminator_len; 712 713 /* callback */ 714 ret = session->recv_data_finished(session, (gchar *)data_buf->data, 715 data_len); 716 717 g_byte_array_set_size(data_buf, 0); 718 719 session->recv_data_notify(session, data_len, 720 session->recv_data_notify_data); 721 722 if (ret < 0) 723 session->state = SESSION_ERROR; 724 725 return FALSE; 726 } 727 728 static gint session_write_buf(Session *session) 729 { 730 gint write_len; 731 gint to_write_len; 732 733 cm_return_val_if_fail(session->write_buf != NULL, -1); 734 cm_return_val_if_fail(session->write_buf_p != NULL, -1); 735 cm_return_val_if_fail(session->write_buf_len > 0, -1); 736 737 to_write_len = session->write_buf_len - 738 (session->write_buf_p - session->write_buf); 739 to_write_len = MIN(to_write_len, SESSION_BUFFSIZE); 740 741 write_len = sock_write(session->sock, session->write_buf_p, 742 to_write_len); 743 744 if (write_len < 0) { 745 switch (errno) { 746 case EAGAIN: 747 write_len = 0; 748 break; 749 default: 750 g_warning("sock_write: %s", g_strerror(errno)); 751 session->state = SESSION_ERROR; 752 return -1; 753 } 754 } 755 756 /* incomplete write */ 757 if (session->write_buf_p - session->write_buf + write_len < 758 session->write_buf_len) { 759 session->write_buf_p += write_len; 760 return 1; 761 } 762 763 g_free(session->write_buf); 764 session->write_buf = NULL; 765 session->write_buf_p = NULL; 766 session->write_buf_len = 0; 767 768 return 0; 769 } 770 771 static gint session_write_data(Session *session) 772 { 773 gint write_len; 774 gint to_write_len; 775 776 cm_return_val_if_fail(session->write_data != NULL, -1); 777 cm_return_val_if_fail(session->write_data_p != NULL, -1); 778 cm_return_val_if_fail(session->write_data_len > 0, -1); 779 780 to_write_len = session->write_data_len - 781 (session->write_data_p - session->write_data); 782 to_write_len = MIN(to_write_len, SESSION_BUFFSIZE); 783 784 write_len = sock_write(session->sock, session->write_data_p, 785 to_write_len); 786 787 if (write_len < 0) { 788 switch (errno) { 789 case EAGAIN: 790 write_len = 0; 791 break; 792 default: 793 g_warning("sock_write: %s", g_strerror(errno)); 794 session->state = SESSION_ERROR; 795 return -1; 796 } 797 } 798 799 /* incomplete write */ 800 if (session->write_data_p - session->write_data + write_len < 801 session->write_data_len) { 802 session->write_data_p += write_len; 803 return 1; 804 } 805 806 session->write_data = NULL; 807 session->write_data_p = NULL; 808 session->write_data_len = 0; 809 810 return 0; 811 } 812 813 static gboolean session_write_msg_cb(SockInfo *source, GIOCondition condition, 814 gpointer data) 815 { 816 Session *session = SESSION(data); 817 gint ret; 818 819 cm_return_val_if_fail(condition == G_IO_OUT, FALSE); 820 cm_return_val_if_fail(session->write_buf != NULL, FALSE); 821 cm_return_val_if_fail(session->write_buf_p != NULL, FALSE); 822 cm_return_val_if_fail(session->write_buf_len > 0, FALSE); 823 824 ret = session_write_buf(session); 825 826 if (ret < 0) { 827 session->state = SESSION_ERROR; 828 return FALSE; 829 } else if (ret > 0) 830 return TRUE; 831 832 if (session->io_tag > 0) { 833 g_source_remove(session->io_tag); 834 session->io_tag = 0; 835 } 836 837 session_recv_msg(session); 838 839 return FALSE; 840 } 841 842 static gboolean session_write_data_cb(SockInfo *source, 843 GIOCondition condition, gpointer data) 844 { 845 Session *session = SESSION(data); 846 guint write_data_len; 847 gint ret; 848 849 cm_return_val_if_fail(condition == G_IO_OUT, FALSE); 850 cm_return_val_if_fail(session->write_data != NULL, FALSE); 851 cm_return_val_if_fail(session->write_data_p != NULL, FALSE); 852 cm_return_val_if_fail(session->write_data_len > 0, FALSE); 853 854 write_data_len = session->write_data_len; 855 856 ret = session_write_data(session); 857 858 if (ret < 0) { 859 session->state = SESSION_ERROR; 860 return FALSE; 861 } else if (ret > 0) { 862 GDateTime *tv_cur = g_date_time_new_now_local(); 863 864 GTimeSpan ts = g_date_time_difference(tv_cur, session->tv_prev); 865 if (1000 - ts < 0 || ts > UI_REFRESH_INTERVAL) { 866 session_set_timeout(session, session->timeout_interval); 867 session->send_data_progressive_notify 868 (session, 869 session->write_data_p - session->write_data, 870 write_data_len, 871 session->send_data_progressive_notify_data); 872 g_date_time_unref(session->tv_prev); 873 session->tv_prev = g_date_time_new_now_local(); 874 } 875 g_date_time_unref(tv_cur); 876 return TRUE; 877 } 878 879 if (session->io_tag > 0) { 880 g_source_remove(session->io_tag); 881 session->io_tag = 0; 882 } 883 884 /* callback */ 885 ret = session->send_data_finished(session, write_data_len); 886 session->send_data_notify(session, write_data_len, 887 session->send_data_notify_data); 888 889 return FALSE; 890 } 891 892 void session_register_ping(Session *session, gboolean (*ping_cb)(gpointer data)) 893 { 894 if (!session) 895 return; 896 if (session->ping_tag > -1) 897 g_source_remove(session->ping_tag); 898 899 session->ping_tag = -1; 900 901 if (ping_cb != NULL) 902 session->ping_tag = g_timeout_add_seconds(60, ping_cb, session); 903 }