1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
#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 = NULL;
char* p;
char* svc;
char** l;
list = (char**)malloc(sizeof(char*) * (int)(strlen(remotetestservers)/2));
if(list == NULL) return NULL;
rts = strdup(remotetestservers);
if(rts == NULL) goto done;
l = list;
p = rts;
for(;;) {
svc = p;
p = strchr(svc,',');
if(p != NULL) *p = '\0';
*l++ = strdup(svc);
if(p == NULL) break;
p++;
}
*l = NULL;
servers = list;
list = NULL;
done:
if(rts) free(rts);
if(list) free(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** svclist;
char** svc;
char url[MAXSERVERURL];
char* match = NULL;
if((svclist = parseServers(serverlist))==NULL) {
fprintf(stderr,"cannot parse test server list: %s\n",serverlist);
return NULL;
}
for(svc=svclist;*svc;svc++) {
if(strlen(*svc) == 0)
goto done;
if(path == NULL) path = "";
if(strlen(path) > 0 && path[0] == '/')
path++;
/* Try https: first */
snprintf(url,MAXSERVERURL,"https://%s/%s",*svc,path);
if(ping(url) == NC_NOERR)
{match = strdup(url); goto done;}
/* Try http: next */
snprintf(url,MAXSERVERURL,"http://%s/%s",*svc,path);
if(ping(url) == NC_NOERR)
{match = strdup(url); goto done;}
}
done:
/* Free up the envv list of servers */
if(svclist != NULL) {
char** p;
for(p=svclist;*p;p++)
free(*p);
free(svclist);
}
return match;
}
#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;
}
|