xref: /petsc/src/sys/webclient/globus.c (revision 9c5460f9064ca60dd71a234a1f6faf93e7a6b0c9)
15dc0f0a4SBarry Smith #include <petscwebclient.h>
21c7e414eSJacob Faibussowitsch PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wdeprecated-declarations")
35dc0f0a4SBarry Smith 
45dc0f0a4SBarry Smith /*
55dc0f0a4SBarry Smith     Encodes and decodes from MIME Base64
65dc0f0a4SBarry Smith */
7*66976f2fSJacob Faibussowitsch static const 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',
89371c9d4SSatish 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', '+', '/'};
95dc0f0a4SBarry Smith 
base64_encode(const unsigned char * data,unsigned char * encoded_data,size_t len)10d71ae5a4SJacob Faibussowitsch static PetscErrorCode base64_encode(const unsigned char *data, unsigned char *encoded_data, size_t len)
11d71ae5a4SJacob Faibussowitsch {
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] = '=';
343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
355dc0f0a4SBarry Smith }
365dc0f0a4SBarry Smith 
base64_decode(const unsigned char * data,unsigned char * decoded_data,size_t length)37d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode base64_decode(const unsigned char *data, unsigned char *decoded_data, size_t length)
38d71ae5a4SJacob Faibussowitsch {
395dc0f0a4SBarry Smith   static char decoding_table[257];
405dc0f0a4SBarry Smith   static int  decode_table_built = 0;
41c1f4622dSBarry Smith   size_t      i, j;
425dc0f0a4SBarry Smith   size_t      input_length, output_length;
435dc0f0a4SBarry Smith 
445dc0f0a4SBarry Smith   PetscFunctionBegin;
455dc0f0a4SBarry Smith   if (!decode_table_built) {
465dc0f0a4SBarry Smith     for (i = 0; i < 64; i++) decoding_table[(unsigned char)encoding_table[i]] = i;
475dc0f0a4SBarry Smith     decode_table_built = 1;
485dc0f0a4SBarry Smith   }
495dc0f0a4SBarry Smith 
509566063dSJacob Faibussowitsch   PetscCall(PetscStrlen((const char *)data, &input_length));
5108401ef6SPierre Jolivet   PetscCheck(input_length % 4 == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input length must be divisible by 4");
525dc0f0a4SBarry Smith 
535dc0f0a4SBarry Smith   output_length = input_length / 4 * 3;
545dc0f0a4SBarry Smith   if (data[input_length - 1] == '=') (output_length)--;
555dc0f0a4SBarry Smith   if (data[input_length - 2] == '=') (output_length)--;
5608401ef6SPierre Jolivet   PetscCheck(output_length <= length, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Output length too shore");
575dc0f0a4SBarry Smith 
585dc0f0a4SBarry Smith   for (i = 0, j = 0; i < input_length;) {
595dc0f0a4SBarry Smith     uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
605dc0f0a4SBarry Smith     uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
615dc0f0a4SBarry Smith     uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
625dc0f0a4SBarry Smith     uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
635dc0f0a4SBarry Smith     uint32_t triple   = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
645dc0f0a4SBarry Smith 
655dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
665dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
675dc0f0a4SBarry Smith     if (j < output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
685dc0f0a4SBarry Smith   }
695dc0f0a4SBarry Smith   decoded_data[j] = 0;
703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
715dc0f0a4SBarry Smith }
725dc0f0a4SBarry Smith 
735dc0f0a4SBarry Smith #if defined(PETSC_HAVE_UNISTD_H)
745dc0f0a4SBarry Smith   #include <unistd.h>
755dc0f0a4SBarry Smith #endif
765dc0f0a4SBarry Smith 
775dc0f0a4SBarry Smith /*@C
785dc0f0a4SBarry Smith   PetscGlobusAuthorize - Get an access token allowing PETSc applications to make Globus file transfer requests
795dc0f0a4SBarry Smith 
8020f4b53cSBarry Smith   Not Collective, only the first process in `MPI_Comm` does anything
815dc0f0a4SBarry Smith 
825dc0f0a4SBarry Smith   Input Parameters:
835dc0f0a4SBarry Smith + comm      - the MPI communicator
845dc0f0a4SBarry Smith - tokensize - size of the token array
855dc0f0a4SBarry Smith 
862fe279fdSBarry Smith   Output Parameter:
87811af0c4SBarry Smith . access_token - can be used with `PetscGlobusUpLoad()` for 30 days
885dc0f0a4SBarry Smith 
8920f4b53cSBarry Smith   Level: intermediate
9020f4b53cSBarry Smith 
9195452b02SPatrick Sanan   Notes:
9220f4b53cSBarry Smith   This call requires `stdout` and `stdin` access from process 0 on the MPI communicator
935dc0f0a4SBarry Smith 
94c4762a1bSJed Brown   You can run src/sys/webclient/tutorials/globusobtainaccesstoken to get an access token
955dc0f0a4SBarry Smith 
96c30dda00SJacob Faibussowitsch .seealso: `PetscGoogleDriveRefresh()`, `PetscGoogleDriveUpload()`, `PetscGlobusUpload()`
975dc0f0a4SBarry Smith @*/
PetscGlobusAuthorize(MPI_Comm comm,char access_token[],size_t tokensize)98d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGlobusAuthorize(MPI_Comm comm, char access_token[], size_t tokensize)
99d71ae5a4SJacob Faibussowitsch {
1005dc0f0a4SBarry Smith   SSL_CTX    *ctx;
1015dc0f0a4SBarry Smith   SSL        *ssl;
1025dc0f0a4SBarry Smith   int         sock;
1035dc0f0a4SBarry Smith   char        buff[8 * 1024], *ptr, head[1024];
1045dc0f0a4SBarry Smith   PetscMPIInt rank;
1055dc0f0a4SBarry Smith   size_t      len;
1065dc0f0a4SBarry Smith   PetscBool   found;
1075dc0f0a4SBarry Smith 
1085dc0f0a4SBarry Smith   PetscFunctionBegin;
1099566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
110dd400576SPatrick Sanan   if (rank == 0) {
111cc73adaaSBarry Smith     PetscCheck(isatty(fileno(PETSC_STDOUT)), PETSC_COMM_SELF, PETSC_ERR_USER, "Requires users input/output");
1129566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Enter globus username:"));
1135dc0f0a4SBarry Smith     ptr = fgets(buff, 1024, stdin);
11428b400f6SJacob Faibussowitsch     PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
1159566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(buff, &len));
1165dc0f0a4SBarry Smith     buff[len - 1] = ':'; /* remove carriage return at end of line */
1175dc0f0a4SBarry Smith 
1189566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Enter globus password:"));
1195dc0f0a4SBarry Smith     ptr = fgets(buff + len, 1024 - len, stdin);
12028b400f6SJacob Faibussowitsch     PetscCheck(ptr, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
1219566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(buff, &len));
1225dc0f0a4SBarry Smith     buff[len - 1] = '\0'; /* remove carriage return at end of line */
123c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(head, "Authorization: Basic ", sizeof(head)));
1249566063dSJacob Faibussowitsch     PetscCall(base64_encode((const unsigned char *)buff, (unsigned char *)(head + 21), sizeof(head) - 21));
125c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "\r\n", sizeof(head)));
1265dc0f0a4SBarry Smith 
1279566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1289566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("nexus.api.globusonline.org", 443, ctx, &sock, &ssl));
1299566063dSJacob 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)));
1309566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1315dc0f0a4SBarry Smith     close(sock);
1325dc0f0a4SBarry Smith 
1339566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "access_token", access_token, tokensize, &found));
13428b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return access token");
1355dc0f0a4SBarry Smith 
1369566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Here is your Globus access token, save it in a save place, in the future you can run PETSc\n"));
1379566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "programs with the option -globus_access_token %s\n", access_token));
1389566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "to access Globus automatically\n"));
1395dc0f0a4SBarry Smith   }
1403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1415dc0f0a4SBarry Smith }
1425dc0f0a4SBarry Smith 
1435dc0f0a4SBarry Smith /*@C
1445dc0f0a4SBarry Smith   PetscGlobusGetTransfers - Get a record of current transfers requested from Globus
1455dc0f0a4SBarry Smith 
14620f4b53cSBarry Smith   Not Collective, only the first process in `MPI_Comm` does anything
1475dc0f0a4SBarry Smith 
1485dc0f0a4SBarry Smith   Input Parameters:
1495dc0f0a4SBarry Smith + comm         - the MPI communicator
15020f4b53cSBarry Smith . access_token - Globus access token, if `NULL` will check in options database for -globus_access_token XXX otherwise
151811af0c4SBarry Smith                   will call `PetscGlobusAuthorize()`.
1525dc0f0a4SBarry Smith - buffsize     - size of the buffer
1535dc0f0a4SBarry Smith 
1542fe279fdSBarry Smith   Output Parameter:
1555dc0f0a4SBarry Smith . buff - location to put Globus information
1565dc0f0a4SBarry Smith 
1572b26979fSBarry Smith   Level: intermediate
1582b26979fSBarry Smith 
159c30dda00SJacob Faibussowitsch .seealso: `PetscGoogleDriveRefresh()`, `PetscGoogleDriveUpload()`, `PetscGlobusUpload()`, `PetscGlobusAuthorize()`
1605dc0f0a4SBarry Smith @*/
PetscGlobusGetTransfers(MPI_Comm comm,const char access_token[],char buff[],size_t buffsize)161d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGlobusGetTransfers(MPI_Comm comm, const char access_token[], char buff[], size_t buffsize)
162d71ae5a4SJacob Faibussowitsch {
1635dc0f0a4SBarry Smith   SSL_CTX    *ctx;
1645dc0f0a4SBarry Smith   SSL        *ssl;
1655dc0f0a4SBarry Smith   int         sock;
1665dc0f0a4SBarry Smith   char        head[4096];
1675dc0f0a4SBarry Smith   PetscMPIInt rank;
1685dc0f0a4SBarry Smith 
1695dc0f0a4SBarry Smith   PetscFunctionBegin;
1709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
171dd400576SPatrick Sanan   if (rank == 0) {
172c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(head, "Authorization : Globus-Goauthtoken ", sizeof(head)));
1735dc0f0a4SBarry Smith     if (access_token) {
174c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(head, access_token, sizeof(head)));
1755dc0f0a4SBarry Smith     } else {
1765dc0f0a4SBarry Smith       PetscBool set;
1775dc0f0a4SBarry Smith       char      accesstoken[4096];
1789566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-globus_access_token", accesstoken, sizeof(accesstoken), &set));
17928b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_USER, "Pass in Globus accesstoken or use -globus_access_token XXX");
180c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(head, accesstoken, sizeof(head)));
1815dc0f0a4SBarry Smith     }
182c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "\r\n", sizeof(head)));
1835dc0f0a4SBarry Smith 
1849566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
1859566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
1869566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("GET", "transfer.api.globusonline.org/v0.10/tasksummary", head, "application/json", NULL, ssl, buff, buffsize));
1879566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
1885dc0f0a4SBarry Smith     close(sock);
1895dc0f0a4SBarry Smith   }
1903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1915dc0f0a4SBarry Smith }
1925dc0f0a4SBarry Smith 
1935dc0f0a4SBarry Smith /*@C
1945dc0f0a4SBarry Smith   PetscGlobusUpload - Loads a file to Globus
1955dc0f0a4SBarry Smith 
19620f4b53cSBarry Smith   Not Collective, only the first process in the `MPI_Comm` uploads the file
1975dc0f0a4SBarry Smith 
1985dc0f0a4SBarry Smith   Input Parameters:
1995dc0f0a4SBarry Smith + comm         - MPI communicator
20020f4b53cSBarry Smith . access_token - obtained with `PetscGlobusAuthorize()`, pass `NULL` to use `-globus_access_token XXX` from the PETSc database
2015dc0f0a4SBarry Smith - filename     - file to upload
2025dc0f0a4SBarry Smith 
203811af0c4SBarry Smith   Options Database Key:
20410699b91SBarry Smith . -globus_access_token XXX - the Globus token
2055dc0f0a4SBarry Smith 
2062b26979fSBarry Smith   Level: intermediate
2072b26979fSBarry Smith 
208c30dda00SJacob Faibussowitsch .seealso: `PetscGoogleDriveAuthorize()`, `PetscGoogleDriveRefresh()`, `PetscGlobusAuthorize()`
2095dc0f0a4SBarry Smith @*/
PetscGlobusUpload(MPI_Comm comm,const char access_token[],const char filename[])210d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGlobusUpload(MPI_Comm comm, const char access_token[], const char filename[])
211d71ae5a4SJacob Faibussowitsch {
2125dc0f0a4SBarry Smith   SSL_CTX    *ctx;
2135dc0f0a4SBarry Smith   SSL        *ssl;
2145dc0f0a4SBarry Smith   int         sock;
2155dc0f0a4SBarry Smith   char        head[4096], buff[8 * 1024], body[4096], submission_id[4096];
2165dc0f0a4SBarry Smith   PetscMPIInt rank;
2175dc0f0a4SBarry Smith   PetscBool   flg, found;
2185dc0f0a4SBarry Smith 
2195dc0f0a4SBarry Smith   PetscFunctionBegin;
2209566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
221dd400576SPatrick Sanan   if (rank == 0) {
2229566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(filename, 'r', &flg));
22328b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to find file: %s", filename);
2245dc0f0a4SBarry Smith 
225c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(head, "Authorization : Globus-Goauthtoken ", sizeof(head)));
2265dc0f0a4SBarry Smith     if (access_token) {
227c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(head, access_token, sizeof(head)));
2285dc0f0a4SBarry Smith     } else {
2295dc0f0a4SBarry Smith       PetscBool set;
2305dc0f0a4SBarry Smith       char      accesstoken[4096];
2319566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-globus_access_token", accesstoken, sizeof(accesstoken), &set));
23228b400f6SJacob Faibussowitsch       PetscCheck(set, PETSC_COMM_SELF, PETSC_ERR_USER, "Pass in Globus accesstoken or use -globus_access_token XXX");
233c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(head, accesstoken, sizeof(head)));
2345dc0f0a4SBarry Smith     }
235c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(head, "\r\n", sizeof(head)));
2365dc0f0a4SBarry Smith 
2375dc0f0a4SBarry Smith     /* Get Globus submission id */
2389566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
2399566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
2409566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("GET", "transfer.api.globusonline.org/v0.10/submission_id", head, "application/json", NULL, ssl, buff, sizeof(buff)));
2419566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2425dc0f0a4SBarry Smith     close(sock);
2439566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "value", submission_id, sizeof(submission_id), &found));
24428b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return submission id");
2455dc0f0a4SBarry Smith 
2465dc0f0a4SBarry Smith     /* build JSON body of transfer request */
247c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(body, "{", sizeof(body)));
2489371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "submission_id", submission_id, sizeof(body)));
249c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2509371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "DATA_TYPE", "transfer", sizeof(body)));
251c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2529371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "sync_level", "null", sizeof(body)));
253c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2549371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "source_endpoint", "barryfsmith#MacBookPro", sizeof(body)));
255c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2569371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "label", "PETSc transfer label", sizeof(body)));
257c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2589371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "length", "1", sizeof(body)));
259c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2609371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "destination_endpoint", "mcs#home", sizeof(body)));
261c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2625dc0f0a4SBarry Smith 
263c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "\"DATA\": [ {", sizeof(body)));
2649371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "source_path", "/~/FEM_GPU.pdf", sizeof(body)));
265c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2669371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "destination_path", "/~/FEM_GPU.pdf", sizeof(body)));
267c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2689371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "verify_size", "null", sizeof(body)));
269c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2709371c9d4SSatish Balay     PetscCall(PetscPushJSONValue(body, "recursive", "false", sizeof(body)));
271c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, ",", sizeof(body)));
2729566063dSJacob Faibussowitsch     PetscCall(PetscPushJSONValue(body, "DATA_TYPE", "transfer_item", sizeof(body)));
273c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(body, "} ] }", sizeof(body)));
2745dc0f0a4SBarry Smith 
2759566063dSJacob Faibussowitsch     PetscCall(PetscSSLInitializeContext(&ctx));
2769566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSConnect("transfer.api.globusonline.org", 443, ctx, &sock, &ssl));
2779566063dSJacob Faibussowitsch     PetscCall(PetscHTTPSRequest("POST", "transfer.api.globusonline.org/v0.10/transfer", head, "application/json", body, ssl, buff, sizeof(buff)));
2789566063dSJacob Faibussowitsch     PetscCall(PetscSSLDestroyContext(ctx));
2795dc0f0a4SBarry Smith     close(sock);
2809566063dSJacob Faibussowitsch     PetscCall(PetscPullJSONValue(buff, "code", submission_id, sizeof(submission_id), &found));
28128b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not return code on transfer");
2829566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(submission_id, "Accepted", &found));
28328b400f6SJacob Faibussowitsch     PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_LIB, "Globus did not accept transfer");
2845dc0f0a4SBarry Smith   }
2853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2865dc0f0a4SBarry Smith }
287