Actual source code: globus.c

petsc-3.14.6 2021-03-30
Report Typos and Errors
  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/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: }