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 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 CHKERRQ(PetscStrlen((const char*)data,&input_length)); 26 output_length = 4 * ((input_length + 2) / 3); 27 PetscCheckFalse(output_length > len,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 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 CHKERRQ(PetscStrlen((const char*)data,&input_length)); 60 PetscCheckFalse(input_length % 4 != 0,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 PetscCheckFalse(output_length > length,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 @*/ 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 CHKERRMPI(MPI_Comm_rank(comm,&rank)); 121 if (rank == 0) { 122 PetscCheckFalse(!isatty(fileno(PETSC_STDOUT)),PETSC_COMM_SELF,PETSC_ERR_USER,"Requires users input/output"); 123 CHKERRQ(PetscPrintf(comm,"Enter globus username:")); 124 ptr = fgets(buff, 1024, stdin); 125 PetscCheck(ptr,PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno); 126 CHKERRQ(PetscStrlen(buff,&len)); 127 buff[len-1] = ':'; /* remove carriage return at end of line */ 128 129 CHKERRQ(PetscPrintf(comm,"Enter globus password:")); 130 ptr = fgets(buff+len, 1024-len, stdin); 131 PetscCheck(ptr,PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno); 132 CHKERRQ(PetscStrlen(buff,&len)); 133 buff[len-1] = '\0'; /* remove carriage return at end of line */ 134 CHKERRQ(PetscStrcpy(head,"Authorization: Basic ")); 135 CHKERRQ(base64_encode((const unsigned char*)buff,(unsigned char*)(head+21),sizeof(head)-21)); 136 CHKERRQ(PetscStrcat(head,"\r\n")); 137 138 CHKERRQ(PetscSSLInitializeContext(&ctx)); 139 CHKERRQ(PetscHTTPSConnect("nexus.api.globusonline.org",443,ctx,&sock,&ssl)); 140 CHKERRQ(PetscHTTPSRequest("GET","nexus.api.globusonline.org/goauth/token?grant_type=client_credentials",head,"application/x-www-form-urlencoded",NULL,ssl,buff,sizeof(buff))); 141 CHKERRQ(PetscSSLDestroyContext(ctx)); 142 close(sock); 143 144 CHKERRQ(PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found)); 145 PetscCheck(found,PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return access token"); 146 147 CHKERRQ(PetscPrintf(comm,"Here is your Globus access token, save it in a save place, in the future you can run PETSc\n")); 148 CHKERRQ(PetscPrintf(comm,"programs with the option -globus_access_token %s\n",access_token)); 149 CHKERRQ(PetscPrintf(comm,"to access Globus automatically\n")); 150 } 151 PetscFunctionReturn(0); 152 } 153 154 /*@C 155 PetscGlobusGetTransfers - Get a record of current transfers requested from Globus 156 157 Not collective, only the first process in MPI_Comm does anything 158 159 Input Parameters: 160 + comm - the MPI communicator 161 . access_token - Globus access token, if NULL will check in options database for -globus_access_token XXX otherwise 162 will call PetscGlobusAuthorize(). 163 - buffsize - size of the buffer 164 165 Output Parameters: 166 . buff - location to put Globus information 167 168 Level: intermediate 169 170 .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscURLShorten(), PetscGlobusUpload(), PetscGlobusAuthorize() 171 172 @*/ 173 PetscErrorCode PetscGlobusGetTransfers(MPI_Comm comm,const char access_token[],char buff[],size_t buffsize) 174 { 175 SSL_CTX *ctx; 176 SSL *ssl; 177 int sock; 178 PetscErrorCode ierr; 179 char head[4096]; 180 PetscMPIInt rank; 181 182 PetscFunctionBegin; 183 CHKERRMPI(MPI_Comm_rank(comm,&rank)); 184 if (rank == 0) { 185 CHKERRQ(PetscStrcpy(head,"Authorization : Globus-Goauthtoken ")); 186 if (access_token) { 187 CHKERRQ(PetscStrcat(head,access_token)); 188 } else { 189 PetscBool set; 190 char accesstoken[4096]; 191 CHKERRQ(PetscOptionsGetString(NULL,NULL,"-globus_access_token",accesstoken,sizeof(accesstoken),&set)); 192 PetscCheck(set,PETSC_COMM_SELF,PETSC_ERR_USER,"Pass in Globus accesstoken or use -globus_access_token XXX"); 193 CHKERRQ(PetscStrcat(head,accesstoken)); 194 } 195 CHKERRQ(PetscStrcat(head,"\r\n")); 196 197 CHKERRQ(PetscSSLInitializeContext(&ctx)); 198 CHKERRQ(PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl)); 199 CHKERRQ(PetscHTTPSRequest("GET","transfer.api.globusonline.org/v0.10/tasksummary",head,"application/json",NULL,ssl,buff,buffsize)); 200 CHKERRQ(PetscSSLDestroyContext(ctx)); 201 close(sock); 202 } 203 PetscFunctionReturn(0); 204 } 205 206 /*@C 207 PetscGlobusUpload - Loads a file to Globus 208 209 Not collective, only the first process in the MPI_Comm uploads the file 210 211 Input Parameters: 212 + comm - MPI communicator 213 . access_token - obtained with PetscGlobusAuthorize(), pass NULL to use -globus_access_token XXX from the PETSc database 214 - filename - file to upload 215 216 Options Database: 217 . -globus_access_token XXX - the Globus token 218 219 Level: intermediate 220 221 .seealso: PetscURLShorten(), PetscGoogleDriveAuthorize(), PetscGoogleDriveRefresh(), PetscGlobusAuthorize() 222 223 @*/ 224 PetscErrorCode PetscGlobusUpload(MPI_Comm comm,const char access_token[],const char filename[]) 225 { 226 SSL_CTX *ctx; 227 SSL *ssl; 228 int sock; 229 PetscErrorCode ierr; 230 char head[4096],buff[8*1024],body[4096],submission_id[4096]; 231 PetscMPIInt rank; 232 PetscBool flg,found; 233 234 PetscFunctionBegin; 235 CHKERRMPI(MPI_Comm_rank(comm,&rank)); 236 if (rank == 0) { 237 CHKERRQ(PetscTestFile(filename,'r',&flg)); 238 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to find file: %s",filename); 239 240 CHKERRQ(PetscStrcpy(head,"Authorization : Globus-Goauthtoken ")); 241 if (access_token) { 242 CHKERRQ(PetscStrcat(head,access_token)); 243 } else { 244 PetscBool set; 245 char accesstoken[4096]; 246 CHKERRQ(PetscOptionsGetString(NULL,NULL,"-globus_access_token",accesstoken,sizeof(accesstoken),&set)); 247 PetscCheck(set,PETSC_COMM_SELF,PETSC_ERR_USER,"Pass in Globus accesstoken or use -globus_access_token XXX"); 248 CHKERRQ(PetscStrcat(head,accesstoken)); 249 } 250 CHKERRQ(PetscStrcat(head,"\r\n")); 251 252 /* Get Globus submission id */ 253 CHKERRQ(PetscSSLInitializeContext(&ctx)); 254 CHKERRQ(PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl)); 255 CHKERRQ(PetscHTTPSRequest("GET","transfer.api.globusonline.org/v0.10/submission_id",head,"application/json",NULL,ssl,buff,sizeof(buff))); 256 CHKERRQ(PetscSSLDestroyContext(ctx)); 257 close(sock); 258 CHKERRQ(PetscPullJSONValue(buff,"value",submission_id,sizeof(submission_id),&found)); 259 PetscCheck(found,PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return submission id"); 260 261 /* build JSON body of transfer request */ 262 CHKERRQ(PetscStrcpy(body,"{")); 263 CHKERRQ(PetscPushJSONValue(body,"submission_id",submission_id,sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 264 CHKERRQ(PetscPushJSONValue(body,"DATA_TYPE","transfer",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 265 CHKERRQ(PetscPushJSONValue(body,"sync_level","null",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 266 CHKERRQ(PetscPushJSONValue(body,"source_endpoint","barryfsmith#MacBookPro",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 267 CHKERRQ(PetscPushJSONValue(body,"label","PETSc transfer label",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 268 CHKERRQ(PetscPushJSONValue(body,"length","1",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 269 CHKERRQ(PetscPushJSONValue(body,"destination_endpoint","mcs#home",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 270 271 CHKERRQ(PetscStrcat(body,"\"DATA\": [ {")); 272 CHKERRQ(PetscPushJSONValue(body,"source_path","/~/FEM_GPU.pdf",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 273 CHKERRQ(PetscPushJSONValue(body,"destination_path","/~/FEM_GPU.pdf",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 274 CHKERRQ(PetscPushJSONValue(body,"verify_size","null",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 275 CHKERRQ(PetscPushJSONValue(body,"recursive","false",sizeof(body))); CHKERRQ(PetscStrcat(body,",")); 276 CHKERRQ(PetscPushJSONValue(body,"DATA_TYPE","transfer_item",sizeof(body))); 277 CHKERRQ(PetscStrcat(body,"} ] }")); 278 279 CHKERRQ(PetscSSLInitializeContext(&ctx)); 280 CHKERRQ(PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl)); 281 CHKERRQ(PetscHTTPSRequest("POST","transfer.api.globusonline.org/v0.10/transfer",head,"application/json",body,ssl,buff,sizeof(buff))); 282 CHKERRQ(PetscSSLDestroyContext(ctx)); 283 close(sock); 284 CHKERRQ(PetscPullJSONValue(buff,"code",submission_id,sizeof(submission_id),&found)); 285 PetscCheck(found,PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return code on transfer"); 286 CHKERRQ(PetscStrcmp(submission_id,"Accepted",&found)); 287 PetscCheck(found,PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not accept transfer"); 288 } 289 PetscFunctionReturn(0); 290 } 291