xref: /petsc/src/sys/webclient/globus.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
15dc0f0a4SBarry Smith #include <petscwebclient.h>
2bb04b57dSBarry Smith #pragma clang diagnostic ignored "-Wdeprecated-declarations"
345e40e47SBarry Smith #pragma gcc diagnostic   ignored "-Wdeprecated-declarations"
45dc0f0a4SBarry Smith 
55dc0f0a4SBarry Smith /*
65dc0f0a4SBarry Smith     Encodes and decodes from MIME Base64
75dc0f0a4SBarry Smith */
8*9371c9d4SSatish Balay 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*9371c9d4SSatish Balay                                 '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', '+', '/'};
105dc0f0a4SBarry Smith 
11*9371c9d4SSatish Balay static PetscErrorCode base64_encode(const unsigned char *data, unsigned char *encoded_data, size_t len) {
12f5b927afSBarry Smith   static size_t mod_table[] = {0, 2, 1};
13f5b927afSBarry Smith   size_t        i, j;
145dc0f0a4SBarry Smith   size_t        input_length, output_length;
155dc0f0a4SBarry Smith 
165dc0f0a4SBarry Smith   PetscFunctionBegin;
179566063dSJacob Faibussowitsch   PetscCall(PetscStrlen((const char *)data, &input_length));
185dc0f0a4SBarry Smith   output_length = 4 * ((input_length + 2) / 3);
1908401ef6SPierre Jolivet   PetscCheck(output_length <= len, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Output length not large enough");
205dc0f0a4SBarry Smith 
215dc0f0a4SBarry Smith   for (i = 0, j = 0; i < input_length;) {
225dc0f0a4SBarry Smith     uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
235dc0f0a4SBarry Smith     uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
245dc0f0a4SBarry Smith     uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
255dc0f0a4SBarry Smith     uint32_t triple  = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
265dc0f0a4SBarry Smith 
275dc0f0a4SBarry Smith     encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
285dc0f0a4SBarry Smith     encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
295dc0f0a4SBarry Smith     encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
305dc0f0a4SBarry Smith     encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
315dc0f0a4SBarry Smith   }
325dc0f0a4SBarry Smith   encoded_data[j] = 0;
335dc0f0a4SBarry Smith   for (i = 0; i < mod_table[input_length % 3]; i++) encoded_data[output_length - 1 - i] = '=';
345dc0f0a4SBarry Smith   PetscFunctionReturn(0);
355dc0f0a4SBarry Smith }
365dc0f0a4SBarry Smith 
37*9371c9d4SSatish Balay PETSC_UNUSED static PetscErrorCode base64_decode(const unsigned char *data, unsigned char *decoded_data, size_t length) {
385dc0f0a4SBarry Smith   static char decoding_table[257];
395dc0f0a4SBarry Smith   static int  decode_table_built = 0;
40c1f4622dSBarry Smith   size_t      i, j;
415dc0f0a4SBarry Smith   size_t      input_length, output_length;
425dc0f0a4SBarry Smith 
435dc0f0a4SBarry Smith   PetscFunctionBegin;
445dc0f0a4SBarry Smith   if (!decode_table_built) {
455dc0f0a4SBarry Smith     for (i = 0; i < 64; i++) decoding_table[(unsigned char)encoding_table[i]] = i;
465dc0f0a4SBarry Smith     decode_table_built = 1;
475dc0f0a4SBarry Smith   }
485dc0f0a4SBarry Smith 
499566063dSJacob Faibussowitsch   PetscCall(PetscStrlen((const char *)data, &input_length));
5008401ef6SPierre Jolivet   PetscCheck(input_length % 4 == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input length must be divisible by 4");
515dc0f0a4SBarry Smith 
525dc0f0a4SBarry Smith   output_length = input_length / 4 * 3;
535dc0f0a4SBarry Smith   if (data[input_length - 1] == '=') (output_length)--;
545dc0f0a4SBarry Smith   if (data[input_length - 2] == '=') (output_length)--;
5508401ef6SPierre Jolivet   PetscCheck(output_length <= length, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Output length too shore");
565dc0f0a4SBarry Smith 
575dc0f0a4SBarry Smith   for (i = 0, j = 0; i < input_length;) {
585dc0f0a4SBarry Smith     uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
595dc0f0a4SBarry Smith     uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
605dc0f0a4SBarry Smith     uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
615dc0f0a4SBarry Smith     uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
625dc0f0a4SBarry Smith     uint32_t triple   = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
635dc0f0a4SBarry Smith 
645dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
655dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
665dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
675dc0f0a4SBarry Smith   }
685dc0f0a4SBarry Smith   decoded_data[j] = 0;
695dc0f0a4SBarry Smith   PetscFunctionReturn(0);
705dc0f0a4SBarry Smith }
715dc0f0a4SBarry Smith 
725dc0f0a4SBarry Smith #if defined(PETSC_HAVE_UNISTD_H)
735dc0f0a4SBarry Smith #include <unistd.h>
745dc0f0a4SBarry Smith #endif
755dc0f0a4SBarry Smith 
765dc0f0a4SBarry Smith /*@C
775dc0f0a4SBarry Smith      PetscGlobusAuthorize - Get an access token allowing PETSc applications to make Globus file transfer requests
785dc0f0a4SBarry Smith 
795dc0f0a4SBarry Smith    Not collective, only the first process in MPI_Comm does anything
805dc0f0a4SBarry Smith 
815dc0f0a4SBarry Smith    Input Parameters:
825dc0f0a4SBarry Smith +  comm - the MPI communicator
835dc0f0a4SBarry Smith -  tokensize - size of the token array
845dc0f0a4SBarry Smith 
855dc0f0a4SBarry Smith    Output Parameters:
865dc0f0a4SBarry Smith .  access_token - can be used with PetscGlobusUpLoad() for 30 days
875dc0f0a4SBarry Smith 
8895452b02SPatrick Sanan    Notes:
8995452b02SPatrick Sanan     This call requires stdout and stdin access from process 0 on the MPI communicator
905dc0f0a4SBarry Smith 
91c4762a1bSJed Brown    You can run src/sys/webclient/tutorials/globusobtainaccesstoken to get an access token
925dc0f0a4SBarry Smith 
932b26979fSBarry Smith    Level: intermediate
942b26979fSBarry Smith 
95db781477SPatrick Sanan .seealso: `PetscGoogleDriveRefresh()`, `PetscGoogleDriveUpload()`, `PetscURLShorten()`, `PetscGlobusUpload()`
965dc0f0a4SBarry Smith 
975dc0f0a4SBarry Smith @*/
98*9371c9d4SSatish Balay PetscErrorCode PetscGlobusAuthorize(MPI_Comm comm, char access_token[], size_t tokensize) {
995dc0f0a4SBarry Smith   SSL_CTX    *ctx;
1005dc0f0a4SBarry Smith   SSL        *ssl;
1015dc0f0a4SBarry Smith   int         sock;
1025dc0f0a4SBarry Smith   char        buff[8 * 1024], *ptr, head[1024];
1035dc0f0a4SBarry Smith   PetscMPIInt rank;
1045dc0f0a4SBarry Smith   size_t      len;
1055dc0f0a4SBarry Smith   PetscBool   found;
1065dc0f0a4SBarry Smith 
1075dc0f0a4SBarry Smith   PetscFunctionBegin;
1089566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
109dd400576SPatrick Sanan   if (rank == 0) {
110cc73adaaSBarry Smith     PetscCheck(isatty(fileno(PETSC_STDOUT)), PETSC_COMM_SELF, PETSC_ERR_USER, "Requires users input/output");
1119566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Enter globus username:"));
1125dc0f0a4SBarry Smith     ptr = fgets(buff, 1024, stdin);
11328b400f6SJacob Faibussowitsch     PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
1149566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(buff, &len));
1155dc0f0a4SBarry Smith     buff[len - 1] = ':'; /* remove carriage return at end of line */
1165dc0f0a4SBarry Smith 
1179566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Enter globus password:"));
1185dc0f0a4SBarry Smith     ptr = fgets(buff + len, 1024 - len, stdin);
11928b400f6SJacob Faibussowitsch     PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
1209566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(buff, &len));
1215dc0f0a4SBarry Smith     buff[len - 1] = '\0'; /* remove carriage return at end of line */
1229566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(head, "Authorization: Basic "));
1239566063dSJacob Faibussowitsch     PetscCall(base64_encode((const unsigned char *)buff, (unsigned char *)(head + 21), sizeof(head) - 21));
1249566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(head, "\r\n"));
1255dc0f0a4SBarry Smith 
1269566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1279566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("nexus.api.globusonline.org", 443, ctx, &sock, &ssl));
1289566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("GET", "nexus.api.globusonline.org/goauth/token?grant_type=client_credentials", head, "application/x-www-form-urlencoded", NULL, ssl, buff, sizeof(buff)));
1299566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1305dc0f0a4SBarry Smith     close(sock);
1315dc0f0a4SBarry Smith 
1329566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
13328b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return access token");
1345dc0f0a4SBarry Smith 
1359566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Here is your Globus access token, save it in a save place, in the future you can run PETSc\n"));
1369566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -globus_access_token %s\n", access_token));
1379566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Globus automatically\n"));
1385dc0f0a4SBarry Smith   }
1395dc0f0a4SBarry Smith   PetscFunctionReturn(0);
1405dc0f0a4SBarry Smith }
1415dc0f0a4SBarry Smith 
1425dc0f0a4SBarry Smith /*@C
1435dc0f0a4SBarry Smith      PetscGlobusGetTransfers - Get a record of current transfers requested from Globus
1445dc0f0a4SBarry Smith 
1455dc0f0a4SBarry Smith    Not collective, only the first process in MPI_Comm does anything
1465dc0f0a4SBarry Smith 
1475dc0f0a4SBarry Smith    Input Parameters:
1485dc0f0a4SBarry Smith +  comm - the MPI communicator
1495dc0f0a4SBarry Smith .  access_token - Globus access token, if NULL will check in options database for -globus_access_token XXX otherwise
1505dc0f0a4SBarry Smith                   will call PetscGlobusAuthorize().
1515dc0f0a4SBarry Smith -  buffsize - size of the buffer
1525dc0f0a4SBarry Smith 
1535dc0f0a4SBarry Smith    Output Parameters:
1545dc0f0a4SBarry Smith .  buff - location to put Globus information
1555dc0f0a4SBarry Smith 
1562b26979fSBarry Smith    Level: intermediate
1572b26979fSBarry Smith 
158db781477SPatrick Sanan .seealso: `PetscGoogleDriveRefresh()`, `PetscGoogleDriveUpload()`, `PetscURLShorten()`, `PetscGlobusUpload()`, `PetscGlobusAuthorize()`
1595dc0f0a4SBarry Smith 
1605dc0f0a4SBarry Smith @*/
161*9371c9d4SSatish Balay PetscErrorCode PetscGlobusGetTransfers(MPI_Comm comm, const char access_token[], char buff[], size_t buffsize) {
1625dc0f0a4SBarry Smith   SSL_CTX    *ctx;
1635dc0f0a4SBarry Smith   SSL        *ssl;
1645dc0f0a4SBarry Smith   int         sock;
1655dc0f0a4SBarry Smith   char        head[4096];
1665dc0f0a4SBarry Smith   PetscMPIInt rank;
1675dc0f0a4SBarry Smith 
1685dc0f0a4SBarry Smith   PetscFunctionBegin;
1699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
170dd400576SPatrick Sanan   if (rank == 0) {
1719566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(head, "Authorization : Globus-Goauthtoken "));
1725dc0f0a4SBarry Smith     if (access_token) {
1739566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(head, access_token));
1745dc0f0a4SBarry Smith     } else {
1755dc0f0a4SBarry Smith       PetscBool set;
1765dc0f0a4SBarry Smith       char      accesstoken[4096];
1779566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-globus_access_token", accesstoken, sizeof(accesstoken), &set));
17828b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_USER, "Pass in Globus accesstoken or use -globus_access_token XXX");
1799566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(head, accesstoken));
1805dc0f0a4SBarry Smith     }
1819566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(head, "\r\n"));
1825dc0f0a4SBarry Smith 
1839566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1849566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
1859566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("GET", "transfer.api.globusonline.org/v0.10/tasksummary", head, "application/json", NULL, ssl, buff, buffsize));
1869566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1875dc0f0a4SBarry Smith     close(sock);
1885dc0f0a4SBarry Smith   }
1895dc0f0a4SBarry Smith   PetscFunctionReturn(0);
1905dc0f0a4SBarry Smith }
1915dc0f0a4SBarry Smith 
1925dc0f0a4SBarry Smith /*@C
1935dc0f0a4SBarry Smith      PetscGlobusUpload - Loads a file to Globus
1945dc0f0a4SBarry Smith 
1955dc0f0a4SBarry Smith      Not collective, only the first process in the MPI_Comm uploads the file
1965dc0f0a4SBarry Smith 
1975dc0f0a4SBarry Smith   Input Parameters:
1985dc0f0a4SBarry Smith +   comm - MPI communicator
1995dc0f0a4SBarry Smith .   access_token - obtained with PetscGlobusAuthorize(), pass NULL to use -globus_access_token XXX from the PETSc database
2005dc0f0a4SBarry Smith -   filename - file to upload
2015dc0f0a4SBarry Smith 
2025dc0f0a4SBarry Smith   Options Database:
20310699b91SBarry Smith .  -globus_access_token XXX - the Globus token
2045dc0f0a4SBarry Smith 
2052b26979fSBarry Smith    Level: intermediate
2062b26979fSBarry Smith 
207db781477SPatrick Sanan .seealso: `PetscURLShorten()`, `PetscGoogleDriveAuthorize()`, `PetscGoogleDriveRefresh()`, `PetscGlobusAuthorize()`
2085dc0f0a4SBarry Smith 
2095dc0f0a4SBarry Smith @*/
210*9371c9d4SSatish Balay PetscErrorCode PetscGlobusUpload(MPI_Comm comm, const char access_token[], const char filename[]) {
2115dc0f0a4SBarry Smith   SSL_CTX    *ctx;
2125dc0f0a4SBarry Smith   SSL        *ssl;
2135dc0f0a4SBarry Smith   int         sock;
2145dc0f0a4SBarry Smith   char        head[4096], buff[8 * 1024], body[4096], submission_id[4096];
2155dc0f0a4SBarry Smith   PetscMPIInt rank;
2165dc0f0a4SBarry Smith   PetscBool   flg, found;
2175dc0f0a4SBarry Smith 
2185dc0f0a4SBarry Smith   PetscFunctionBegin;
2199566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
220dd400576SPatrick Sanan   if (rank == 0) {
2219566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(filename, 'r', &flg));
22228b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to find file: %s", filename);
2235dc0f0a4SBarry Smith 
2249566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(head, "Authorization : Globus-Goauthtoken "));
2255dc0f0a4SBarry Smith     if (access_token) {
2269566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(head, access_token));
2275dc0f0a4SBarry Smith     } else {
2285dc0f0a4SBarry Smith       PetscBool set;
2295dc0f0a4SBarry Smith       char      accesstoken[4096];
2309566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-globus_access_token", accesstoken, sizeof(accesstoken), &set));
23128b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_USER, "Pass in Globus accesstoken or use -globus_access_token XXX");
2329566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(head, accesstoken));
2335dc0f0a4SBarry Smith     }
2349566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(head, "\r\n"));
2355dc0f0a4SBarry Smith 
2365dc0f0a4SBarry Smith     /* Get Globus submission id */
2379566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
2389566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
2399566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("GET", "transfer.api.globusonline.org/v0.10/submission_id", head, "application/json", NULL, ssl, buff, sizeof(buff)));
2409566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2415dc0f0a4SBarry Smith     close(sock);
2429566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "value", submission_id, sizeof(submission_id), &found));
24328b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return submission id");
2445dc0f0a4SBarry Smith 
2455dc0f0a4SBarry Smith     /* build JSON body of transfer request */
2469566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(body, "{"));
247*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "submission_id", submission_id, sizeof(body)));
248*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
249*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "DATA_TYPE", "transfer", sizeof(body)));
250*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
251*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "sync_level", "null", sizeof(body)));
252*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
253*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "source_endpoint", "barryfsmith#MacBookPro", sizeof(body)));
254*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
255*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "label", "PETSc transfer label", sizeof(body)));
256*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
257*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "length", "1", sizeof(body)));
258*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
259*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "destination_endpoint", "mcs#home", sizeof(body)));
260*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
2615dc0f0a4SBarry Smith 
2629566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, "\"DATA\": [ {"));
263*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "source_path", "/~/FEM_GPU.pdf", sizeof(body)));
264*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
265*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "destination_path", "/~/FEM_GPU.pdf", sizeof(body)));
266*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
267*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "verify_size", "null", sizeof(body)));
268*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
269*9371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "recursive", "false", sizeof(body)));
270*9371c9d4SSatish Balay     PetscCall(PetscStrcat(body, ","));
2719566063dSJacob Faibussowitsch     PetscCall(PetscPushJSONValue(body, "DATA_TYPE", "transfer_item", sizeof(body)));
2729566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(body, "} ] }"));
2735dc0f0a4SBarry Smith 
2749566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
2759566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
2769566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "transfer.api.globusonline.org/v0.10/transfer", head, "application/json", body, ssl, buff, sizeof(buff)));
2779566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2785dc0f0a4SBarry Smith     close(sock);
2799566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "code", submission_id, sizeof(submission_id), &found));
28028b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return code on transfer");
2819566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(submission_id, "Accepted", &found));
28228b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not accept transfer");
2835dc0f0a4SBarry Smith   }
2845dc0f0a4SBarry Smith   PetscFunctionReturn(0);
2855dc0f0a4SBarry Smith }
286