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