Actual source code: globus.c
petsc-3.7.1 2016-05-15
Report Typos and Errors

      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',
      9:                                 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
     10:                                 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
     11:                                 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
     12:                                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
     13:                                 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
     14:                                 'w', 'x', 'y', 'z', '0', '1', '2', '3',
     15:                                 '4', '5', '6', '7', '8', '9', '+', '/'};

     17: static PetscErrorCode base64_encode(const unsigned char *data,unsigned char *encoded_data,size_t len)
     18: {
     19:   static size_t  mod_table[] = {0, 2, 1};
     20:   size_t         i,j;
     21:   size_t         input_length,output_length;

     25:   PetscStrlen((const char*)data,&input_length);
     26:   output_length = 4 * ((input_length + 2) / 3);
     27:   if (output_length > len) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Output length not large enough");

     29:   for (i = 0, j = 0; i < input_length;) {
     30:      uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
     31:      uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
     32:      uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
     33:      uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

     35:      encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
     36:      encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
     37:      encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
     38:      encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
     39:   }
     40:   encoded_data[j] = 0;
     41:   for (i = 0; i < mod_table[input_length % 3]; i++) encoded_data[output_length - 1 - i] = '=';
     42:   return(0);
     43: }

     45: PETSC_UNUSED static PetscErrorCode base64_decode(const unsigned char *data,unsigned char* decoded_data, size_t length)
     46: {
     47:   static char    decoding_table[257];
     48:   static int     decode_table_built = 0;
     49:   size_t         i,j;
     51:   size_t         input_length,output_length;

     54:   if (!decode_table_built) {
     55:     for (i = 0; i < 64; i++) decoding_table[(unsigned char) encoding_table[i]] = i;
     56:     decode_table_built = 1;
     57:   }

     59:   PetscStrlen((const char*)data,&input_length);
     60:   if (input_length % 4 != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Input length must be divisible by 4");

     62:   output_length = input_length / 4 * 3;
     63:   if (data[input_length - 1] == '=') (output_length)--;
     64:   if (data[input_length - 2] == '=') (output_length)--;
     65:   if (output_length > length) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Output length too shore");

     67:   for (i = 0, j = 0; i < input_length;) {
     68:     uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
     69:     uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
     70:     uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
     71:     uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[(int)data[i++]];
     72:     uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);

     74:     if (j < output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
     75:     if (j < output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
     76:     if (j < output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
     77:   }
     78:   decoded_data[j] = 0;
     79:   return(0);
     80: }

     82: #if defined(PETSC_HAVE_UNISTD_H)
     83: #include <unistd.h>
     84: #endif

     88: /*@C
     89:      PetscGlobusAuthorize - Get an access token allowing PETSc applications to make Globus file transfer requests

     91:    Not collective, only the first process in MPI_Comm does anything

     93:    Input Parameters:
     94: +  comm - the MPI communicator
     95: -  tokensize - size of the token array

     97:    Output Parameters:
     98: .  access_token - can be used with PetscGlobusUpLoad() for 30 days

    100:    Notes: This call requires stdout and stdin access from process 0 on the MPI communicator

    102:    You can run src/sys/webclient/examples/tutorials/globusobtainaccesstoken to get an access token

    104:    Level: intermediate

    106: .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscURLShorten(), PetscGlobusUpload()

    108: @*/
    109: PetscErrorCode PetscGlobusAuthorize(MPI_Comm comm,char access_token[],size_t tokensize)
    110: {
    111:   SSL_CTX        *ctx;
    112:   SSL            *ssl;
    113:   int            sock;
    115:   char           buff[8*1024],*ptr,head[1024];
    116:   PetscMPIInt    rank;
    117:   size_t         len;
    118:   PetscBool      found;

    121:   MPI_Comm_rank(comm,&rank);
    122:   if (!rank) {
    123:     if (!isatty(fileno(PETSC_STDOUT))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Requires users input/output");
    124:     PetscPrintf(comm,"Enter globus username:");
    125:     ptr  = fgets(buff, 1024, stdin);
    126:     if (!ptr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
    127:     PetscStrlen(buff,&len);
    128:     buff[len-1] = ':'; /* remove carriage return at end of line */

    130:     PetscPrintf(comm,"Enter globus password:");
    131:     ptr  = fgets(buff+len, 1024-len, stdin);
    132:     if (!ptr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from stdin: %d", errno);
    133:     PetscStrlen(buff,&len);
    134:     buff[len-1] = '\0'; /* remove carriage return at end of line */
    135:     PetscStrcpy(head,"Authorization: Basic ");
    136:     base64_encode((const unsigned char*)buff,(unsigned char*)(head+21),sizeof(head)-21);
    137:     PetscStrcat(head,"\r\n");

    139:     PetscSSLInitializeContext(&ctx);
    140:     PetscHTTPSConnect("nexus.api.globusonline.org",443,ctx,&sock,&ssl);
    141:     PetscHTTPSRequest("GET","nexus.api.globusonline.org/goauth/token?grant_type=client_credentials",head,"application/x-www-form-urlencoded",NULL,ssl,buff,sizeof(buff));
    142:     PetscSSLDestroyContext(ctx);
    143:     close(sock);

    145:     PetscPullJSONValue(buff,"access_token",access_token,tokensize,&found);
    146:     if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return access token");

    148:     PetscPrintf(comm,"Here is your Globus access token, save it in a save place, in the future you can run PETSc\n");
    149:     PetscPrintf(comm,"programs with the option -globus_access_token %s\n",access_token);
    150:     PetscPrintf(comm,"to access Globus automatically\n");
    151:   }
    152:   return(0);
    153: }

    158: /*@C
    159:      PetscGlobusGetTransfers - Get a record of current transfers requested from Globus

    161:    Not collective, only the first process in MPI_Comm does anything

    163:    Input Parameters:
    164: +  comm - the MPI communicator
    165: .  access_token - Globus access token, if NULL will check in options database for -globus_access_token XXX otherwise
    166:                   will call PetscGlobusAuthorize().
    167: -  buffsize - size of the buffer

    169:    Output Parameters:
    170: .  buff - location to put Globus information

    172:    Level: intermediate

    174: .seealso: PetscGoogleDriveRefresh(), PetscGoogleDriveUpload(), PetscURLShorten(), PetscGlobusUpload(), PetscGlobusAuthorize()

    176: @*/
    177: PetscErrorCode PetscGlobusGetTransfers(MPI_Comm comm,const char access_token[],char buff[],size_t buffsize)
    178: {
    179:   SSL_CTX        *ctx;
    180:   SSL            *ssl;
    181:   int            sock;
    183:   char           head[4096];
    184:   PetscMPIInt    rank;

    187:   MPI_Comm_rank(comm,&rank);
    188:   if (!rank) {
    189:     PetscStrcpy(head,"Authorization : Globus-Goauthtoken ");
    190:     if (access_token) {
    191:       PetscStrcat(head,access_token);
    192:     } else {
    193:       PetscBool set;
    194:       char      accesstoken[4096];
    195:       PetscOptionsGetString(NULL,NULL,"-globus_access_token",accesstoken,sizeof(accesstoken),&set);
    196:       if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Pass in Globus accesstoken or use -globus_access_token XXX");
    197:       PetscStrcat(head,accesstoken);
    198:     }
    199:     PetscStrcat(head,"\r\n");

    201:     PetscSSLInitializeContext(&ctx);
    202:     PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);
    203:     PetscHTTPSRequest("GET","transfer.api.globusonline.org/v0.10/tasksummary",head,"application/json",NULL,ssl,buff,buffsize);
    204:     PetscSSLDestroyContext(ctx);
    205:     close(sock);
    206:   }
    207:   return(0);
    208: }

    212: /*@C
    213:      PetscGlobusUpload - Loads a file to Globus

    215:      Not collective, only the first process in the MPI_Comm uploads the file

    217:   Input Parameters:
    218: +   comm - MPI communicator
    219: .   access_token - obtained with PetscGlobusAuthorize(), pass NULL to use -globus_access_token XXX from the PETSc database
    220: -   filename - file to upload

    222:   Options Database:
    223: .  -globus_access_token   XXX

    225:    Level: intermediate

    227: .seealso: PetscURLShorten(), PetscGoogleDriveAuthorize(), PetscGoogleDriveRefresh(), PetscGlobusAuthorize()

    229: @*/
    230: PetscErrorCode PetscGlobusUpload(MPI_Comm comm,const char access_token[],const char filename[])
    231: {
    232:   SSL_CTX        *ctx;
    233:   SSL            *ssl;
    234:   int            sock;
    236:   char           head[4096],buff[8*1024],body[4096],submission_id[4096];
    237:   PetscMPIInt    rank;
    238:   PetscBool      flg,found;

    241:   MPI_Comm_rank(comm,&rank);
    242:   if (!rank) {
    243:     PetscTestFile(filename,'r',&flg);
    244:     if (!flg) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to find file: %s",filename);

    246:     PetscStrcpy(head,"Authorization : Globus-Goauthtoken ");
    247:     if (access_token) {
    248:       PetscStrcat(head,access_token);
    249:     } else {
    250:       PetscBool set;
    251:       char      accesstoken[4096];
    252:       PetscOptionsGetString(NULL,NULL,"-globus_access_token",accesstoken,sizeof(accesstoken),&set);
    253:       if (!set) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Pass in Globus accesstoken or use -globus_access_token XXX");
    254:       PetscStrcat(head,accesstoken);
    255:     }
    256:     PetscStrcat(head,"\r\n");

    258:     /* Get Globus submission id */
    259:     PetscSSLInitializeContext(&ctx);
    260:     PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);
    261:     PetscHTTPSRequest("GET","transfer.api.globusonline.org/v0.10/submission_id",head,"application/json",NULL,ssl,buff,sizeof(buff));
    262:     PetscSSLDestroyContext(ctx);
    263:     close(sock);
    264:     PetscPullJSONValue(buff,"value",submission_id,sizeof(submission_id),&found);
    265:     if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return submission id");

    267:     /* build JSON body of transfer request */
    268:     PetscStrcpy(body,"{");
    269:     PetscPushJSONValue(body,"submission_id",submission_id,sizeof(body));                 PetscStrcat(body,",");
    270:     PetscPushJSONValue(body,"DATA_TYPE","transfer",sizeof(body));                        PetscStrcat(body,",");
    271:     PetscPushJSONValue(body,"sync_level","null",sizeof(body));                           PetscStrcat(body,",");
    272:     PetscPushJSONValue(body,"source_endpoint","barryfsmith#MacBookPro",sizeof(body));    PetscStrcat(body,",");
    273:     PetscPushJSONValue(body,"label","PETSc transfer label",sizeof(body));                PetscStrcat(body,",");
    274:     PetscPushJSONValue(body,"length","1",sizeof(body));                                  PetscStrcat(body,",");
    275:     PetscPushJSONValue(body,"destination_endpoint","mcs#home",sizeof(body));             PetscStrcat(body,",");

    277:     PetscStrcat(body,"\"DATA\": [ {");
    278:     PetscPushJSONValue(body,"source_path","/~/FEM_GPU.pdf",sizeof(body));                PetscStrcat(body,",");
    279:     PetscPushJSONValue(body,"destination_path","/~/FEM_GPU.pdf",sizeof(body));           PetscStrcat(body,",");
    280:     PetscPushJSONValue(body,"verify_size","null",sizeof(body));                          PetscStrcat(body,",");
    281:     PetscPushJSONValue(body,"recursive","false",sizeof(body));                           PetscStrcat(body,",");
    282:     PetscPushJSONValue(body,"DATA_TYPE","transfer_item",sizeof(body));
    283:     PetscStrcat(body,"} ] }");

    285:     PetscSSLInitializeContext(&ctx);
    286:     PetscHTTPSConnect("transfer.api.globusonline.org",443,ctx,&sock,&ssl);
    287:     PetscHTTPSRequest("POST","transfer.api.globusonline.org/v0.10/transfer",head,"application/json",body,ssl,buff,sizeof(buff));
    288:     PetscSSLDestroyContext(ctx);
    289:     close(sock);
    290:     PetscPullJSONValue(buff,"code",submission_id,sizeof(submission_id),&found);
    291:     if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not return code on transfer");
    292:     PetscStrcmp(submission_id,"Accepted",&found);
    293:     if (!found) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Globus did not accept transfer");
    294:   }
    295:   return(0);
    296: }