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