Actual source code: globus.c
petsc-3.12.5 2020-03-29
1: #include <petscwebclient.h>
2: #pragma clang diagnostic ignored "-Wdeprecated-declarations"
3: #pragma gcc diagnostic ignored "-Wdeprecated-declarations"
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', '+', '/'};
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;
25: PetscStrlen((const char*)data,&input_length);
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");
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;
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: return(0);
43: }
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;
51: size_t input_length,output_length;
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: }
59: PetscStrlen((const char*)data,&input_length);
60: if (input_length % 4 != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Input length must be divisible by 4");
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");
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);
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: return(0);
80: }
82: #if defined(PETSC_HAVE_UNISTD_H)
83: #include <unistd.h>
84: #endif
86: /*@C
87: PetscGlobusAuthorize - Get an access token allowing PETSc applications to make Globus file transfer requests
89: Not collective, only the first process in MPI_Comm does anything
91: Input Parameters:
92: + comm - the MPI communicator
93: - tokensize - size of the token array
95: Output Parameters:
96: . access_token - can be used with PetscGlobusUpLoad() for 30 days
98: Notes:
99: This call requires stdout and stdin access from process 0 on the MPI communicator
101: You can run src/sys/webclient/examples/tutorials/globusobtainaccesstoken to get an access token
103: Level: intermediate
105: .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscURLShorten(), PetscGlobusUpload()
107: @*/
108: PetscErrorCode PetscGlobusAuthorize(MPI_Comm comm,char access_token[],size_t tokensize)
109: {
110: SSL_CTX *ctx;
111: SSL *ssl;
112: int sock;
114: char buff[8*1024],*ptr,head[1024];
115: PetscMPIInt rank;
116: size_t len;
117: PetscBool found;
120: MPI_Comm_rank(comm,&rank);
121: if (!rank) {
122: if (!isatty(fileno(PETSC_STDOUT))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Requires users input/output");
123: PetscPrintf(comm,"Enter globus username:");
124: ptr = fgets(buff, 1024, stdin);
125: if (!ptr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
126: PetscStrlen(buff,&len);
127: buff[len-1] = ':'; /* remove carriage return at end of line */
129: PetscPrintf(comm,"Enter globus password:");
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: PetscStrlen(buff,&len);
133: buff[len-1] = '\0'; /* remove carriage return at end of line */
134: PetscStrcpy(head,"Authorization: Basic ");
135: base64_encode((const unsigned char*)buff,(unsigned char*)(head+21),sizeof(head)-21);
136: PetscStrcat(head,"\r\n");
138: PetscSSLInitializeContext(&ctx);
139: PetscHTTPSConnect("nexus.api.globusonline.org",443,ctx,&sock,&ssl);
140: PetscHTTPSRequest("GET","nexus.api.globusonline.org/goauth/token?grant_type=client_credentials",head,"application/x-www-form-urlencoded",NULL,ssl,buff,sizeof(buff));
141: PetscSSLDestroyContext(ctx);
142: close(sock);
144: PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);
145: if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return access token");
147: PetscPrintf(comm,"Here is your Globus access token, save it in a save place, in the future you can run PETSc\n");
148: PetscPrintf(comm,"programs with the option -globus_access_token %s\n",access_token);
149: PetscPrintf(comm,"to access Globus automatically\n");
150: }
151: return(0);
152: }
155: /*@C
156: PetscGlobusGetTransfers - Get a record of current transfers requested from Globus
158: Not collective, only the first process in MPI_Comm does anything
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
166: Output Parameters:
167: . buff - location to put Globus information
169: Level: intermediate
171: .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscURLShorten(), PetscGlobusUpload(), PetscGlobusAuthorize()
173: @*/
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;
180: char head[4096];
181: PetscMPIInt rank;
184: MPI_Comm_rank(comm,&rank);
185: if (!rank) {
186: PetscStrcpy(head,"Authorization : Globus-Goauthtoken ");
187: if (access_token) {
188: PetscStrcat(head,access_token);
189: } else {
190: PetscBool set;
191: char accesstoken[4096];
192: PetscOptionsGetString(NULL,NULL,"-globus_access_token",accesstoken,sizeof(accesstoken),&set);
193: if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Pass in Globus accesstoken or use -globus_access_token XXX");
194: PetscStrcat(head,accesstoken);
195: }
196: PetscStrcat(head,"\r\n");
198: PetscSSLInitializeContext(&ctx);
199: PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);
200: PetscHTTPSRequest("GET","transfer.api.globusonline.org/v0.10/tasksummary",head,"application/json",NULL,ssl,buff,buffsize);
201: PetscSSLDestroyContext(ctx);
202: close(sock);
203: }
204: return(0);
205: }
207: /*@C
208: PetscGlobusUpload - Loads a file to Globus
210: Not collective, only the first process in the MPI_Comm uploads the file
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
217: Options Database:
218: . -globus_access_token XXX
220: Level: intermediate
222: .seealso: PetscURLShorten(), PetscGoogleDriveAuthorize(), PetscGoogleDriveRefresh(), PetscGlobusAuthorize()
224: @*/
225: PetscErrorCode PetscGlobusUpload(MPI_Comm comm,const char access_token[],const char filename[])
226: {
227: SSL_CTX *ctx;
228: SSL *ssl;
229: int sock;
231: char head[4096],buff[8*1024],body[4096],submission_id[4096];
232: PetscMPIInt rank;
233: PetscBool flg,found;
236: MPI_Comm_rank(comm,&rank);
237: if (!rank) {
238: PetscTestFile(filename,'r',&flg);
239: if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to find file: %s",filename);
241: PetscStrcpy(head,"Authorization : Globus-Goauthtoken ");
242: if (access_token) {
243: PetscStrcat(head,access_token);
244: } else {
245: PetscBool set;
246: char accesstoken[4096];
247: PetscOptionsGetString(NULL,NULL,"-globus_access_token",accesstoken,sizeof(accesstoken),&set);
248: if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Pass in Globus accesstoken or use -globus_access_token XXX");
249: PetscStrcat(head,accesstoken);
250: }
251: PetscStrcat(head,"\r\n");
253: /* Get Globus submission id */
254: PetscSSLInitializeContext(&ctx);
255: PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);
256: PetscHTTPSRequest("GET","transfer.api.globusonline.org/v0.10/submission_id",head,"application/json",NULL,ssl,buff,sizeof(buff));
257: PetscSSLDestroyContext(ctx);
258: close(sock);
259: PetscPullJSONValue(buff,"value",submission_id,sizeof(submission_id),&found);
260: if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return submission id");
262: /* build JSON body of transfer request */
263: PetscStrcpy(body,"{");
264: PetscPushJSONValue(body,"submission_id",submission_id,sizeof(body)); PetscStrcat(body,",");
265: PetscPushJSONValue(body,"DATA_TYPE","transfer",sizeof(body)); PetscStrcat(body,",");
266: PetscPushJSONValue(body,"sync_level","null",sizeof(body)); PetscStrcat(body,",");
267: PetscPushJSONValue(body,"source_endpoint","barryfsmith#MacBookPro",sizeof(body)); PetscStrcat(body,",");
268: PetscPushJSONValue(body,"label","PETSc transfer label",sizeof(body)); PetscStrcat(body,",");
269: PetscPushJSONValue(body,"length","1",sizeof(body)); PetscStrcat(body,",");
270: PetscPushJSONValue(body,"destination_endpoint","mcs#home",sizeof(body)); PetscStrcat(body,",");
272: PetscStrcat(body,"\"DATA\": [ {");
273: PetscPushJSONValue(body,"source_path","/~/FEM_GPU.pdf",sizeof(body)); PetscStrcat(body,",");
274: PetscPushJSONValue(body,"destination_path","/~/FEM_GPU.pdf",sizeof(body)); PetscStrcat(body,",");
275: PetscPushJSONValue(body,"verify_size","null",sizeof(body)); PetscStrcat(body,",");
276: PetscPushJSONValue(body,"recursive","false",sizeof(body)); PetscStrcat(body,",");
277: PetscPushJSONValue(body,"DATA_TYPE","transfer_item",sizeof(body));
278: PetscStrcat(body,"} ] }");
280: PetscSSLInitializeContext(&ctx);
281: PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);
282: PetscHTTPSRequest("POST","transfer.api.globusonline.org/v0.10/transfer",head,"application/json",body,ssl,buff,sizeof(buff));
283: PetscSSLDestroyContext(ctx);
284: close(sock);
285: PetscPullJSONValue(buff,"code",submission_id,sizeof(submission_id),&found);
286: if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return code on transfer");
287: PetscStrcmp(submission_id,"Accepted",&found);
288: if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not accept transfer");
289: }
290: return(0);
291: }