diff --git a/rhizome.h b/rhizome.h index 698951ee..6bbe352d 100644 --- a/rhizome.h +++ b/rhizome.h @@ -511,3 +511,8 @@ extern unsigned char favicon_bytes[]; extern int favicon_len; int rhizome_import_from_files(const char *manifestpath,const char *filepath); +int rhizome_fetch_request_manifest_by_prefix(struct sockaddr_in *peerip, + unsigned char *prefix, + int prefix_length, + int importP); +extern int rhizome_file_fetch_queue_count; diff --git a/rhizome_direct_http.c b/rhizome_direct_http.c index ff48f1e5..342cdd84 100644 --- a/rhizome_direct_http.c +++ b/rhizome_direct_http.c @@ -508,9 +508,9 @@ int rhizome_direct_parse_http_request(rhizome_http_request *r) r->request_length = 0; r->source_flags = 0; - /* Find the end of the headers and start of any body bytes that we have read so far. - Copy the bytes to a separate buffer, because r->request and r->request_length get used - internally in the parser. + /* Find the end of the headers and start of any body bytes that we have read + so far. Copy the bytes to a separate buffer, because r->request and + r->request_length get used internally in the parser. */ if (contentlen) { char buffer[contentlen]; @@ -736,10 +736,25 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r) if (type==2&&r->pullP) { WARN("XXX Rhizome direct http pull yet implemented"); /* Need to fetch manifest. Once we have the manifest, then we can - use our normal bundle fetch routines from rhizome_fetch.c + use our normal bundle fetch routines from rhizome_fetch.c + + Generate a request like: GET /rhizome/manifestbybar/ + and add it to our list of HTTP fetch requests, then watch + until the request is finished. That will give us the manifest. + Then as noted above, we can use that to pull the file down using + existing routines. */ + if (!rhizome_fetch_request_manifest_by_prefix + (&addr,(unsigned char *)&p[i+1],RHIZOME_BAR_PREFIX_BYTES, + 1 /* import, getting file if needed */)) + { + /* Fetching the manifest, and then using it to see if we want to + fetch the file for import is all handled asynchronously, so just + wait for it to finish. */ + while(rhizome_file_fetch_queue_count) fd_poll(); + } + } else if (type==1&&r->pushP) { - WARN("XXX rhizome direct http push not implemented"); /* Form up the POST request to submit the appropriate bundle. */ /* Start by getting the manifest, which is the main thing we need, and also diff --git a/rhizome_fetch.c b/rhizome_fetch.c index 10b01649..96bbcf81 100644 --- a/rhizome_fetch.c +++ b/rhizome_fetch.c @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include +#include #include "serval.h" #include "rhizome.h" @@ -782,9 +783,15 @@ void rhizome_write_content(rhizome_file_fetch_record *q, char *buffer, int bytes DEBUGF("Received all of file via rhizome -- now to import it"); fclose(q->file); q->file = NULL; - rhizome_import_received_bundle(q->manifest); - rhizome_manifest_free(q->manifest); - q->manifest = NULL; + if (q->manifest) { + rhizome_import_received_bundle(q->manifest); + rhizome_manifest_free(q->manifest); + q->manifest = NULL; + } else { + /* This was to fetch the manifest, so now fetch the file if needed */ + DEBUGF("Received a manifest in response to supplying a manifest prefix."); + DEBUGF("XXX Not implemented scheduling the fetching of the file itself."); + } rhizome_fetch_close(q); return; } @@ -937,3 +944,91 @@ void rhizome_fetch_poll(struct sched_ent *alarm) } return; } + +int rhizome_fetch_request_manifest_by_prefix(struct sockaddr_in *peerip, + unsigned char *prefix, + int prefix_length, + int importP) +{ + assert(peerip); + /* Transfer via HTTP over IPv4 */ + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) + return WHY_perror("socket"); + if (set_nonblock(sock) == -1) { + close(sock); + return -1; + } + struct sockaddr_in addr = *peerip; + addr.sin_family = AF_INET; + INFOF("RHIZOME HTTP REQUEST, CONNECT family=%u port=%u addr=%u.%u.%u.%u", + addr.sin_family, ntohs(addr.sin_port), + ((unsigned char*)&addr.sin_addr.s_addr)[0], + ((unsigned char*)&addr.sin_addr.s_addr)[1], + ((unsigned char*)&addr.sin_addr.s_addr)[2], + ((unsigned char*)&addr.sin_addr.s_addr)[3] + ); + if (connect(sock, (struct sockaddr*)&addr, sizeof addr) == -1) { + if (errno == EINPROGRESS) { + if (debug & DEBUG_RHIZOME_RX) + DEBUGF("connect() returned EINPROGRESS"); + } else { + WHY_perror("connect"); + WHY("Failed to open socket to peer's rhizome web server"); + close(sock); + return -1; + } + } + rhizome_file_fetch_record *q=&file_fetch_queue[rhizome_file_fetch_queue_count]; + q->manifest = NULL; + q->alarm.poll.fd=sock; + bzero(q->fileid, sizeof(q->fileid)); + q->request_len = snprintf(q->request, sizeof q->request, "GET /rhizome/manifestbyprefix/%s HTTP/1.0\r\n\r\n", alloca_tohex(prefix,prefix_length)); + q->request_ofs=0; + q->state=RHIZOME_FETCH_CONNECTING; + q->file_len=-1; + q->file_ofs=0; + + /* XXX Don't forget to implement resume */ + /* XXX We should stream file straight into the database */ + const char *id = rhizome_manifest_get(q->manifest, "id", NULL, 0); + if (id == NULL) { + close(sock); + return WHY("Manifest missing ID"); + } + if (create_rhizome_import_dir() == -1) + return -1; + char filename[1024]; + if (!FORM_RHIZOME_IMPORT_PATH(filename, "file.%s", id)) { + close(sock); + return -1; + } + q->manifest->dataFileName = strdup(filename); + if ((q->file = fopen(q->manifest->dataFileName, "w")) == NULL) { + WHY_perror("fopen"); + if (debug & DEBUG_RHIZOME_RX) + DEBUGF("Could not open '%s' to write received file", q->manifest->dataFileName); + close(sock); + return -1; + } + + INFOF("RHIZOME HTTP REQUEST, GET \"/rhizome/file/%s\"", q->fileid); + + /* Watch for activity on the socket */ + q->alarm.function=rhizome_fetch_poll; + fetch_stats.name="rhizome_fetch_poll"; + q->alarm.stats=&fetch_stats; + q->alarm.poll.events=POLLIN|POLLOUT; + watch(&q->alarm); + /* And schedule a timeout alarm */ + q->alarm.alarm=gettime_ms() + RHIZOME_IDLE_TIMEOUT; + q->alarm.deadline = q->alarm.alarm + RHIZOME_IDLE_TIMEOUT; + + schedule(&q->alarm); + + rhizome_file_fetch_queue_count++; + if (debug & DEBUG_RHIZOME_RX) + DEBUGF("Queued file for fetching into %s (%d in queue)", + q->manifest->dataFileName, rhizome_file_fetch_queue_count); + return 0; +} diff --git a/rhizome_packetformats.c b/rhizome_packetformats.c index d60451b3..b7681c3b 100644 --- a/rhizome_packetformats.c +++ b/rhizome_packetformats.c @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "rhizome.h" #include #include +#include #include #include #include