void tr_bandwidthAllocate( tr_bandwidth * b, tr_direction dir, unsigned int period_msec ) { int i, peerCount; tr_ptrArray tmp = TR_PTR_ARRAY_INIT; tr_ptrArray low = TR_PTR_ARRAY_INIT; tr_ptrArray high = TR_PTR_ARRAY_INIT; tr_ptrArray normal = TR_PTR_ARRAY_INIT; struct tr_peerIo ** peers; /* allocateBandwidth() is a helper function with two purposes: * 1. allocate bandwidth to b and its subtree * 2. accumulate an array of all the peerIos from b and its subtree. */ allocateBandwidth( b, TR_PRI_LOW, dir, period_msec, &tmp ); peers = (struct tr_peerIo**) tr_ptrArrayBase( &tmp ); peerCount = tr_ptrArraySize( &tmp ); for( i=0; i<peerCount; ++i ) { tr_peerIo * io = peers[i]; tr_peerIoRef( io ); tr_peerIoFlushOutgoingProtocolMsgs( io ); switch( io->priority ) { case TR_PRI_HIGH: tr_ptrArrayAppend( &high, io ); /* fall through */ case TR_PRI_NORMAL: tr_ptrArrayAppend( &normal, io ); /* fall through */ default: tr_ptrArrayAppend( &low, io ); } } /* First phase of IO. Tries to distribute bandwidth fairly to keep faster * peers from starving the others. Loop through the peers, giving each a * small chunk of bandwidth. Keep looping until we run out of bandwidth * and/or peers that can use it */ phaseOne( &high, dir ); phaseOne( &normal, dir ); phaseOne( &low, dir ); /* Second phase of IO. To help us scale in high bandwidth situations, * enable on-demand IO for peers with bandwidth left to burn. * This on-demand IO is enabled until (1) the peer runs out of bandwidth, * or (2) the next tr_bandwidthAllocate() call, when we start over again. */ for( i=0; i<peerCount; ++i ) tr_peerIoSetEnabled( peers[i], dir, tr_peerIoHasBandwidthLeft( peers[i], dir ) ); for( i=0; i<peerCount; ++i ) tr_peerIoUnref( peers[i] ); /* cleanup */ tr_ptrArrayDestruct( &normal, NULL ); tr_ptrArrayDestruct( &high, NULL ); tr_ptrArrayDestruct( &low, NULL ); tr_ptrArrayDestruct( &tmp, NULL ); }
void tr_cacheFree (tr_cache * cache) { assert (tr_ptrArrayEmpty (&cache->blocks)); tr_ptrArrayDestruct (&cache->blocks, NULL); tr_free (cache); }
static void tr_watchdir_kqueue_free (tr_watchdir_backend * backend_base) { tr_watchdir_kqueue * const backend = BACKEND_UPCAST (backend_base); if (backend == NULL) return; assert (backend->base.free_func == &tr_watchdir_kqueue_free); if (backend->event != NULL) { event_del (backend->event); event_free (backend->event); } if (backend->kq != -1) close (backend->kq); if (backend->dirfd != -1) close (backend->dirfd); tr_ptrArrayDestruct (&backend->dir_entries, &tr_free); tr_free (backend); }
static void web_free( tr_web * g ) { evdns_shutdown( TRUE ); curl_multi_cleanup( g->multi ); evtimer_del( &g->timer_event ); tr_ptrArrayDestruct( &g->dns_cache, (PtrArrayForeachFunc)dns_cache_item_free ); memset( g, TR_MEMORY_TRASH, sizeof( struct tr_web ) ); tr_free( g ); }
void tr_bandwidthDestruct (tr_bandwidth * b) { assert (tr_isBandwidth (b)); tr_bandwidthSetParent (b, NULL); tr_ptrArrayDestruct (&b->children, NULL); memset (b, ~0, sizeof (tr_bandwidth)); }
int tr_jsonParse( const void * vbuf, size_t len, tr_benc * setme_benc, const uint8_t ** setme_end ) { int line = 1; int column = 1; int err = 0; const unsigned char * buf = vbuf; const void * bufend = buf + len; struct JSON_config_struct config; struct JSON_parser_struct * checker; struct json_benc_data data; init_JSON_config( &config ); config.callback = callback; config.callback_ctx = &data; config.depth = -1; data.hasContent = FALSE; data.key = NULL; data.top = setme_benc; data.stack = TR_PTR_ARRAY_INIT; checker = new_JSON_parser( &config ); while( ( buf != bufend ) && JSON_parser_char( checker, *buf ) ) { if( *buf != '\n' ) ++column; else { ++line; column = 1; } ++buf; } if( buf != bufend ) { tr_err( "JSON parser failed at line %d, column %d: \"%.16s\"", line, column, buf ); err = EILSEQ; } if( !data.hasContent ) err = EINVAL; if( setme_end ) *setme_end = (const uint8_t*) buf; delete_JSON_parser( checker ); tr_ptrArrayDestruct( &data.stack, NULL ); return err; }
/** * This function's previous recursive implementation was * easier to read, but was vulnerable to a smash-stacking * attack via maliciously-crafted bencoded data. (#667) */ int tr_variantParseBenc (const void * buf_in, const void * bufend_in, tr_variant * top, const char ** setme_end) { int err = 0; const uint8_t * buf = buf_in; const uint8_t * bufend = bufend_in; tr_ptrArray stack = TR_PTR_ARRAY_INIT; tr_quark key = 0; tr_variantInit (top, 0); while (buf != bufend) { if (buf > bufend) /* no more text to parse... */ err = EILSEQ; if (err) break; if (*buf == 'i') /* int */ { int64_t val; const uint8_t * end; tr_variant * v; if ((err = tr_bencParseInt (buf, bufend, &end, &val))) break; buf = end; if ((v = get_node (&stack, &key, top, &err))) tr_variantInitInt (v, val); } else if (*buf == 'l') /* list */ { tr_variant * v; ++buf; if ((v = get_node (&stack, &key, top, &err))) { tr_variantInitList (v, 0); tr_ptrArrayAppend (&stack, v); } } else if (*buf == 'd') /* dict */ { tr_variant * v; ++buf; if ((v = get_node (&stack, &key, top, &err))) { tr_variantInitDict (v, 0); tr_ptrArrayAppend (&stack, v); } } else if (*buf == 'e') /* end of list or dict */ { ++buf; if (tr_ptrArrayEmpty (&stack) || (key != 0)) { err = EILSEQ; break; } else { tr_ptrArrayPop (&stack); if (tr_ptrArrayEmpty (&stack)) break; } } else if (isdigit (*buf)) /* string? */ { tr_variant * v; const uint8_t * end; const uint8_t * str; size_t str_len; if ((err = tr_bencParseStr (buf, bufend, &end, &str, &str_len))) break; buf = end; if (!key && !tr_ptrArrayEmpty(&stack) && tr_variantIsDict(tr_ptrArrayBack(&stack))) key = tr_quark_new (str, str_len); else if ((v = get_node (&stack, &key, top, &err))) tr_variantInitStr (v, str, str_len); } else /* invalid bencoded text... march past it */ { ++buf; } if (tr_ptrArrayEmpty (&stack)) break; } if (!err && (!top->type || !tr_ptrArrayEmpty(&stack))) err = EILSEQ; if (!err && setme_end) *setme_end = (const char*) buf; tr_ptrArrayDestruct (&stack, NULL); return err; }
static void handle_upload (struct evhttp_request * req, struct tr_rpc_server * server) { if (req->type != EVHTTP_REQ_POST) { send_simple_response (req, 405, NULL); } else { int i; int n; bool hasSessionId = false; tr_ptrArray parts = TR_PTR_ARRAY_INIT; const char * query = strchr (req->uri, '?'); const bool paused = query && strstr (query + 1, "paused=true"); extract_parts_from_multipart (req->input_headers, req->input_buffer, &parts); n = tr_ptrArraySize (&parts); /* first look for the session id */ for (i=0; i<n; ++i) { struct tr_mimepart * p = tr_ptrArrayNth (&parts, i); if (tr_memmem (p->headers, p->headers_len, TR_RPC_SESSION_ID_HEADER, strlen (TR_RPC_SESSION_ID_HEADER))) break; } if (i<n) { const struct tr_mimepart * p = tr_ptrArrayNth (&parts, i); const char * ours = get_current_session_id (server); const size_t ourlen = strlen (ours); hasSessionId = ourlen <= p->body_len && memcmp (p->body, ours, ourlen) == 0; } if (!hasSessionId) { int code = 409; const char * codetext = tr_webGetResponseStr (code); struct evbuffer * body = evbuffer_new (); evbuffer_add_printf (body, "%s", "{ \"success\": false, \"msg\": \"Bad Session-Id\" }");; evhttp_send_reply (req, code, codetext, body); evbuffer_free (body); } else for (i=0; i<n; ++i) { struct tr_mimepart * p = tr_ptrArrayNth (&parts, i); size_t body_len = p->body_len; tr_variant top, *args; tr_variant test; bool have_source = false; char * body = p->body; if (body_len >= 2 && memcmp (&body[body_len - 2], "\r\n", 2) == 0) body_len -= 2; tr_variantInitDict (&top, 2); tr_variantDictAddStr (&top, TR_KEY_method, "torrent-add"); args = tr_variantDictAddDict (&top, TR_KEY_arguments, 2); tr_variantDictAddBool (args, TR_KEY_paused, paused); if (tr_urlIsValid (body, body_len)) { tr_variantDictAddRaw (args, TR_KEY_filename, body, body_len); have_source = true; } else if (!tr_variantFromBenc (&test, body, body_len)) { char * b64 = tr_base64_encode (body, body_len, NULL); tr_variantDictAddStr (args, TR_KEY_metainfo, b64); tr_free (b64); have_source = true; } if (have_source) tr_rpc_request_exec_json (server->session, &top, NULL, NULL); tr_variantFree (&top); } tr_ptrArrayDestruct (&parts, (PtrArrayForeachFunc)tr_mimepart_free); /* send "success" response */ { int code = HTTP_OK; const char * codetext = tr_webGetResponseStr (code); struct evbuffer * body = evbuffer_new (); evbuffer_add_printf (body, "%s", "{ \"success\": true, \"msg\": \"Torrent Added\" }");; evhttp_send_reply (req, code, codetext, body); evbuffer_free (body); } } }