Ignore:
Timestamp:
2016-11-13T20:10:17Z (8 years ago)
Author:
dequis <dx@…>
Branches:
master
Children:
9f03c47
Parents:
701ab812
git-author:
dequis <dx@…> (13-11-16 20:00:04)
git-committer:
dequis <dx@…> (13-11-16 20:10:17)
Message:

purple: fix file transfer memory management

This means cancelling transfers on logout to avoid crashes, keeping
track of timeouts, reffing and unreffing the xfers, listening to the
callbacks from UI and purple more carefully and using the correct
functions to free the correct things at the correct moments.

Originally intended to fix a crash triggered when the dcc stall timeout
kicks in after the account is offline, which is apparently very frequent
with telegram (it sends file transfers while fetching history, and
randomly disconnects a while later).

Trying to fix that meant opening a can of worms, but after three days of
work on this bug I'm pretty sure I've finished dealing with the
resulting mess and tested all the typical edge cases.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/purple/ft.c

    r701ab812 rea90275  
    4242        char *fn, *handle;
    4343        gboolean ui_wants_data;
     44        int timeout;
    4445};
    4546
     
    6465        struct prpl_xfer_data *px = ft->data;
    6566
    66         purple_xfer_request_denied(px->xfer);
     67        if (px->xfer) {
     68                if (!purple_xfer_is_completed(px->xfer) && !purple_xfer_is_canceled(px->xfer)) {
     69                        purple_xfer_cancel_local(px->xfer);
     70                }
     71                px->xfer->ui_data = NULL;
     72                purple_xfer_unref(px->xfer);
     73                px->xfer = NULL;
     74        }
     75}
     76
     77static void prpl_xfer_free(struct file_transfer *ft)
     78{
     79        struct prpl_xfer_data *px = ft->data;
     80        struct purple_data *pd = px->ic->proto_data;
     81
     82        pd->filetransfers = g_slist_remove(pd->filetransfers, px);
     83
     84        if (px->xfer) {
     85                px->xfer->ui_data = NULL;
     86                purple_xfer_unref(px->xfer);
     87        }
     88
     89        if (px->timeout) {
     90                b_event_remove(px->timeout);
     91        }
     92
     93        g_free(px->fn);
     94        g_free(px->handle);
     95        if (px->fd >= 0) {
     96                close(px->fd);
     97        }
     98        g_free(px);
    6799}
    68100
    69101static void prplcb_xfer_new(PurpleXfer *xfer)
    70102{
     103        purple_xfer_ref(xfer);
     104
    71105        if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) {
    72106                struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1);
     107                struct purple_data *pd;
    73108
    74109                xfer->ui_data = px;
     
    77112                px->fd = -1;
    78113                px->ic = purple_ic_by_pa(xfer->account);
     114
     115                pd = px->ic->proto_data;
     116                pd->filetransfers = g_slist_prepend(pd->filetransfers, px);
    79117
    80118                purple_xfer_set_local_filename(xfer, px->fn);
     
    112150        px->ft->accept = prpl_xfer_accept;
    113151        px->ft->canceled = prpl_xfer_canceled;
     152        px->ft->free = prpl_xfer_free;
    114153        px->ft->write_request = prpl_xfer_write_request;
    115154
     
    164203
    165204
    166 /* Generic (IM<>UI): */
    167205static void prplcb_xfer_destroy(PurpleXfer *xfer)
    168206{
    169207        struct prpl_xfer_data *px = xfer->ui_data;
    170208
    171         g_free(px->fn);
    172         g_free(px->handle);
    173         if (px->fd >= 0) {
    174                 close(px->fd);
    175         }
    176         g_free(px);
     209        if (px) {
     210                px->xfer = NULL;
     211        }
    177212}
    178213
     
    224259        struct prpl_xfer_data *px = xfer->ui_data;
    225260
    226         if (px->ft) {
     261        if (px && px->ft) {
    227262                imcb_file_canceled(px->ic, px->ft, "Canceled by remote end");
    228         } else {
     263        } else if (px) {
    229264                /* px->ft == NULL for sends, because of the two stages. :-/ */
    230265                imcb_error(px->ic, "File transfer cancelled by remote end");
     
    240275{
    241276        struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1);
     277        struct purple_data *pd;
    242278        char *dir, *basename;
    243279
    244280        ft->data = px;
    245281        px->ft = ft;
     282        px->ft->free = prpl_xfer_free;
    246283
    247284        dir = g_strdup("/tmp/bitlbee-purple-ft.XXXXXX");
     
    272309        px->handle = g_strdup(handle);
    273310
     311        pd = px->ic->proto_data;
     312        pd->filetransfers = g_slist_prepend(pd->filetransfers, px);
     313
    274314        imcb_log(ic,
    275315                 "Due to libpurple limitations, the file has to be cached locally before proceeding with the actual file transfer. Please wait...");
    276316
    277         b_timeout_add(0, purple_transfer_request_cb, ft);
     317        px->timeout = b_timeout_add(0, purple_transfer_request_cb, ft);
    278318}
    279319
     
    295335        struct prpl_xfer_data *px = ft->data;
    296336
     337        px->timeout = 0;
     338
    297339        if (ft->write == NULL) {
    298340                ft->write = prpl_xfer_write;
     
    322364                px->ft = NULL;
    323365        } else {
    324                 b_timeout_add(0, purple_transfer_request_cb, ft);
     366                px->timeout = b_timeout_add(0, purple_transfer_request_cb, ft);
    325367        }
    326368
    327369        return TRUE;
     370}
     371
     372void purple_transfer_cancel_all(struct im_connection *ic)
     373{
     374        struct purple_data *pd = ic->proto_data;
     375
     376        while (pd->filetransfers) {
     377                struct prpl_xfer_data *px = pd->filetransfers->data;
     378
     379                if (px->ft) {
     380                        imcb_file_canceled(ic, px->ft, "Logging out");
     381                }
     382
     383                pd->filetransfers = g_slist_remove(pd->filetransfers, px);
     384        }
    328385}
    329386
Note: See TracChangeset for help on using the changeset viewer.