File: nctestserver.h

package info (click to toggle)
netcdf-parallel 1%3A4.6.2-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 101,668 kB
  • sloc: ansic: 200,241; sh: 10,807; yacc: 2,522; makefile: 1,306; lex: 1,153; xml: 173; awk: 2
file content (185 lines) | stat: -rw-r--r-- 4,714 bytes parent folder | download | duplicates (2)
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;
}