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