size_t Net::Request::Read(void *_buffer, size_t buffer_size, unsigned long timeout) { assert(handle != NULL); const int timeout_ms = timeout == INFINITE ? -1 : timeout; Buffer::Range range; CURLMcode mcode = CURLM_CALL_MULTI_PERFORM; while (true) { range = buffer.Read(); if (!range.IsEmpty()) break; CURLcode code = session.InfoRead(handle); if (code != CURLE_AGAIN) return 0; if (mcode != CURLM_CALL_MULTI_PERFORM && !session.Select(timeout_ms)) return 0; CURLMcode mcode = session.Perform(); if (mcode != CURLM_OK && mcode != CURLM_CALL_MULTI_PERFORM) return 0; } --buffer_size; if (buffer_size > range.length) buffer_size = range.length; uint8_t *p = (uint8_t *)_buffer; std::copy(range.data, range.data + buffer_size, p); p[buffer_size] = 0; buffer.Consume(buffer_size); curl_easy_pause(handle, CURLPAUSE_CONT); return buffer_size; }
int client_send (struct Session *s, struct HTTP_Message *msg) { GNUNET_assert (s != NULL); GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); if (GNUNET_YES != exist_session(p, s)) { GNUNET_break (0); return GNUNET_SYSERR; } if (s->client_put_paused == GNUNET_YES) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Client: %p was suspended, unpausing\n", s->client_put); s->client_put_paused = GNUNET_NO; curl_easy_pause (s->client_put, CURLPAUSE_CONT); } client_schedule (s->plugin, GNUNET_YES); return GNUNET_OK; }
void requestBytes( size_t offset, size_t len ) { switch (state_) { case 0: // requestInfo has not be called state_ = 3; perform(); break; case 1: // requestInfo has been called but we are not blocked yet state_ = 3; break; case 2: // we are blocked state_ = 3; #ifdef USE_CURL_PAUSE curl_easy_pause(cur_, CURLPAUSE_SEND_CONT); #endif break; #ifndef USE_CURL_PAUSE case 4: state_ = 3; break; #endif } }
extern "C" int32_t HttpNative_EasyUnpause(CURL* handle) { return curl_easy_pause(handle, CURLPAUSE_CONT); }
// This is the writer call back function used by cur_ size_t writer_callback( void *ptr, size_t size, size_t nmemb) { dputils::StreamGuard guard(this); if (!client_) return 0; // What we will return size_t result = 0; size_t bytes = size * nmemb; switch (state_) { case 0: // broken state; return 0; case 1: // unexpected, but let's recover #ifdef USE_CURL_PAUSE curl_easy_pause (cur_, CURLPAUSE_SEND); state_ = 2; #else state_ = 4; #endif append ((unsigned char *)ptr, bytes); if (client_) { client_->propertiesReady(); } break; case 2: { //it's the first time after requestBytes was called append((unsigned char *)ptr, bytes); dp::Data data (saved_, saved_size_); state_ = 3; if (client_) { size_t oldOffset = write_offset_; write_offset_ += bytes; client_->bytesReady(oldOffset, data, bytes == 0); } } break; case 3: { dp::Data data (static_cast<unsigned char *>(ptr), bytes); if (client_) { size_t oldOffset = write_offset_; write_offset_ += bytes; client_->bytesReady(oldOffset, data, bytes == 0); } } break; #ifndef USE_CURL_PAUSE case 4: { append ((unsigned char *)ptr, bytes); } break; #endif } if (client_) result = bytes; return result; }
size_t header_callback( void *ptr, size_t size, size_t nmemb) { dputils::StreamGuard guard(this); if (!client_) return 0; // What we will return size_t result = 0; size_t bytes = size * nmemb; if (state_ > 1) return bytes; // we are not guaranteed that ptr is null-terminated char *buf = new char[bytes + 1]; if (ptr != NULL && bytes != 0) ::memcpy (buf, ptr, bytes); buf[bytes] = (char)0; size_t len = ::strlen(buf); while (len > 0 && buf[len-1] <= ' ') { len--; buf[len] = 0; } if (len == 0) { #ifdef USE_CURL_PAUSE curl_easy_pause (cur_, CURLPAUSE_SEND); state_ = 2; #else state_ = 4; #endif if (client_) { client_->propertiesReady(); } } else { char * colon = ::strchr(buf, ':'); if (colon) { *colon = (char)0; do { ++colon; } while (*colon == ' '); int t = ::strlen(colon); if (client_) { if (::strcmp(buf, "Content-Length") == 0) { int len = ::atoi(colon); if (len > 0) { client_->totalLengthReady(len); } } else { client_->propertyReady(buf, colon); } } } } delete[] buf; if (client_) result = bytes; return result; }
CURLcode Mtacurl::pause( int bitmask ) { return curl_easy_pause(m_pCurl, bitmask); }
static void tr_webThreadFunc (void * vsession) { char * str; CURLM * multi; struct tr_web * web; int taskCount = 0; struct tr_web_task * task; tr_session * session = vsession; /* try to enable ssl for https support; but if that fails, * try a plain vanilla init */ if (curl_global_init (CURL_GLOBAL_SSL)) curl_global_init (0); web = tr_new0 (struct tr_web, 1); web->close_mode = ~0; web->taskLock = tr_lockNew (); web->tasks = NULL; web->curl_verbose = getenv ("TR_CURL_VERBOSE") != NULL; web->curl_ssl_verify = getenv ("TR_CURL_SSL_VERIFY") != NULL; web->curl_ca_bundle = getenv ("CURL_CA_BUNDLE"); if (web->curl_ssl_verify) { tr_logAddNamedInfo ("web", "will verify tracker certs using envvar CURL_CA_BUNDLE: %s", web->curl_ca_bundle == NULL ? "none" : web->curl_ca_bundle); tr_logAddNamedInfo ("web", "NB: this only works if you built against libcurl with openssl or gnutls, NOT nss"); tr_logAddNamedInfo ("web", "NB: invalid certs will show up as 'Could not connect to tracker' like many other errors"); } str = tr_buildPath (session->configDir, "cookies.txt", NULL); if (tr_fileExists (str, NULL)) web->cookie_filename = tr_strdup (str); tr_free (str); multi = curl_multi_init (); session->web = web; for (;;) { long msec; int unused; CURLMsg * msg; CURLMcode mcode; if (web->close_mode == TR_WEB_CLOSE_NOW) break; if ((web->close_mode == TR_WEB_CLOSE_WHEN_IDLE) && (web->tasks == NULL)) break; /* add tasks from the queue */ tr_lockLock (web->taskLock); while (web->tasks != NULL) { /* pop the task */ task = web->tasks; web->tasks = task->next; task->next = NULL; dbgmsg ("adding task to curl: [%s]", task->url); curl_multi_add_handle (multi, createEasy (session, web, task)); /*fprintf (stderr, "adding a task.. taskCount is now %d\n", taskCount);*/ ++taskCount; } tr_lockUnlock (web->taskLock); /* unpause any paused curl handles */ if (paused_easy_handles != NULL) { CURL * handle; tr_list * tmp; /* swap paused_easy_handles to prevent oscillation between writeFunc this while loop */ tmp = paused_easy_handles; paused_easy_handles = NULL; while ((handle = tr_list_pop_front (&tmp))) curl_easy_pause (handle, CURLPAUSE_CONT); } /* maybe wait a little while before calling curl_multi_perform () */ msec = 0; curl_multi_timeout (multi, &msec); if (msec < 0) msec = THREADFUNC_MAX_SLEEP_MSEC; if (session->isClosed) msec = 100; /* on shutdown, call perform () more frequently */ if (msec > 0) { int usec; int max_fd; struct timeval t; fd_set r_fd_set, w_fd_set, c_fd_set; max_fd = 0; FD_ZERO (&r_fd_set); FD_ZERO (&w_fd_set); FD_ZERO (&c_fd_set); curl_multi_fdset (multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd); if (msec > THREADFUNC_MAX_SLEEP_MSEC) msec = THREADFUNC_MAX_SLEEP_MSEC; usec = msec * 1000; t.tv_sec = usec / 1000000; t.tv_usec = usec % 1000000; tr_select (max_fd+1, &r_fd_set, &w_fd_set, &c_fd_set, &t); } /* call curl_multi_perform () */ do mcode = curl_multi_perform (multi, &unused); while (mcode == CURLM_CALL_MULTI_PERFORM); /* pump completed tasks from the multi */ while ((msg = curl_multi_info_read (multi, &unused))) { if ((msg->msg == CURLMSG_DONE) && (msg->easy_handle != NULL)) { double total_time; struct tr_web_task * task; long req_bytes_sent; CURL * e = msg->easy_handle; curl_easy_getinfo (e, CURLINFO_PRIVATE, (void*)&task); assert (e == task->curl_easy); curl_easy_getinfo (e, CURLINFO_RESPONSE_CODE, &task->code); curl_easy_getinfo (e, CURLINFO_REQUEST_SIZE, &req_bytes_sent); curl_easy_getinfo (e, CURLINFO_TOTAL_TIME, &total_time); task->did_connect = task->code>0 || req_bytes_sent>0; task->did_timeout = !task->code && (total_time >= task->timeout_secs); curl_multi_remove_handle (multi, e); tr_list_remove_data (&paused_easy_handles, e); curl_easy_cleanup (e); tr_runInEventThread (task->session, task_finish_func, task); --taskCount; } } } /* Discard any remaining tasks. * This is rare, but can happen on shutdown with unresponsive trackers. */ while (web->tasks != NULL) { task = web->tasks; web->tasks = task->next; dbgmsg ("Discarding task \"%s\"", task->url); task_free (task); } /* cleanup */ tr_list_free (&paused_easy_handles, NULL); curl_multi_cleanup (multi); tr_lockFree (web->taskLock); tr_free (web->cookie_filename); tr_free (web); session->web = NULL; }
size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) { size_t rc; struct OutStruct *outs = userdata; struct OperationConfig *config = outs->config; size_t bytes = sz * nmemb; bool is_tty = config->global->isatty; /* * Once that libcurl has called back tool_write_cb() the returned value * is checked against the amount that was intended to be written, if * it does not match then it fails with CURLE_WRITE_ERROR. So at this * point returning a value different from sz*nmemb indicates failure. */ const size_t failure = bytes ? 0 : 1; #ifdef DEBUGBUILD { char *tty = curlx_getenv("CURL_ISATTY"); if(tty) { is_tty = TRUE; curl_free(tty); } } if(config->show_headers) { if(bytes > (size_t)CURL_MAX_HTTP_HEADER) { warnf(config->global, "Header data size exceeds single call write " "limit!\n"); return failure; } } else { if(bytes > (size_t)CURL_MAX_WRITE_SIZE) { warnf(config->global, "Data size exceeds single call write limit!\n"); return failure; } } { /* Some internal congruency checks on received OutStruct */ bool check_fails = FALSE; if(outs->filename) { /* regular file */ if(!*outs->filename) check_fails = TRUE; if(!outs->s_isreg) check_fails = TRUE; if(outs->fopened && !outs->stream) check_fails = TRUE; if(!outs->fopened && outs->stream) check_fails = TRUE; if(!outs->fopened && outs->bytes) check_fails = TRUE; } else { /* standard stream */ if(!outs->stream || outs->s_isreg || outs->fopened) check_fails = TRUE; if(outs->alloc_filename || outs->is_cd_filename || outs->init) check_fails = TRUE; } if(check_fails) { warnf(config->global, "Invalid output struct data for write callback\n"); return failure; } } #endif if(!outs->stream && !tool_create_output_file(outs)) return failure; if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) { /* binary output to terminal? */ if(memchr(buffer, 0, bytes)) { warnf(config->global, "Binary output can mess up your terminal. " "Use \"--output -\" to tell curl to output it to your terminal " "anyway, or consider \"--output <FILE>\" to save to a file.\n"); config->synthetic_error = ERR_BINARY_TERMINAL; return failure; } } #ifdef _WIN32 if(isatty(fileno(outs->stream))) { DWORD in_len = (DWORD)(sz * nmemb); wchar_t* wc_buf; DWORD wc_len; intptr_t fhnd; /* calculate buffer size for wide characters */ wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, NULL, 0); wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t)); if(!wc_buf) return failure; /* calculate buffer size for multi-byte characters */ wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, wc_buf, wc_len); if(!wc_len) { free(wc_buf); return failure; } fhnd = _get_osfhandle(fileno(outs->stream)); if(!WriteConsoleW( (HANDLE) fhnd, wc_buf, wc_len, &wc_len, NULL)) { free(wc_buf); return failure; } free(wc_buf); rc = bytes; } else #endif rc = fwrite(buffer, sz, nmemb, outs->stream); if(bytes == rc) /* we added this amount of data to the output */ outs->bytes += bytes; if(config->readbusy) { config->readbusy = FALSE; curl_easy_pause(config->easy, CURLPAUSE_CONT); } if(config->nobuffer) { /* output buffering disabled */ int res = fflush(outs->stream); if(res) return failure; } return rc; }
void ResourceHandleManager::initializeHandle(ResourceHandle* job) { KURL kurl = job->request().url(); // Remove any fragment part, otherwise curl will send it as part of the request. kurl.removeRef(); ResourceHandleInternal* d = job->getInternal(); String url = kurl.string(); if (kurl.isLocalFile()) { String query = kurl.query(); // Remove any query part sent to a local file. if (!query.isEmpty()) url = url.left(url.find(query)); // Determine the MIME type based on the path. d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(url)); } d->m_handle = curl_easy_init(); #if LIBCURL_VERSION_NUM > 0x071200 if (d->m_defersLoading) { CURLcode error = curl_easy_pause(d->m_handle, CURLPAUSE_ALL); // If we did not pause the handle, we would ASSERT in the // header callback. So just assert here. ASSERT(error == CURLE_OK); } #endif #ifndef NDEBUG if (getenv("DEBUG_CURL")) curl_easy_setopt(d->m_handle, CURLOPT_VERBOSE, 1); #endif curl_easy_setopt(d->m_handle, CURLOPT_PRIVATE, job); curl_easy_setopt(d->m_handle, CURLOPT_ERRORBUFFER, m_curlErrorBuffer); curl_easy_setopt(d->m_handle, CURLOPT_WRITEFUNCTION, writeCallback); curl_easy_setopt(d->m_handle, CURLOPT_WRITEDATA, job); curl_easy_setopt(d->m_handle, CURLOPT_HEADERFUNCTION, headerCallback); curl_easy_setopt(d->m_handle, CURLOPT_WRITEHEADER, job); curl_easy_setopt(d->m_handle, CURLOPT_AUTOREFERER, 1); curl_easy_setopt(d->m_handle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(d->m_handle, CURLOPT_MAXREDIRS, 10); curl_easy_setopt(d->m_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(d->m_handle, CURLOPT_SHARE, m_curlShareHandle); curl_easy_setopt(d->m_handle, CURLOPT_DNS_CACHE_TIMEOUT, 60 * 5); // 5 minutes // FIXME: Enable SSL verification when we have a way of shipping certs // and/or reporting SSL errors to the user. if (ignoreSSLErrors) curl_easy_setopt(d->m_handle, CURLOPT_SSL_VERIFYPEER, false); // enable gzip and deflate through Accept-Encoding: curl_easy_setopt(d->m_handle, CURLOPT_ENCODING, ""); // url must remain valid through the request ASSERT(!d->m_url); // url is in ASCII so latin1() will only convert it to char* without character translation. d->m_url = strdup(url.latin1().data()); curl_easy_setopt(d->m_handle, CURLOPT_URL, d->m_url); if (m_cookieJarFileName) { curl_easy_setopt(d->m_handle, CURLOPT_COOKIEFILE, m_cookieJarFileName); curl_easy_setopt(d->m_handle, CURLOPT_COOKIEJAR, m_cookieJarFileName); } struct curl_slist* headers = 0; if (job->request().httpHeaderFields().size() > 0) { HTTPHeaderMap customHeaders = job->request().httpHeaderFields(); HTTPHeaderMap::const_iterator end = customHeaders.end(); for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it) { String key = it->first; String value = it->second; String headerString(key); headerString.append(": "); headerString.append(value); CString headerLatin1 = headerString.latin1(); headers = curl_slist_append(headers, headerLatin1.data()); } } if ("GET" == job->request().httpMethod()) curl_easy_setopt(d->m_handle, CURLOPT_HTTPGET, TRUE); else if ("POST" == job->request().httpMethod()) setupPOST(job, &headers); else if ("PUT" == job->request().httpMethod()) setupPUT(job, &headers); else if ("HEAD" == job->request().httpMethod()) curl_easy_setopt(d->m_handle, CURLOPT_NOBODY, TRUE); if (headers) { curl_easy_setopt(d->m_handle, CURLOPT_HTTPHEADER, headers); d->m_customHeaders = headers; } }
static DWORD WINAPI curl_threadfunc(LPVOID _unused) { #else static void *curl_threadfunc(void *_unused) { #endif while(1) { if(will_overflow()) { curl_easy_pause(curl_handle, CURLPAUSE_ALL); do { printf("."); fflush(stdout); usleep(100000); } while(will_overflow()); curl_easy_pause(curl_handle, CURLPAUSE_CONT); } if(curl_easy_perform(curl_handle) != CURLE_OK) sleep(2); printf("Retrying URL connect...\n"); } return 0; } int main(int argc, char *argv[]) { #ifdef _WIN32 int tid; #else pthread_t thd; #endif if(argc != 4) { fprintf(stderr, "Usage: %s <stream_url> <nbd_addr> <nbd_port>\n", argv[0]); return 1; } curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_URL, argv[1]); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, curl_cback); curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "vdf_stream"); drv = vdf_drive_create(DRIVE_SIZE, DRIVE_FLAGS); if(drv == NULL) { perror("vdf_createdrive"); return 1; } bps = vdf_drive_sectorsize(drv); filesize = (vdf_drive_dataclusters(drv) - 16) * vdf_drive_clustersize(drv); /* leave a bit of room */ bufflen = bps * BUFFCNT; buffer = malloc(bufflen); if(buffer == NULL) { perror("malloc"); return 1; } bstart = bend = 0; writeoff = 0; fil = vdf_add_file_virt(vdf_drive_root(drv), TRACK_NAME, filesize, file_cback, NULL, 0); if(fil == NULL) { perror("vdf_add_file_virt"); return 1; } trans = vdf_transport_open(VTD_NBD_CLI_STR, drv, NULL, argv[2], argv[3]); if(trans == NULL) { perror("vdf_transport_open"); return 1; } #ifdef _WIN32 if(CreateThread(NULL, 0, curl_threadfunc, NULL, 0, &tid) == NULL) { perror("CreateThread"); return 1; } #else if(pthread_create(&thd, NULL, curl_threadfunc, NULL) == -1) { perror("pthread_create"); return 1; } #endif // vdf_dump_drive_info(drv, stdout); // vdf_dump_drive(drv, "stream.img"); // return 0; while(1) { if(vdf_transport_start(trans) == 0) { while(vdf_transport_process(trans) == 0); } else { printf("Retrying NBD connect...\n"); sleep(2); } } }
static off_t libcurl_seek(hFILE *fpv, off_t offset, int whence) { hFILE_libcurl *fp = (hFILE_libcurl *) fpv; CURLcode err; CURLMcode errm; off_t origin, pos; switch (whence) { case SEEK_SET: origin = 0; break; case SEEK_CUR: errno = ENOSYS; return -1; case SEEK_END: if (fp->file_size < 0) { errno = ESPIPE; return -1; } origin = fp->file_size; break; default: errno = EINVAL; return -1; } // Check 0 <= origin+offset < fp->file_size carefully, avoiding overflow if ((offset < 0)? origin + offset < 0 : (fp->file_size >= 0 && offset > fp->file_size - origin)) { errno = EINVAL; return -1; } pos = origin + offset; errm = curl_multi_remove_handle(curl.multi, fp->easy); if (errm != CURLM_OK) { errno = multi_errno(errm); return -1; } curl.nrunning--; // TODO If we seem to be doing random access, use CURLOPT_RANGE to do // limited reads (e.g. about a BAM block!) so seeking can reuse the // existing connection more often. if (pos <= 2147483647) err = curl_easy_setopt(fp->easy, CURLOPT_RESUME_FROM, (long) pos); else err = curl_easy_setopt(fp->easy, CURLOPT_RESUME_FROM_LARGE, (curl_off_t) pos); if (err != CURLE_OK) { errno = easy_errno(fp->easy, err); return -1; } fp->buffer.len = 0; fp->paused = fp->finished = 0; errm = curl_multi_add_handle(curl.multi, fp->easy); if (errm != CURLM_OK) { errno = multi_errno(errm); return -1; } curl.nrunning++; err = curl_easy_pause(fp->easy, CURLPAUSE_CONT); if (err != CURLE_OK) { errno = easy_errno(fp->easy, err); return -1; } while (! fp->paused && ! fp->finished) if (wait_perform() < 0) return -1; if (fp->finished && fp->final_result != CURLE_OK) { errno = easy_errno(fp->easy, fp->final_result); return -1; } return pos; }
CURLcode DllLibCurl::easy_pause(CURL_HANDLE* handle, int bitmask) { return curl_easy_pause(handle, bitmask); }
int32_t HttpNative_EasyUnpause(CURL* handle) { return (int32_t)(curl_easy_pause(handle, CURLPAUSE_CONT)); }
// This is the writer call back function used by m_curl size_t writer_callback( void *ptr, size_t size, size_t nmemb) { dputils::StreamGuard guard(this); if (!m_client) return 0; // What we will return size_t result = 0; size_t bytes = size * nmemb; switch (m_state) { case 0: // broken state; return 0; case 1: // unexpected, but let's recover #ifdef USE_CURL_PAUSE curl_easy_pause (m_curl, CURLPAUSE_SEND); m_state = 2; #else m_state = 4; #endif append ((unsigned char *)ptr, bytes); if (m_client) { m_client->propertiesReady(); } break; case 2: { //it's the first time after requestBytes was called append((unsigned char *)ptr, bytes); dp::Data data (m_saved, m_savedSize); m_state = 3; if (m_client) { size_t oldOffset = m_writeOffset; m_writeOffset += bytes; if( m_verbose ) reportData( "in", oldOffset, data ); m_client->bytesReady(oldOffset, data, bytes == 0); } } break; case 3: { dp::Data data (static_cast<unsigned char *>(ptr), bytes); if (m_client) { size_t oldOffset = m_writeOffset; m_writeOffset += bytes; if( m_verbose ) reportData( "in", oldOffset, data ); m_client->bytesReady(oldOffset, data, bytes == 0); } } break; #ifndef USE_CURL_PAUSE case 4: { append ((unsigned char *)ptr, bytes); } break; #endif } if (m_client) result = bytes; return result; }
size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata) { size_t rc; struct OutStruct *outs = userdata; struct Configurable *config = outs->config; /* * Once that libcurl has called back tool_write_cb() the returned value * is checked against the amount that was intended to be written, if * it does not match then it fails with CURLE_WRITE_ERROR. So at this * point returning a value different from sz*nmemb indicates failure. */ const size_t failure = (sz * nmemb) ? 0 : 1; if(!config) return failure; #ifdef DEBUGBUILD if(config->include_headers) { if(sz * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { warnf(config, "Header data size exceeds single call write limit!\n"); return failure; } } else { if(sz * nmemb > (size_t)CURL_MAX_WRITE_SIZE) { warnf(config, "Data size exceeds single call write limit!\n"); return failure; } } { /* Some internal congruency checks on received OutStruct */ bool check_fails = FALSE; if(outs->filename) { /* regular file */ if(!*outs->filename) check_fails = TRUE; if(!outs->s_isreg) check_fails = TRUE; if(outs->fopened && !outs->stream) check_fails = TRUE; if(!outs->fopened && outs->stream) check_fails = TRUE; if(!outs->fopened && outs->bytes) check_fails = TRUE; } else { /* standard stream */ if(!outs->stream || outs->s_isreg || outs->fopened) check_fails = TRUE; if(outs->alloc_filename || outs->init) check_fails = TRUE; } if(check_fails) { warnf(config, "Invalid output struct data for write callback\n"); return failure; } } #endif if(!outs->stream) { FILE *file; if(!outs->filename || !*outs->filename) { warnf(config, "Remote filename has no length!\n"); return failure; } if(config->content_disposition) { /* don't overwrite existing files */ file = fopen(outs->filename, "rb"); if(file) { fclose(file); warnf(config, "Refusing to overwrite %s: %s\n", outs->filename, strerror(EEXIST)); return failure; } } /* open file for writing */ file = fopen(outs->filename, "wb"); if(!file) { warnf(config, "Failed to create the file %s: %s\n", outs->filename, strerror(errno)); return failure; } outs->s_isreg = TRUE; outs->fopened = TRUE; outs->stream = file; outs->bytes = 0; outs->init = 0; } rc = fwrite(buffer, sz, nmemb, outs->stream); if((sz * nmemb) == rc) /* we added this amount of data to the output */ outs->bytes += (sz * nmemb); if(config->readbusy) { config->readbusy = FALSE; curl_easy_pause(config->easy, CURLPAUSE_CONT); } if(config->nobuffer) { /* output buffering disabled */ int res = fflush(outs->stream); if(res) return failure; } return rc; }
/** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a * peer disconnecting, the continuation MUST be called * prior to the disconnect notification itself. This function * will be called with this peer's HELLO message to initiate * a fresh connection to another peer. * * @param cls closure * @param s which session must be used * @param msgbuf the message to transmit * @param msgbuf_size number of bytes in 'msgbuf' * @param priority how important is the message (most plugins will * ignore message priority and just FIFO) * @param to how long to wait at most for the transmission (does not * require plugins to discard the message after the timeout, * just advisory for the desired delay; most plugins will ignore * this as well) * @param cont continuation to call once the message has * been transmitted (or if the transport is ready * for the next transmission call; or if the * peer disconnected...); can be NULL * @param cont_cls closure for cont * @return number of bytes used (on the physical network, with overheads); * -1 on hard errors (i.e. address invalid); 0 is a legal value * and does NOT mean that the message was not transmitted (DV) */ static ssize_t http_client_plugin_send (void *cls, struct Session *s, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) { struct HTTP_Client_Plugin *plugin = cls; struct HTTP_Message *msg; char *stat_txt; GNUNET_assert (plugin != NULL); GNUNET_assert (s != NULL); /* lookup if session is really existing */ if (GNUNET_YES != client_exist_session (plugin, s)) { GNUNET_break (0); return GNUNET_SYSERR; } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Session %p/connection %p: Sending message with %u to peer `%s' \n", s, s->client_put, msgbuf_size, GNUNET_i2s (&s->target)); /* create new message and schedule */ msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size); msg->next = NULL; msg->size = msgbuf_size; msg->pos = 0; msg->buf = (char *) &msg[1]; msg->transmit_cont = cont; msg->transmit_cont_cls = cont_cls; memcpy (msg->buf, msgbuf, msgbuf_size); GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); GNUNET_asprintf (&stat_txt, "# bytes currently in %s_client buffers", plugin->protocol); GNUNET_STATISTICS_update (plugin->env->stats, stat_txt, msgbuf_size, GNUNET_NO); GNUNET_free (stat_txt); if (GNUNET_YES == s->put_tmp_disconnecting) { /* PUT connection is currently getting disconnected */ s->put_reconnect_required = GNUNET_YES; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Session %p/connection %jp: currently disconnecting, reconnecting immediately\n", s, s->client_put); return msgbuf_size; } else if (GNUNET_YES == s->put_paused) { /* PUT connection was paused, unpause */ GNUNET_assert (s->put_disconnect_task != GNUNET_SCHEDULER_NO_TASK); GNUNET_SCHEDULER_cancel (s->put_disconnect_task); s->put_disconnect_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Session %p/connection %p: unpausing connection\n", s, s->client_put); s->put_paused = GNUNET_NO; curl_easy_pause (s->client_put, CURLPAUSE_CONT); } else if (GNUNET_YES == s->put_tmp_disconnected) { /* PUT connection was disconnected, reconnect */ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Session %p: Reconnecting PUT connection\n", s); s->put_tmp_disconnected = GNUNET_NO; GNUNET_break (s->client_put == NULL); if (GNUNET_SYSERR == client_connect_put (s)) { return GNUNET_SYSERR; } } client_schedule (s->plugin, GNUNET_YES); client_reschedule_session_timeout (s); return msgbuf_size; }