Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
diff src/gt_xfer_obj.c @ 0:d39e1d0d75b6
initial add
author | paulo@hit-nxdomain.opendns.com |
---|---|
date | Sat, 20 Feb 2010 21:18:28 -0800 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/gt_xfer_obj.c Sat Feb 20 21:18:28 2010 -0800 1.3 @@ -0,0 +1,867 @@ 1.4 +/* 1.5 + * $Id: gt_xfer_obj.c,v 1.48 2004/12/19 12:38:42 mkern Exp $ 1.6 + * 1.7 + * acts as a gateway between giFT and the HTTP implementation 1.8 + * 1.9 + * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) 1.10 + * 1.11 + * This program is free software; you can redistribute it and/or modify it 1.12 + * under the terms of the GNU General Public License as published by the 1.13 + * Free Software Foundation; either version 2, or (at your option) any 1.14 + * later version. 1.15 + * 1.16 + * This program is distributed in the hope that it will be useful, but 1.17 + * WITHOUT ANY WARRANTY; without even the implied warranty of 1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.19 + * General Public License for more details. 1.20 + */ 1.21 + 1.22 +#include "gt_gnutella.h" 1.23 + 1.24 +#include "gt_xfer_obj.h" 1.25 +#include "gt_xfer.h" 1.26 +#include "gt_http_server.h" 1.27 +#include "gt_http_client.h" 1.28 +#include "gt_share.h" 1.29 + 1.30 +#include "encoding/url.h" 1.31 + 1.32 +#include "transfer/source.h" 1.33 + 1.34 +/*****************************************************************************/ 1.35 + 1.36 +static List *upload_connections = NULL; 1.37 +static List *download_connections = NULL; 1.38 + 1.39 +/*****************************************************************************/ 1.40 +/* HTTP COMMUNICATION */ 1.41 + 1.42 +static BOOL header_read_timeout (GtTransfer *xfer) 1.43 +{ 1.44 + gt_transfer_status (xfer, SOURCE_TIMEOUT, "Timed out"); 1.45 + gt_transfer_close (xfer, TRUE); 1.46 + return FALSE; 1.47 +} 1.48 + 1.49 +GtTransfer *gt_transfer_new (GtTransferType type, Source *source, 1.50 + in_addr_t ip, in_port_t port, 1.51 + off_t start, off_t stop) 1.52 +{ 1.53 + GtTransfer *xfer; 1.54 + GtTransferCB cb; 1.55 + 1.56 + if (!(xfer = malloc (sizeof (GtTransfer)))) 1.57 + return NULL; 1.58 + 1.59 + memset (xfer, 0, sizeof (GtTransfer)); 1.60 + 1.61 + if (type == GT_TRANSFER_UPLOAD) 1.62 + cb = gt_upload; 1.63 + else if (type == GT_TRANSFER_DOWNLOAD) 1.64 + cb = gt_download; 1.65 + else 1.66 + abort (); 1.67 + 1.68 + xfer->type = type; 1.69 + xfer->callback = cb; 1.70 + xfer->source = source; 1.71 + 1.72 + /* parsed information about the source */ 1.73 + xfer->ip = ip; 1.74 + xfer->port = port; 1.75 + 1.76 + xfer->start = start; 1.77 + xfer->stop = stop; 1.78 + 1.79 + xfer->shared = TRUE; 1.80 + 1.81 + xfer->detach_timer = TIMER_NONE; 1.82 + xfer->detach_msgtxt = NULL; 1.83 + 1.84 + /* set the size of this http request */ 1.85 + xfer->remaining_len = xfer->stop - xfer->start; 1.86 + 1.87 + /* give this GtTransfer a maximum amount of time before cancelling */ 1.88 + xfer->header_timer = timer_add (1 * MINUTES, 1.89 + (TimerCallback)header_read_timeout, 1.90 + xfer); 1.91 + 1.92 + return xfer; 1.93 +} 1.94 + 1.95 +static void gt_transfer_free (GtTransfer *xfer) 1.96 +{ 1.97 + if (!xfer) 1.98 + return; 1.99 + 1.100 + free (xfer->command); 1.101 + free (xfer->request); 1.102 + free (xfer->request_path); 1.103 + free (xfer->content_urns); 1.104 + free (xfer->detach_msgtxt); 1.105 + 1.106 + if (xfer->header) 1.107 + dataset_clear (xfer->header); 1.108 + 1.109 +#if 0 1.110 + if (xfer->share_authd && xfer->shared_authd_free) 1.111 + share_free (xfer->share_authd); 1.112 +#endif 1.113 + 1.114 + timer_remove (xfer->detach_timer); 1.115 + timer_remove (xfer->header_timer); 1.116 + 1.117 + /* uploads use these */ 1.118 + free (xfer->open_path); 1.119 + free (xfer->hash); 1.120 + free (xfer->version); 1.121 + 1.122 + if (xfer->f) 1.123 + fclose (xfer->f); 1.124 + 1.125 + /* whee */ 1.126 + free (xfer); 1.127 +} 1.128 + 1.129 +/*****************************************************************************/ 1.130 + 1.131 +void gt_transfer_set_tcpc (GtTransfer *xfer, TCPC *c) 1.132 +{ 1.133 + assert (c->udata == NULL); 1.134 + assert (xfer->c == NULL); 1.135 + 1.136 + c->udata = xfer; 1.137 + xfer->c = c; 1.138 +} 1.139 + 1.140 +void gt_transfer_set_chunk (GtTransfer *xfer, Chunk *chunk) 1.141 +{ 1.142 + assert (chunk->udata == NULL); 1.143 + assert (xfer->chunk == NULL); 1.144 + 1.145 + xfer->chunk = chunk; 1.146 + chunk->udata = xfer; 1.147 +} 1.148 + 1.149 +Chunk *gt_transfer_get_chunk (GtTransfer *xfer) 1.150 +{ 1.151 + assert (xfer->chunk != NULL); 1.152 + assert (xfer->chunk->udata == xfer); 1.153 + 1.154 + return xfer->chunk; 1.155 +} 1.156 + 1.157 +TCPC *gt_transfer_get_tcpc (GtTransfer *xfer) 1.158 +{ 1.159 + assert (xfer->c != NULL); 1.160 + assert (xfer->c->udata == xfer); 1.161 + 1.162 + return xfer->c; 1.163 +} 1.164 + 1.165 +/*****************************************************************************/ 1.166 + 1.167 +GtSource *gt_transfer_get_source (GtTransfer *xfer) 1.168 +{ 1.169 + Source *source = xfer->source; 1.170 + 1.171 + /* could be null for uploads */ 1.172 + if (!source) 1.173 + return NULL; 1.174 + 1.175 + assert (source->udata != NULL); 1.176 + return source->udata; 1.177 +} 1.178 + 1.179 +/*****************************************************************************/ 1.180 + 1.181 +/* 1.182 + * giftd may change the Chunk size. This routine will reset the range of the 1.183 + * transfer we'll ask the remote end for. It should be called before we've 1.184 + * transmitted the HTTP headers that include the Range: request. 1.185 + */ 1.186 +void gt_transfer_set_length (GtTransfer *xfer, Chunk *chunk) 1.187 +{ 1.188 + TCPC *c; 1.189 + off_t old_start; 1.190 + off_t old_stop; 1.191 + off_t old_len; 1.192 + 1.193 + c = gt_transfer_get_tcpc (xfer); 1.194 + 1.195 + /* don't call me if you've already transmitted headers */ 1.196 + assert (!xfer->transmitted_hdrs); 1.197 + 1.198 + old_start = xfer->start; 1.199 + old_stop = xfer->stop; 1.200 + old_len = xfer->remaining_len; 1.201 + 1.202 + xfer->start = chunk->start + chunk->transmit; 1.203 + xfer->stop = chunk->stop; 1.204 + 1.205 + xfer->remaining_len = xfer->stop - xfer->start; 1.206 + 1.207 + /* i believe this is true even for push downloads... */ 1.208 + assert (xfer->start == old_start); 1.209 + 1.210 + if (xfer->stop != old_stop) 1.211 + { 1.212 + assert (xfer->remaining_len != old_len); 1.213 + 1.214 + GT->DBGSOCK (GT, c, "(%s) old chunk range: [%lu,%lu) " 1.215 + "new range: [%lu,%lu) old len: %lu new len: %lu", 1.216 + xfer->request, (long)old_start,(long)old_stop, 1.217 + (long)xfer->start, (long)xfer->stop, 1.218 + (long)old_len, (long)xfer->remaining_len); 1.219 + } 1.220 +} 1.221 + 1.222 +/*****************************************************************************/ 1.223 + 1.224 +/* 1.225 + * Cancels a possibly active HTTP transfer 1.226 + * 1.227 + * NOTE: 1.228 + * This function may be called recursively if you don't do what giFT expects 1.229 + * of you. This is a feature, not a bug, trust me. 1.230 + */ 1.231 +static void gt_transfer_cancel (Chunk *chunk, TransferType type) 1.232 +{ 1.233 + GtTransfer *xfer; 1.234 + BOOL force_close = FALSE; 1.235 + 1.236 + if (!chunk) 1.237 + return; 1.238 + 1.239 + xfer = chunk->udata; 1.240 + 1.241 + /* each time this function is called we _MUST_ uncouple the transfer 1.242 + * and the chunk or the code to follow will eventually call this func 1.243 + * again!! */ 1.244 + if (!xfer) 1.245 + return; 1.246 + 1.247 + /* do not emit a callback signal */ 1.248 + xfer->callback = NULL; 1.249 + gt_transfer_close (xfer, force_close); 1.250 +} 1.251 + 1.252 +/*****************************************************************************/ 1.253 + 1.254 +static void close_http_connection (TCPC *c, BOOL force_close, 1.255 + GtTransferType type, GtSource *gt_src) 1.256 +{ 1.257 + if (!c) 1.258 + return; 1.259 + 1.260 + /* 1.261 + * If this is an incoming indirect download that we sent a push out 1.262 + * for, then don't store the connection in the HTTP connection cache, 1.263 + * store it in the separate push connection cache that uses the client 1.264 + * id as well as the IP address to identify the node. 1.265 + */ 1.266 + if (!force_close && type == GT_TRANSFER_DOWNLOAD && !c->outgoing) 1.267 + { 1.268 + if (gt_src != NULL) 1.269 + { 1.270 + if (HTTP_DEBUG) 1.271 + GT->DBGSOCK (GT, c, "Keeping push connection"); 1.272 + 1.273 + /* nullify the previous data on this connection */ 1.274 + c->udata = NULL; 1.275 + 1.276 + gt_push_source_add_conn (gt_src->guid, gt_src->user_ip, c); 1.277 + return; 1.278 + } 1.279 + 1.280 + /* 1.281 + * This could happen if the chunk has no source url to parse 1.282 + * at the moment. Argh, GtTransfer should always have a GtSource 1.283 + * if xfer->type == GT_TRANSFER_DOWNLOAD. 1.284 + */ 1.285 + if (HTTP_DEBUG) 1.286 + GT->DBGSOCK (GT, c, "Closing pushed connection! ARGH!"); 1.287 + 1.288 + force_close = TRUE; 1.289 + } 1.290 + 1.291 + gt_http_connection_close (type, c, force_close); 1.292 +} 1.293 + 1.294 +/* 1.295 + * This function is very critical to OpenFT's transfer system. It is called 1.296 + * anytime either the client or server HTTP implementations need to "cleanup" 1.297 + * all data associated. This includes disconnecting the socket, unlinking 1.298 + * itself from the chunk system and registering this status with giFT, just 1.299 + * in case this is premature. If anything is leaking or fucking up, blame 1.300 + * this :) 1.301 + */ 1.302 +void gt_transfer_close (GtTransfer *xfer, BOOL force_close) 1.303 +{ 1.304 + TCPC *c; 1.305 + Chunk *chunk; 1.306 + GtSource *gt_src = NULL; 1.307 + char *conn_hdr; 1.308 + 1.309 + if (!xfer) 1.310 + return; 1.311 + 1.312 + c = xfer->c; 1.313 + chunk = xfer->chunk; 1.314 + 1.315 + assert (xfer != NULL); 1.316 + 1.317 + /* remove the xfer from the indirect src list */ 1.318 + gt_push_source_remove_xfer (xfer); 1.319 + 1.320 + /* get this source if this was a download */ 1.321 + if (xfer->type == GT_TRANSFER_DOWNLOAD && chunk && chunk->source) 1.322 + gt_src = gt_source_unserialize (chunk->source->url); 1.323 + 1.324 + /* if we have associated a chunk with this transfer we need to make sure 1.325 + * we remove cleanly detach */ 1.326 + if (chunk) 1.327 + { 1.328 + chunk->udata = NULL; 1.329 + 1.330 + /* 1.331 + * notify the transfer callback that we have terminated this 1.332 + * connection. let giFT handle the rest 1.333 + * 1.334 + * NOTE: 1.335 + * see gt_transfer_cancel for some warnings about this code 1.336 + */ 1.337 + if (xfer->callback) 1.338 + (*xfer->callback) (chunk, NULL, 0); 1.339 + 1.340 + /* WARNING: chunk is free'd in the depths of xfer->callback! */ 1.341 + } 1.342 + 1.343 + /* HTTP/1.0 does not support persist connections or something...i dunno */ 1.344 + if (!STRCASECMP (xfer->version, "HTTP/1.0")) 1.345 + force_close = TRUE; 1.346 + 1.347 + /* older gnutella clients send a plain "HTTP" version, that is 1.348 + * not persistent */ 1.349 + if (!STRCASECMP (xfer->version, "HTTP")) 1.350 + force_close = TRUE; 1.351 + 1.352 + /* 1.353 + * We must force a socket close if there is still data waiting to 1.354 + * be read on this transfer. 1.355 + */ 1.356 + if (!xfer->transmitted_hdrs || xfer->remaining_len != 0) 1.357 + force_close = TRUE; 1.358 + 1.359 + /* close the connection if "Connection: close" was supplied */ 1.360 + conn_hdr = dataset_lookupstr (xfer->header, "connection"); 1.361 + if (!STRCASECMP (conn_hdr, "close")) 1.362 + force_close = TRUE; 1.363 + 1.364 + close_http_connection (c, force_close, xfer->type, gt_src); 1.365 + 1.366 + gt_source_free (gt_src); 1.367 + 1.368 + gt_transfer_free (xfer); 1.369 +} 1.370 + 1.371 +void gt_transfer_status (GtTransfer *xfer, SourceStatus status, char *text) 1.372 +{ 1.373 + Chunk *chunk; 1.374 + GtSource *gt_src; 1.375 + char *next_status; 1.376 + 1.377 + if (!xfer || !text) 1.378 + return; 1.379 + 1.380 + /* Added this on 2004-12-19 to track observed assertion failure in 1.381 + * gt_transfer_get_chunk. -- mkern 1.382 + */ 1.383 + if (!xfer->chunk || xfer->chunk->udata != xfer) 1.384 + { 1.385 + GT->DBGFN (GT, "This is where we say good bye. status = %d, " 1.386 + "text = %s, xfer->request_path = %s, xfer->ip = %s", 1.387 + status, text, xfer->request_path, net_ip_str (xfer->ip)); 1.388 + } 1.389 + 1.390 + chunk = gt_transfer_get_chunk (xfer); 1.391 + 1.392 + GT->source_status (GT, chunk->source, status, text); 1.393 + 1.394 + /* 1.395 + * HACK: Store the status message on the GtSource, 1.396 + * so we can reuse it sometimes. 1.397 + */ 1.398 + if (!xfer->source || !(gt_src = xfer->source->udata)) 1.399 + return; 1.400 + 1.401 + /* allocate first so it's ok to call this function with an old value of 1.402 + * gt_src->status_txt */ 1.403 + next_status = STRDUP (text); 1.404 + free (gt_src->status_txt); 1.405 + gt_src->status_txt = next_status; 1.406 +} 1.407 + 1.408 +/*****************************************************************************/ 1.409 +/* PERSISTENT HTTP HANDLING */ 1.410 + 1.411 +struct conn_info 1.412 +{ 1.413 + in_addr_t ip; 1.414 + in_port_t port; 1.415 + size_t count; 1.416 +}; 1.417 + 1.418 +static int conn_cmp (TCPC *c, struct conn_info *info) 1.419 +{ 1.420 + if (info->port != c->port) 1.421 + return -1; 1.422 + 1.423 + if (net_peer (c->fd) != info->ip) 1.424 + return 1; 1.425 + 1.426 + return 0; 1.427 +} 1.428 + 1.429 +TCPC *gt_http_connection_lookup (GtTransferType type, in_addr_t ip, 1.430 + in_port_t port) 1.431 +{ 1.432 + List *link; 1.433 + List **connlist_ptr; 1.434 + TCPC *c = NULL; 1.435 + struct conn_info info; 1.436 + 1.437 + info.ip = ip; 1.438 + info.port = port; 1.439 + 1.440 + if (type == GT_TRANSFER_DOWNLOAD) 1.441 + connlist_ptr = &download_connections; 1.442 + else 1.443 + connlist_ptr = &upload_connections; 1.444 + 1.445 + link = list_find_custom (*connlist_ptr, &info, (CompareFunc)conn_cmp); 1.446 + 1.447 + if (link) 1.448 + { 1.449 + c = link->data; 1.450 + 1.451 + GT->DBGFN (GT, "using previous connection to %s:%hu", 1.452 + net_ip_str (ip), port); 1.453 + 1.454 + /* remove from the open list */ 1.455 + *connlist_ptr = list_remove_link (*connlist_ptr, link); 1.456 + input_remove_all (c->fd); 1.457 + } 1.458 + 1.459 + return c; 1.460 +} 1.461 + 1.462 +/* 1.463 + * Handles outgoing HTTP connections. This function is capable of 1.464 + * retrieving an already connected socket that was left over from a previous 1.465 + * transfer. 1.466 + */ 1.467 +TCPC *gt_http_connection_open (GtTransferType type, in_addr_t ip, 1.468 + in_port_t port) 1.469 +{ 1.470 + TCPC *c; 1.471 + 1.472 + if (!(c = gt_http_connection_lookup (type, ip, port))) 1.473 + c = tcp_open (ip, port, FALSE); 1.474 + 1.475 + return c; 1.476 +} 1.477 + 1.478 +static BOOL count_open (TCPC *c, struct conn_info *info) 1.479 +{ 1.480 + if (info->ip == net_peer (c->fd)) 1.481 + info->count++; 1.482 + 1.483 + return FALSE; 1.484 +} 1.485 + 1.486 +size_t gt_http_connection_length (GtTransferType type, in_addr_t ip) 1.487 +{ 1.488 + struct conn_info info; 1.489 + List *list; 1.490 + 1.491 + info.ip = ip; 1.492 + info.port = 0; 1.493 + info.count = 0; 1.494 + 1.495 + assert (type == GT_TRANSFER_DOWNLOAD || type == GT_TRANSFER_UPLOAD); 1.496 + list = (type == GT_TRANSFER_DOWNLOAD ? download_connections : 1.497 + upload_connections); 1.498 + 1.499 + list_foreach (list, (ListForeachFunc)count_open, &info); 1.500 + 1.501 + return info.count; 1.502 +} 1.503 + 1.504 +void gt_http_connection_close (GtTransferType type, TCPC *c, BOOL force_close) 1.505 +{ 1.506 + List **connlist_ptr; 1.507 + 1.508 + if (!c) 1.509 + return; 1.510 + 1.511 + switch (type) 1.512 + { 1.513 + case GT_TRANSFER_DOWNLOAD: 1.514 + { 1.515 + gt_http_client_reset (c); 1.516 + connlist_ptr = &download_connections; 1.517 + } 1.518 + break; 1.519 + 1.520 + case GT_TRANSFER_UPLOAD: 1.521 + { 1.522 + gt_http_server_reset (c); 1.523 + connlist_ptr = &upload_connections; 1.524 + } 1.525 + break; 1.526 + 1.527 + default: 1.528 + abort (); 1.529 + } 1.530 + 1.531 + if (force_close) 1.532 + { 1.533 + *connlist_ptr = list_remove (*connlist_ptr, c); 1.534 + 1.535 + if (HTTP_DEBUG) 1.536 + GT->DBGSOCK (GT, c, "force closing"); 1.537 + 1.538 + tcp_close (c); 1.539 + return; 1.540 + } 1.541 + 1.542 + /* remove the data associated with this connection */ 1.543 + c->udata = NULL; 1.544 + 1.545 + /* 1.546 + * This condition will happen because the server doesn't remove the 1.547 + * connection from the persistent list until the connection fails. 1.548 + */ 1.549 + if (list_find (*connlist_ptr, c)) 1.550 + { 1.551 + assert (type == GT_TRANSFER_UPLOAD); 1.552 + return; 1.553 + } 1.554 + 1.555 + /* track it */ 1.556 + *connlist_ptr = list_prepend (*connlist_ptr, c); 1.557 +} 1.558 + 1.559 +/*****************************************************************************/ 1.560 + 1.561 +static char *localize_request (GtTransfer *xfer, BOOL *authorized) 1.562 +{ 1.563 + char *open_path; 1.564 + char *s_path; 1.565 + int auth = FALSE; 1.566 + int need_free = FALSE; 1.567 + 1.568 + if (!xfer || !xfer->request) 1.569 + return NULL; 1.570 + 1.571 + /* dont call secure_path if they dont even care if it's a secure 1.572 + * lookup */ 1.573 + s_path = 1.574 + (authorized ? file_secure_path (xfer->request) : xfer->request); 1.575 + 1.576 + if (authorized) 1.577 + need_free = TRUE; 1.578 + 1.579 + open_path = gt_localize_request (xfer, s_path, &auth); 1.580 + 1.581 + if (need_free || !open_path) 1.582 + free (s_path); 1.583 + 1.584 + if (authorized) 1.585 + *authorized = auth; 1.586 + 1.587 + /* we need a unix style path for authorization */ 1.588 + return open_path; 1.589 +} 1.590 + 1.591 +/* 1.592 + * request is expected in the form: 1.593 + * /shared/Fuck%20Me%20Hard.mpg 1.594 + */ 1.595 +BOOL gt_transfer_set_request (GtTransfer *xfer, char *request) 1.596 +{ 1.597 +#if 0 1.598 + FileShare *file; 1.599 + char *shared_path; 1.600 +#endif 1.601 + 1.602 + free (xfer->request); 1.603 + xfer->request = NULL; 1.604 + 1.605 + /* lets keep this sane shall we */ 1.606 + if (!request || *request != '/') 1.607 + return FALSE; 1.608 + 1.609 + xfer->request = STRDUP (request); 1.610 + xfer->request_path = gt_url_decode (request); /* storing here for opt */ 1.611 + 1.612 + return TRUE; 1.613 +} 1.614 + 1.615 +/* attempts to open the requested file locally. 1.616 + * NOTE: this handles verification */ 1.617 +FILE *gt_transfer_open_request (GtTransfer *xfer, int *code) 1.618 +{ 1.619 + FILE *f; 1.620 + char *shared_path; 1.621 + char *full_path = NULL; 1.622 + char *host_path; 1.623 + int auth = FALSE; 1.624 + int code_l = 200; 1.625 + 1.626 + if (code) 1.627 + *code = 404; /* Not Found */ 1.628 + 1.629 + if (!xfer || !xfer->request) 1.630 + return NULL; 1.631 + 1.632 + if (!(shared_path = localize_request (xfer, &auth))) 1.633 + { 1.634 + /* 1.635 + * If we havent finished syncing shares, that may be why the 1.636 + * request failed. If so, return 503 here. 1.637 + */ 1.638 + if (!gt_share_local_sync_is_done () && code != NULL) 1.639 + *code = 503; 1.640 + 1.641 + return NULL; 1.642 + } 1.643 + 1.644 + /* needs more work for virtual requests */ 1.645 +#if 0 1.646 + /* check to see if we matched a special OpenFT condition. If we did, the 1.647 + * localized path is in the wrong order, so convert it (just to be 1.648 + * converted back again...it's easier to maintain this way :) */ 1.649 + if (auth) 1.650 + { 1.651 + xfer->shared = FALSE; 1.652 + full_path = file_unix_path (shared_path); 1.653 + } 1.654 + else 1.655 +#endif 1.656 + { 1.657 + Share *share; 1.658 + int reason = UPLOAD_AUTH_NOTSHARED; 1.659 + upload_auth_t cond; 1.660 + 1.661 + /* 1.662 + * NOTE: the user string is not consistent with the one 1.663 + * echoed through search results, which prefixes the IP 1.664 + * with the GUID, if this node is firewalled. 1.665 + */ 1.666 + if ((share = GT->share_lookup (GT, SHARE_LOOKUP_HPATH, shared_path))) 1.667 + reason = GT->upload_auth (GT, net_ip_str (xfer->ip), share, &cond); 1.668 + 1.669 + xfer->share_authd = share; 1.670 + 1.671 + switch (reason) 1.672 + { 1.673 + case UPLOAD_AUTH_STALE: 1.674 + code_l = 500; /* Internal Server Error */ 1.675 + break; 1.676 + case UPLOAD_AUTH_NOTSHARED: 1.677 + code_l = 404; /* Not Found */ 1.678 + break; 1.679 + case UPLOAD_AUTH_ALLOW: 1.680 + code_l = 200; /* OK */ 1.681 + xfer->open_path_size = share->size; 1.682 + xfer->content_type = share->mime; 1.683 + full_path = STRDUP (share->path); 1.684 + break; 1.685 + case UPLOAD_AUTH_MAX: 1.686 + case UPLOAD_AUTH_MAX_PERUSER: 1.687 + case UPLOAD_AUTH_HIDDEN: 1.688 + default: 1.689 + code_l = 503; /* Service Unavailable */ 1.690 + xfer->queue_pos = cond.queue_pos; 1.691 + xfer->queue_ttl = cond.queue_ttl; 1.692 + break; 1.693 + } 1.694 + } 1.695 + 1.696 + if (code) 1.697 + *code = code_l; 1.698 + 1.699 + /* error of some kind, get out of here */ 1.700 + if (code_l != 200) 1.701 + return NULL; 1.702 + 1.703 + /* figure out the actual filename that we should be opening */ 1.704 + host_path = file_host_path (full_path); 1.705 + free (full_path); 1.706 + 1.707 + /* needs more work for virtual requests */ 1.708 +#if 0 1.709 + /* complete the rest of the data required */ 1.710 + if (auth) 1.711 + { 1.712 + struct stat st; 1.713 + 1.714 + if (!file_stat (host_path, &st)) 1.715 + { 1.716 + free (host_path); 1.717 + return NULL; 1.718 + } 1.719 + 1.720 + xfer->open_path_size = st.st_size; 1.721 + xfer->content_type = mime_type (host_path); 1.722 + } 1.723 +#endif 1.724 + 1.725 + if (!(f = fopen (host_path, "rb"))) 1.726 + { 1.727 + *code = 500; 1.728 + return NULL; 1.729 + } 1.730 + 1.731 + /* NOTE: gt_transfer_close will be responsible for freeing this now */ 1.732 + xfer->open_path = host_path; 1.733 + 1.734 + if (code) 1.735 + *code = 200; /* OK */ 1.736 + 1.737 + return f; 1.738 +} 1.739 + 1.740 +/*****************************************************************************/ 1.741 + 1.742 +/* 1.743 + * The callbacks here are from within the HTTP system, centralized for 1.744 + * maintainability. 1.745 + */ 1.746 + 1.747 +/* report back the progress of this download chunk */ 1.748 +void gt_download (Chunk *chunk, unsigned char *segment, size_t len) 1.749 +{ 1.750 + GT->chunk_write (GT, chunk->transfer, chunk, chunk->source, 1.751 + segment, len); 1.752 +} 1.753 + 1.754 +/* report back the progress of this upload chunk */ 1.755 +void gt_upload (Chunk *chunk, unsigned char *segment, size_t len) 1.756 +{ 1.757 + GT->chunk_write (GT, chunk->transfer, chunk, chunk->source, 1.758 + segment, len); 1.759 +} 1.760 + 1.761 +void gt_transfer_write (GtTransfer *xfer, Chunk *chunk, 1.762 + unsigned char *segment, size_t len) 1.763 +{ 1.764 + /* 1.765 + * Cap the data at the remaining size of the xfer. Note that this is 1.766 + * the size of the HTTP request issued, _NOT_ the chunk size, which may 1.767 + * have been altered by giFT in splitting up chunks. I think giFT 1.768 + * handles that case properly, but we also have to guard against 1.769 + * remaining_len becoming less than 0. Note that p->chunk_write 1.770 + * will cancel the transfer if remaining_len goes to 0. 1.771 + * 1.772 + * TODO: remaining_len is off_t, make sure this is handled right wrt 1.773 + * negative file sizes (do big files become negative sizes?) 1.774 + */ 1.775 + if (len > xfer->remaining_len) 1.776 + len = xfer->remaining_len; 1.777 + 1.778 + xfer->remaining_len -= len; 1.779 + (*xfer->callback) (chunk, segment, len); 1.780 +} 1.781 + 1.782 +/*****************************************************************************/ 1.783 + 1.784 +static BOOL throttle_suspend (Chunk *chunk, int s_opt, float factor) 1.785 +{ 1.786 + GtTransfer *xfer; 1.787 + 1.788 + if (!chunk) 1.789 + return FALSE; 1.790 + 1.791 + xfer = chunk->udata; 1.792 + 1.793 + if (!xfer || !xfer->c) 1.794 + { 1.795 + GT->DBGFN (GT, "no connection found to suspend"); 1.796 + return FALSE; 1.797 + } 1.798 + 1.799 + input_suspend_all (xfer->c->fd); 1.800 + 1.801 + if (factor) 1.802 + net_sock_adj_buf (xfer->c->fd, s_opt, factor); 1.803 + 1.804 + return TRUE; 1.805 +} 1.806 + 1.807 +static BOOL throttle_resume (Chunk *chunk, int s_opt, float factor) 1.808 +{ 1.809 + GtTransfer *xfer = NULL; 1.810 + 1.811 + if (!chunk) 1.812 + return FALSE; 1.813 + 1.814 + xfer = chunk->udata; 1.815 + 1.816 + if (!xfer || !xfer->c) 1.817 + { 1.818 + GT->DBGFN (GT, "no connection found to resume"); 1.819 + return FALSE; 1.820 + } 1.821 + 1.822 + input_resume_all (xfer->c->fd); 1.823 + 1.824 +#if 0 1.825 + if (factor) 1.826 + net_sock_adj_buf (xfer->c->fd, s_opt, factor); 1.827 +#endif 1.828 + 1.829 + return TRUE; 1.830 +} 1.831 + 1.832 +/*****************************************************************************/ 1.833 + 1.834 +void gt_download_cancel (Chunk *chunk, void *data) 1.835 +{ 1.836 + gt_transfer_cancel (chunk, TRANSFER_DOWNLOAD); 1.837 +} 1.838 + 1.839 +/* cancel the transfer associate with the chunk giFT gave us */ 1.840 +void gt_upload_cancel (Chunk *chunk, void *data) 1.841 +{ 1.842 + gt_transfer_cancel (chunk, TRANSFER_UPLOAD); 1.843 +} 1.844 + 1.845 +static int throttle_sopt (Transfer *transfer) 1.846 +{ 1.847 + int sopt = 0; 1.848 + 1.849 + switch (transfer_direction (transfer)) 1.850 + { 1.851 + case TRANSFER_DOWNLOAD: 1.852 + sopt = SO_RCVBUF; 1.853 + break; 1.854 + case TRANSFER_UPLOAD: 1.855 + sopt = SO_SNDBUF; 1.856 + break; 1.857 + } 1.858 + 1.859 + return sopt; 1.860 +} 1.861 + 1.862 +BOOL gt_chunk_suspend (Chunk *chunk, Transfer *transfer, void *data) 1.863 +{ 1.864 + return throttle_suspend (chunk, throttle_sopt (transfer), 0.0); 1.865 +} 1.866 + 1.867 +BOOL gt_chunk_resume (Chunk *chunk, Transfer *transfer, void *data) 1.868 +{ 1.869 + return throttle_resume (chunk, throttle_sopt (transfer), 0.0); 1.870 +}