mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-12-27 08:49:16 +08:00
d62a9e623c
re: github issue https://github.com/Unidata/netcdf-c/issues/1111 One of the less common use cases for the in-memory feature is apparently failing with HDF5-1.10.x. The fix is complicated and requires significant changes to libhdf5/nc4memcb.c. The current setup is detailed in the file docs/inmeminternal.dox. Additionally, it was discovered that the program nc_test/tst_inmemory.c, which is invoked by nc_test/run_inmemory.sh, actually was failing because of the above problem. But the failure is not detected since the script does not return non-zero value. Other Changes: 1. Fix nc_test_tst_inmemory to return errors correctly. 2. Make ncdap_tests/findtestserver.c and dap4_tests/findtestserver4.c be generated from ncdap_test/findtestserver.c.in. 3. Make LOG() print output to stderr instead of stdout to avoid contaminating e.g. ncdump output. 4. Modify the handling of NC_INMEMORY and NC_DISKLESS flags to properly handle that NC_DISKLESS => NC_INMEMORY. This affects a number of code pieces, especially memio.c.
168 lines
4.2 KiB
C
168 lines
4.2 KiB
C
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <curl/curl.h>
|
|
#include "netcdf.h"
|
|
|
|
#undef FINDTESTSERVER_DEBUG
|
|
|
|
#define MAXSERVERURL 4096
|
|
#define TIMEOUT 10 /*seconds*/
|
|
#define BUFSIZE 8192 /*bytes*/
|
|
|
|
#ifndef HAVE_CURLINFO_RESPONSE_CODE
|
|
#define CURLINFO_RESPONSE_CODE CURLINFO_HTTP_CODE
|
|
#endif
|
|
|
|
static int ping(const char* url);
|
|
|
|
static char**
|
|
parseServers(const char* remotetestservers)
|
|
{
|
|
char* rts;
|
|
char** servers = NULL;
|
|
char** list;
|
|
char* p;
|
|
char* svc;
|
|
char** l;
|
|
|
|
list = (char**)malloc(sizeof(char*) * (int)(strlen(remotetestservers)/2));
|
|
if(list == NULL) return NULL;
|
|
l = list;
|
|
rts = strdup(remotetestservers);
|
|
if(rts == NULL) {free(list); return NULL;}
|
|
p = rts;
|
|
for(;;) {
|
|
svc = p;
|
|
p = strchr(svc,',');
|
|
if(p != NULL) *p = '\0';
|
|
*l++ = strdup(svc);
|
|
if(p == NULL) break;
|
|
p++;
|
|
}
|
|
*l = NULL;
|
|
if(p) free(p);
|
|
servers = list;
|
|
return servers;
|
|
}
|
|
|
|
/**
|
|
Given a partial suffix path and a specified
|
|
protocol, test if a request to any of the test
|
|
servers + path returns some kind of result.
|
|
This indicates that the server is up and running.
|
|
Return the complete url for the server plus the path.
|
|
*/
|
|
|
|
static char*
|
|
nc_findtestserver(const char* path, int isdap4, const char* serverlist)
|
|
{
|
|
char** svc;
|
|
char url[MAXSERVERURL];
|
|
|
|
if((svc = parseServers(serverlist))==NULL) {
|
|
fprintf(stderr,"cannot parse test server list: %s\n",serverlist);
|
|
return NULL;
|
|
}
|
|
for(;*svc;svc++) {
|
|
if(*svc == NULL || strlen(*svc) == 0)
|
|
return NULL;
|
|
if(path == NULL) path = "";
|
|
if(strlen(path) > 0 && path[0] == '/')
|
|
path++;
|
|
snprintf(url,MAXSERVERURL,"http://%s/%s",*svc,path);
|
|
if(ping(url) == NC_NOERR)
|
|
return strdup(url);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define CERR(expr) if((cstat=(expr)) != CURLE_OK) goto done;
|
|
|
|
struct Buffer {
|
|
char data[BUFSIZE];
|
|
size_t offset; /* into buffer */
|
|
};
|
|
|
|
static size_t
|
|
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
|
|
{
|
|
struct Buffer* buffer = (struct Buffer*)data;
|
|
size_t total = size * nmemb;
|
|
size_t canwrite = total; /* assume so */
|
|
if(total == 0) {
|
|
fprintf(stderr,"WriteMemoryCallback: zero sized chunk\n");
|
|
goto done;
|
|
}
|
|
if((buffer->offset + total) > sizeof(buffer->data))
|
|
canwrite = (sizeof(buffer->data) - buffer->offset); /* partial read */
|
|
if(canwrite > 0)
|
|
memcpy(&(buffer->data[buffer->offset]),ptr,canwrite);
|
|
buffer->offset += canwrite;
|
|
done:
|
|
return total; /* pretend we captured everything */
|
|
}
|
|
|
|
/*
|
|
See if a server is responding.
|
|
Return NC_ECURL if the ping fails, NC_NOERR otherwise
|
|
*/
|
|
static int
|
|
ping(const char* url)
|
|
{
|
|
int stat = NC_NOERR;
|
|
CURLcode cstat = CURLE_OK;
|
|
CURL* curl = NULL;
|
|
long http_code = 0;
|
|
struct Buffer data;
|
|
|
|
/* Create a CURL instance */
|
|
curl = curl_easy_init();
|
|
if (curl == NULL) {cstat = CURLE_OUT_OF_MEMORY; goto done;}
|
|
CERR((curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1)));
|
|
|
|
/* Use redirects */
|
|
CERR((curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L)));
|
|
CERR((curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L)));
|
|
|
|
/* use a very short timeout: 10 seconds */
|
|
CERR((curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)TIMEOUT)));
|
|
|
|
/* fail on HTTP 400 code errors */
|
|
CERR((curl_easy_setopt(curl, CURLOPT_FAILONERROR, (long)1)));
|
|
|
|
/* Set the URL */
|
|
CERR((curl_easy_setopt(curl, CURLOPT_URL, (void*)url)));
|
|
|
|
/* send all data to this function */
|
|
CERR((curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback)));
|
|
|
|
/* we pass our file to the callback function */
|
|
CERR((curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&data)));
|
|
|
|
data.offset = 0;
|
|
memset(data.data,0,sizeof(data.data));
|
|
|
|
CERR((curl_easy_perform(curl)));
|
|
|
|
/* Don't trust curl to return an error when request gets 404 */
|
|
CERR((curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &http_code)));
|
|
if(http_code >= 400) {
|
|
cstat = CURLE_HTTP_RETURNED_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if(cstat != CURLE_OK) {
|
|
#ifdef FINDTESTSERVER_DEBUG
|
|
fprintf(stderr, "curl error: %s; url=%s\n",
|
|
curl_easy_strerror(cstat),url);
|
|
#endif
|
|
stat = NC_ECURL;
|
|
}
|
|
if (curl != NULL)
|
|
curl_easy_cleanup(curl);
|
|
return stat;
|
|
}
|