/** * Create new message queue capable of holding `maxsize' bytes, and * owned by the supplied node. * * @param maxsize the overall sum of message size that can be held * @param n the network node to which the message queue is attached * @oaram nd the top of the TX stack to use to send out messages * @param uops user-defined operations */ mqueue_t * mq_udp_make(int maxsize, gnutella_node_t *n, struct txdriver *nd, const struct mq_uops *uops) { mqueue_t *q; node_check(n); tx_check(nd); g_assert(uops != NULL); g_assert(maxsize > 0); WALLOC0(q); q->magic = MQ_MAGIC; q->node = n; q->tx_drv = nd; q->maxsize = maxsize; q->lowat = maxsize >> 2; /* 25% of max size */ q->hiwat = maxsize >> 1; /* 50% of max size */ q->qwait = slist_new(); q->ops = &mq_udp_ops; q->cops = mq_get_cops(); q->uops = uops; q->debug = GNET_PROPERTY_PTR(mq_udp_debug); tx_srv_register(nd, mq_udp_service, q); return q; }
/** * Creates a new THEX upload context. The context must be freed with * thex_upload_close(). * * @param owner the owner of the TX stack (the upload) * @param host the host to which we're talking to * @param writable no document * @param link_cb callbacks for the link layer * @param wio no document * @param flags opening flags * * @return An initialized THEX upload context. */ struct special_upload * thex_upload_open( void *owner, const struct gnutella_host *host, const shared_file_t *sf, special_upload_writable_t writable, const struct tx_link_cb *link_cb, struct wrap_io *wio, int flags) { struct thex_upload *ctx; WALLOC(ctx); ctx->special_upload.read = thex_upload_read; ctx->special_upload.write = thex_upload_write; ctx->special_upload.flush = thex_upload_flush; ctx->special_upload.close = thex_upload_close; ctx->tth = atom_tth_get(shared_file_tth(sf)); ctx->filesize = shared_file_size(sf); ctx->data = NULL; ctx->size = 0; ctx->offset = 0; ctx->state = THEX_STATE_INITIAL; /* * Instantiate the TX stack. */ { struct tx_link_args args; args.cb = link_cb; args.wio = wio; args.bws = bsched_out_select_by_addr(gnet_host_get_addr(host)); ctx->tx = tx_make(owner, host, tx_link_get_ops(), &args); } if (flags & THEX_UPLOAD_F_CHUNKED) { ctx->tx = tx_make_above(ctx->tx, tx_chunk_get_ops(), 0); } /* * Put stack in "eager" mode: we want to be notified whenever * we can write something. */ tx_srv_register(ctx->tx, writable, owner); tx_eager_mode(ctx->tx, TRUE); /* * Update statistics. */ gnet_prop_incr_guint32(PROP_THEX_FILES_REQUESTED); return &ctx->special_upload; }
/** * Create new message queue capable of holding `maxsize' bytes, and * owned by the supplied node. */ mqueue_t * mq_udp_make(int maxsize, struct gnutella_node *n, struct txdriver *nd) { mqueue_t *q; WALLOC0(q); q->magic = MQ_MAGIC; q->node = n; q->tx_drv = nd; q->maxsize = maxsize; q->lowat = maxsize >> 2; /* 25% of max size */ q->hiwat = maxsize >> 1; /* 50% of max size */ q->qwait = slist_new(); q->ops = &mq_udp_ops; q->cops = mq_get_cops(); q->debug = GNET_PROPERTY_PTR(mq_udp_debug); tx_srv_register(nd, mq_udp_service, q); return q; }
/** * Creates a new browse host context. The context must be freed with * browse_host_close(). * * @param owner the owner of the TX stack (the upload) * @param host the host to which we're talking to * @param writable no document * @param deflate_cb callbacks for the deflate layer * @param link_cb callbacks for the link layer * @param wio no document * @param flags opening flags * * @return An initialized browse host context. */ struct special_upload * browse_host_open( void *owner, struct gnutella_host *host, special_upload_writable_t writable, const struct tx_deflate_cb *deflate_cb, const struct tx_link_cb *link_cb, struct wrap_io *wio, int flags) { struct browse_host_upload *bh; /* BH_HTML xor BH_QHITS set */ g_assert(flags & (BH_F_HTML|BH_F_QHITS)); g_assert((flags & (BH_F_HTML|BH_F_QHITS)) != (BH_F_HTML|BH_F_QHITS)); WALLOC(bh); bh->special.read = (flags & BH_F_HTML) ? browse_host_read_html : browse_host_read_qhits; bh->special.write = browse_host_write; bh->special.flush = browse_host_flush; bh->special.close = browse_host_close; browse_host_next_state(bh, BH_STATE_HEADER); bh->hits = NULL; bh->file_index = 0; bh->flags = flags; /* * Instantiate the TX stack. */ { struct tx_link_args args; args.cb = link_cb; args.wio = wio; args.bws = bsched_out_select_by_addr(gnet_host_get_addr(host)); bh->tx = tx_make(owner, host, tx_link_get_ops(), &args); } if (flags & BH_F_CHUNKED) { bh->tx = tx_make_above(bh->tx, tx_chunk_get_ops(), 0); } if (flags & (BH_F_DEFLATE | BH_F_GZIP)) { struct tx_deflate_args args; txdrv_t *tx; args.cq = cq_main(); args.cb = deflate_cb; args.nagle = FALSE; args.reduced = FALSE; args.gzip = 0 != (flags & BH_F_GZIP); args.buffer_flush = INT_MAX; /* Flush only at the end */ args.buffer_size = BH_BUFSIZ; tx = tx_make_above(bh->tx, tx_deflate_get_ops(), &args); if (tx == NULL) { tx_free(bh->tx); link_cb->eof_remove(owner, "Cannot setup compressing TX stack"); WFREE(bh); return NULL; } bh->tx = tx; } /* * Put stack in "eager" mode: we want to be notified whenever * we can write something. */ tx_srv_register(bh->tx, writable, owner); tx_eager_mode(bh->tx, TRUE); /* * Update statistics. */ if (flags & BH_F_HTML) { gnet_prop_incr_guint32(PROP_HTML_BROWSE_COUNT); } else if (flags & BH_F_QHITS) { gnet_prop_incr_guint32(PROP_QHITS_BROWSE_COUNT); } return &bh->special; }
/** * Initialize the driver. * * @return NULL if there is an initialization problem. */ static void * tx_deflate_init(txdrv_t *tx, void *args) { struct attr *attr; struct tx_deflate_args *targs = args; z_streamp outz; int ret; int i; g_assert(tx); g_assert(NULL != targs->cb); WALLOC(outz); outz->zalloc = zlib_alloc_func; outz->zfree = zlib_free_func; outz->opaque = NULL; /* * Reduce memory requirements for deflation when running as an ultrapeer. * * Memory used for deflation is: * * (1 << (window_bits +2)) + (1 << (mem_level + 9)) * * For leaves, we use window_bits = 15 and mem_level = 9, which makes * for 128 KiB + 256 KiB = 384 KiB per connection (TX side). * * For ultra peers, we use window_bits = 14 and mem_level = 6, so this * uses 64 KiB + 32 KiB = 96 KiB only. * * Since ultra peers have many more connections than leaves, the memory * savings are drastic, yet compression levels remain around 50% (varies * depending on the nature of the traffic, of course). * * --RAM, 2009-04-09 * * For Ultra <-> Ultra connections we use window_bits = 15 and mem_level = 9 * and request a best compression because the amount of ultra connections * is far less than the number of leaf connections and modern machines * can cope with a "best" compression overhead. * * This is now controlled with the "reduced" argument, so this layer does * not need to know whether we're an ultra node or even what an ultra * node is... It just knows whether we have to setup a fully compressed * connection or a reduced one (both in terms of memory usage and level * of compression). * * --RAM, 2011-11-29 */ { int window_bits = MAX_WBITS; /* Must be 8 .. MAX_WBITS */ int mem_level = MAX_MEM_LEVEL; /* Must be 1 .. MAX_MEM_LEVEL */ int level = Z_BEST_COMPRESSION; if (targs->reduced) { /* Ultra -> Leaf connection */ window_bits = 14; mem_level = 6; level = Z_DEFAULT_COMPRESSION; } g_assert(window_bits >= 8 && window_bits <= MAX_WBITS); g_assert(mem_level >= 1 && mem_level <= MAX_MEM_LEVEL); g_assert(level == Z_DEFAULT_COMPRESSION || (level >= Z_BEST_SPEED && level <= Z_BEST_COMPRESSION)); ret = deflateInit2(outz, level, Z_DEFLATED, targs->gzip ? (-window_bits) : window_bits, mem_level, Z_DEFAULT_STRATEGY); } if (Z_OK != ret) { g_warning("unable to initialize compressor for peer %s: %s", gnet_host_to_string(&tx->host), zlib_strerror(ret)); WFREE(outz); return NULL; } WALLOC0(attr); attr->cq = targs->cq; attr->cb = targs->cb; attr->buffer_size = targs->buffer_size; attr->buffer_flush = targs->buffer_flush; attr->nagle = booleanize(targs->nagle); attr->gzip.enabled = targs->gzip; attr->outz = outz; attr->tm_ev = NULL; for (i = 0; i < BUFFER_COUNT; i++) { struct buffer *b = &attr->buf[i]; b->arena = b->wptr = b->rptr = walloc(attr->buffer_size); b->end = &b->arena[attr->buffer_size]; } attr->fill_idx = 0; attr->send_idx = -1; /* Signals: none ready */ if (attr->gzip.enabled) { /* See RFC 1952 - GZIP file format specification version 4.3 */ static const unsigned char header[] = { 0x1f, 0x8b, /* gzip magic */ 0x08, /* compression method: deflate */ 0, /* flags: none */ 0, 0, 0, 0, /* modification time: unavailable */ 0, /* extra flags: none */ 0xff, /* filesystem: unknown */ }; struct buffer *b; b = &attr->buf[attr->fill_idx]; /* Buffer we fill */ g_assert(sizeof header <= (size_t) (b->end - b->wptr)); b->wptr = mempcpy(b->wptr, header, sizeof header); attr->gzip.crc = crc32(0, NULL, 0); attr->gzip.size = 0; } tx->opaque = attr; /* * Register our service routine to the lower layer. */ tx_srv_register(tx->lower, deflate_service, tx); return tx; /* OK */ }