1 #include <petscwebclient.h>
2 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3 #pragma gcc diagnostic ignored "-Wdeprecated-declarations"
4
5 /*
6 Encodes and decodes from MIME Base64
7 */
8 static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
9 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
10 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
11 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
12 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
13 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
14 'w', 'x', 'y', 'z', '0', '1', '2', '3',
15 '4', '5', '6', '7', '8', '9', '+', '/'};
16
base64_encode(const unsigned char * data,unsigned char * encoded_data,size_t len)17 static PetscErrorCode base64_encode(const unsigned char *data,unsigned char *encoded_data,size_t len)
18 {
19 static size_t mod_table[] = {0, 2, 1};
20 size_t i,j;
21 size_t input_length,output_length;
22 PetscErrorCode ierr;
23
24 PetscFunctionBegin;
25 ierr = PetscStrlen((const char*)data,&input_length);CHKERRQ(ierr);
26 output_length = 4 * ((input_length + 2) / 3);
27 if (output_length > len) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Output length not large enough");
28
29 for (i = 0, j = 0; i < input_length;) {
30 uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
31 uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
32 uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
33 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
34
35 encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
36 encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
37 encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
38 encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
39 }
40 encoded_data[j] = 0;
41 for (i = 0; i < mod_table[input_length % 3]; i++) encoded_data[output_length - 1 - i] = '=';
42 PetscFunctionReturn(0);
43 }
44
base64_decode(const unsigned char * data,unsigned char * decoded_data,size_t length)45 PETSC_UNUSED static PetscErrorCode base64_decode(const unsigned char *data,unsigned char* decoded_data, size_t length)
46 {
47 static char decoding_table[257];
48 static int decode_table_built = 0;
49 size_t i,j;
50 PetscErrorCode ierr;
51 size_t input_length,output_length;
52
53 PetscFunctionBegin;
54 if (!decode_table_built) {
55 for (i = 0; i < 64; i++) decoding_table[(unsigned char) encoding_table[i]] = i;
56 decode_table_built = 1;
57 }
58
59 ierr = PetscStrlen((const char*)data,&input_length);CHKERRQ(ierr);
60 if (input_length % 4 != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Input length must be divisible by 4");
61
62 output_length = input_length / 4 * 3;
63 if (data[input_length - 1] == '=') (output_length)--;
64 if (data[input_length - 2] == '=') (output_length)--;
65 if (output_length > length) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Output length too shore");
66
67 for (i = 0, j = 0; i < input_length;) {
68 uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
69 uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
70 uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
71 uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
72 uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
73
74 if (j < output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
75 if (j < output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
76 if (j < output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
77 }
78 decoded_data[j] = 0;
79 PetscFunctionReturn(0);
80 }
81
82 #if defined(PETSC_HAVE_UNISTD_H)
83 #include <unistd.h>
84 #endif
85
86 /*@C
87 PetscGlobusAuthorize - Get an access token allowing PETSc applications to make Globus file transfer requests
88
89 Not collective, only the first process in MPI_Comm does anything
90
91 Input Parameters:
92 + comm - the MPI communicator
93 - tokensize - size of the token array
94
95 Output Parameters:
96 . access_token - can be used with PetscGlobusUpLoad() for 30 days
97
98 Notes:
99 This call requires stdout and stdin access from process 0 on the MPI communicator
100
101 You can run src/sys/webclient/tutorials/globusobtainaccesstoken to get an access token
102
103 Level: intermediate
104
105 .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscURLShorten(), PetscGlobusUpload()
106
107 @*/
PetscGlobusAuthorize(MPI_Comm comm,char access_token[],size_t tokensize)108 PetscErrorCode PetscGlobusAuthorize(MPI_Comm comm,char access_token[],size_t tokensize)
109 {
110 SSL_CTX *ctx;
111 SSL *ssl;
112 int sock;
113 PetscErrorCode ierr;
114 char buff[8*1024],*ptr,head[1024];
115 PetscMPIInt rank;
116 size_t len;
117 PetscBool found;
118
119 PetscFunctionBegin;
120 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
121 if (!rank) {
122 if (!isatty(fileno(PETSC_STDOUT))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Requires users input/output");
123 ierr = PetscPrintf(comm,"Enter globus username:");CHKERRQ(ierr);
124 ptr = fgets(buff, 1024, stdin);
125 if (!ptr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
126 ierr = PetscStrlen(buff,&len);CHKERRQ(ierr);
127 buff[len-1] = ':'; /* remove carriage return at end of line */
128
129 ierr = PetscPrintf(comm,"Enter globus password:");CHKERRQ(ierr);
130 ptr = fgets(buff+len, 1024-len, stdin);
131 if (!ptr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
132 ierr = PetscStrlen(buff,&len);CHKERRQ(ierr);
133 buff[len-1] = '\0'; /* remove carriage return at end of line */
134 ierr = PetscStrcpy(head,"Authorization: Basic ");CHKERRQ(ierr);
135 ierr = base64_encode((const unsigned char*)buff,(unsigned char*)(head+21),sizeof(head)-21);CHKERRQ(ierr);
136 ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr);
137
138 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr);
139 ierr = PetscHTTPSConnect("nexus.api.globusonline.org",443,ctx,&sock,&ssl);CHKERRQ(ierr);
140 ierr = PetscHTTPSRequest("GET","nexus.api.globusonline.org/goauth/token?grant_type=client_credentials",head,"application/x-www-form-urlencoded",NULL,ssl,buff,sizeof(buff));CHKERRQ(ierr);
141 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr);
142 close(sock);
143
144 ierr = PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);CHKERRQ(ierr);
145 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return access token");
146
147 ierr = PetscPrintf(comm,"Here is your Globus access token, save it in a save place, in the future you can run PETSc\n");CHKERRQ(ierr);
148 ierr = PetscPrintf(comm,"programs with the option -globus_access_token %s\n",access_token);CHKERRQ(ierr);
149 ierr = PetscPrintf(comm,"to access Globus automatically\n");CHKERRQ(ierr);
150 }
151 PetscFunctionReturn(0);
152 }
153
154
155 /*@C
156 PetscGlobusGetTransfers - Get a record of current transfers requested from Globus
157
158 Not collective, only the first process in MPI_Comm does anything
159
160 Input Parameters:
161 + comm - the MPI communicator
162 . access_token - Globus access token, if NULL will check in options database for -globus_access_token XXX otherwise
163 will call PetscGlobusAuthorize().
164 - buffsize - size of the buffer
165
166 Output Parameters:
167 . buff - location to put Globus information
168
169 Level: intermediate
170
171 .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscURLShorten(), PetscGlobusUpload(), PetscGlobusAuthorize()
172
173 @*/
PetscGlobusGetTransfers(MPI_Comm comm,const char access_token[],char buff[],size_t buffsize)174 PetscErrorCode PetscGlobusGetTransfers(MPI_Comm comm,const char access_token[],char buff[],size_t buffsize)
175 {
176 SSL_CTX *ctx;
177 SSL *ssl;
178 int sock;
179 PetscErrorCode ierr;
180 char head[4096];
181 PetscMPIInt rank;
182
183 PetscFunctionBegin;
184 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
185 if (!rank) {
186 ierr = PetscStrcpy(head,"Authorization : Globus-Goauthtoken ");CHKERRQ(ierr);
187 if (access_token) {
188 ierr = PetscStrcat(head,access_token);CHKERRQ(ierr);
189 } else {
190 PetscBool set;
191 char accesstoken[4096];
192 ierr = PetscOptionsGetString(NULL,NULL,"-globus_access_token",accesstoken,sizeof(accesstoken),&set);CHKERRQ(ierr);
193 if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Pass in Globus accesstoken or use -globus_access_token XXX");
194 ierr = PetscStrcat(head,accesstoken);CHKERRQ(ierr);
195 }
196 ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr);
197
198 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr);
199 ierr = PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);CHKERRQ(ierr);
200 ierr = PetscHTTPSRequest("GET","transfer.api.globusonline.org/v0.10/tasksummary",head,"application/json",NULL,ssl,buff,buffsize);CHKERRQ(ierr);
201 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr);
202 close(sock);
203 }
204 PetscFunctionReturn(0);
205 }
206
207 /*@C
208 PetscGlobusUpload - Loads a file to Globus
209
210 Not collective, only the first process in the MPI_Comm uploads the file
211
212 Input Parameters:
213 + comm - MPI communicator
214 . access_token - obtained with PetscGlobusAuthorize(), pass NULL to use -globus_access_token XXX from the PETSc database
215 - filename - file to upload
216
217 Options Database:
218 . -globus_access_token XXX
219
220 Level: intermediate
221
222 .seealso: PetscURLShorten(), PetscGoogleDriveAuthorize(), PetscGoogleDriveRefresh(), PetscGlobusAuthorize()
223
224 @*/
PetscGlobusUpload(MPI_Comm comm,const char access_token[],const char filename[])225 PetscErrorCode PetscGlobusUpload(MPI_Comm comm,const char access_token[],const char filename[])
226 {
227 SSL_CTX *ctx;
228 SSL *ssl;
229 int sock;
230 PetscErrorCode ierr;
231 char head[4096],buff[8*1024],body[4096],submission_id[4096];
232 PetscMPIInt rank;
233 PetscBool flg,found;
234
235 PetscFunctionBegin;
236 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
237 if (!rank) {
238 ierr = PetscTestFile(filename,'r',&flg);CHKERRQ(ierr);
239 if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to find file: %s",filename);
240
241 ierr = PetscStrcpy(head,"Authorization : Globus-Goauthtoken ");CHKERRQ(ierr);
242 if (access_token) {
243 ierr = PetscStrcat(head,access_token);CHKERRQ(ierr);
244 } else {
245 PetscBool set;
246 char accesstoken[4096];
247 ierr = PetscOptionsGetString(NULL,NULL,"-globus_access_token",accesstoken,sizeof(accesstoken),&set);CHKERRQ(ierr);
248 if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Pass in Globus accesstoken or use -globus_access_token XXX");
249 ierr = PetscStrcat(head,accesstoken);CHKERRQ(ierr);
250 }
251 ierr = PetscStrcat(head,"\r\n");CHKERRQ(ierr);
252
253 /* Get Globus submission id */
254 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr);
255 ierr = PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);CHKERRQ(ierr);
256 ierr = PetscHTTPSRequest("GET","transfer.api.globusonline.org/v0.10/submission_id",head,"application/json",NULL,ssl,buff,sizeof(buff));CHKERRQ(ierr);
257 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr);
258 close(sock);
259 ierr = PetscPullJSONValue(buff,"value",submission_id,sizeof(submission_id),&found);CHKERRQ(ierr);
260 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return submission id");
261
262 /* build JSON body of transfer request */
263 ierr = PetscStrcpy(body,"{");CHKERRQ(ierr);
264 ierr = PetscPushJSONValue(body,"submission_id",submission_id,sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
265 ierr = PetscPushJSONValue(body,"DATA_TYPE","transfer",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
266 ierr = PetscPushJSONValue(body,"sync_level","null",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
267 ierr = PetscPushJSONValue(body,"source_endpoint","barryfsmith#MacBookPro",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
268 ierr = PetscPushJSONValue(body,"label","PETSc transfer label",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
269 ierr = PetscPushJSONValue(body,"length","1",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
270 ierr = PetscPushJSONValue(body,"destination_endpoint","mcs#home",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
271
272 ierr = PetscStrcat(body,"\"DATA\": [ {");CHKERRQ(ierr);
273 ierr = PetscPushJSONValue(body,"source_path","/~/FEM_GPU.pdf",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
274 ierr = PetscPushJSONValue(body,"destination_path","/~/FEM_GPU.pdf",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
275 ierr = PetscPushJSONValue(body,"verify_size","null",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
276 ierr = PetscPushJSONValue(body,"recursive","false",sizeof(body));CHKERRQ(ierr); ierr = PetscStrcat(body,",");CHKERRQ(ierr);
277 ierr = PetscPushJSONValue(body,"DATA_TYPE","transfer_item",sizeof(body));CHKERRQ(ierr);
278 ierr = PetscStrcat(body,"} ] }");CHKERRQ(ierr);
279
280 ierr = PetscSSLInitializeContext(&ctx);CHKERRQ(ierr);
281 ierr = PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);CHKERRQ(ierr);
282 ierr = PetscHTTPSRequest("POST","transfer.api.globusonline.org/v0.10/transfer",head,"application/json",body,ssl,buff,sizeof(buff));CHKERRQ(ierr);
283 ierr = PetscSSLDestroyContext(ctx);CHKERRQ(ierr);
284 close(sock);
285 ierr = PetscPullJSONValue(buff,"code",submission_id,sizeof(submission_id),&found);CHKERRQ(ierr);
286 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return code on transfer");
287 ierr = PetscStrcmp(submission_id,"Accepted",&found);CHKERRQ(ierr);
288 if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not accept transfer");
289 }
290 PetscFunctionReturn(0);
291 }
292
293
294