Kaidul

RestClient.cpp

Nov 28th, 2014
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.00 KB | None | 0 0
  1. #include "RESTClient.h"
  2. #include "Hash.h"
  3. //#include <curl/curl.h>
  4. #include <string.h>
  5. #include <string>
  6. #include <stdio.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <netdb.h>
  10. #include <netinet/in.h>
  11. #include <unistd.h>
  12. #include <stdlib.h>
  13. #include <openssl/ssl.h>
  14. #include <openssl/err.h>
  15. #include <fstream>
  16. #include <openssl/bio.h>
  17. #include <openssl/err.h>
  18. #include <openssl/pem.h>
  19. #include <openssl/x509.h>
  20. #include <openssl/x509_vfy.h>
  21. #include "Settings.h""
  22. #include "LoginEngine.h"
  23. #include "Utilities.h"
  24.  
  25. #define MAXSZ 2048
  26. #define USE_JSON
  27.  
  28. #ifdef USE_JSON
  29. #define CONTENT_TYPE    "application/json"
  30. #else
  31. #define CONTENT_TYPE    "application/x-www-form-urlencoded"
  32. #endif
  33.  
  34. static void RestLog(const char* format, ...)
  35. {
  36.     static FILE *g_sfpLogFile = NULL;
  37.     if(!g_sfpLogFile && CSettings::GetInstance()->m_bLoggingEnabled)
  38.     {
  39.         g_sfpLogFile = fopen("/media/EyeballSDKLogs/rest.log", "w");
  40.         if(g_sfpLogFile){
  41.             fprintf(g_sfpLogFile, "=========== Log file opened for rest api calls (" __DATE__ ")============\n");
  42.         }
  43.     }
  44.     va_list argptr;
  45.     va_start(argptr, format);  
  46.     if(g_sfpLogFile){
  47.         fprintf(g_sfpLogFile, "[%s] ", SGetTimeInMS().c_str());
  48.         vfprintf(g_sfpLogFile, format, argptr);
  49.         fflush(g_sfpLogFile);      
  50.     }
  51.     vfprintf(stdout, format, argptr);
  52.     va_end(argptr);
  53. }
  54.  
  55. #define printf(...) RestLog(__VA_ARGS__)
  56.  
  57. static size_t WriteDataCallback(char *ptr, size_t size, size_t nmemb, void *userdata)
  58. {
  59.     std::string* pResponse = (std::string*)userdata;
  60.     size_t total = size * nmemb;
  61.     for (size_t i = 0; i < total; ++i)
  62.         pResponse->push_back(*ptr++);
  63.     return total;
  64. }
  65.  
  66. #if 0
  67. int RESTClient::BlockingRequest(const std::string& strRequestUrl, std::string& strResponse, long nTimeout)
  68. {
  69.     int nRet = 0;
  70.     CURL *pCurlHandle;
  71.     CURLcode res;
  72.  
  73.     curl_global_init(CURL_GLOBAL_DEFAULT);
  74.    
  75.     pCurlHandle = curl_easy_init();
  76.     if(pCurlHandle) {
  77.         curl_easy_setopt(pCurlHandle, CURLOPT_URL, strRequestUrl.c_str());
  78.         curl_easy_setopt(pCurlHandle, CURLOPT_CONNECTTIMEOUT, nTimeout);
  79.         curl_easy_setopt(pCurlHandle, CURLOPT_WRITEFUNCTION, WriteDataCallback);
  80.         strResponse = "";
  81.         curl_easy_setopt(pCurlHandle, CURLOPT_WRITEDATA, &strResponse);
  82.    
  83.         curl_easy_setopt(pCurlHandle, CURLOPT_SSL_VERIFYPEER, 0L); // skip ssl peer verification !!
  84.         curl_easy_setopt(pCurlHandle, CURLOPT_SSL_VERIFYHOST, 0L); // skip ssl host verification !!
  85.    
  86.         /* Perform the request, res will get the return code */
  87.         res = curl_easy_perform(pCurlHandle);
  88.         /* Check for errors */
  89.         if(res != CURLE_OK){
  90.             nRet = -1;
  91.             fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
  92.         }
  93.         curl_easy_cleanup(pCurlHandle);
  94.     }
  95.  
  96.     curl_global_cleanup();
  97.     return nRet;   
  98. }
  99. #endif
  100.  
  101. // Start of functions for sending HTTPS request
  102.  
  103. int OpenConnection(const char *hostname, int port, int nTimeout)
  104. {   int sd;
  105.     struct hostent *host;
  106.     struct sockaddr_in addr;
  107.  
  108.     if ( (host = gethostbyname(hostname)) == NULL )
  109.     {
  110.         printf("Error retrieving DNS information.\n");
  111.         return -1;
  112.     }
  113.     sd = socket(PF_INET, SOCK_STREAM, 0);
  114.     if(sd < 0)
  115.     {
  116.         printf("Error creating socket\n");
  117.         return -1;
  118.     }
  119.  
  120.     struct timeval timeout;
  121.     timeout.tv_sec = 2;
  122.     timeout.tv_usec = 0;
  123.     if(setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof timeout) < 0)
  124.     {
  125.         printf("setsockopt failed\n");
  126.         return -1;
  127.     }
  128.  
  129.     timeout.tv_sec = nTimeout;
  130.     timeout.tv_usec = 0;
  131.     if(setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof timeout) < 0)
  132.     {
  133.         printf("setsockopt failed\n");
  134.         return -1;
  135.     }
  136.  
  137.     bzero(&addr, sizeof(addr));
  138.     addr.sin_family = AF_INET;
  139.     addr.sin_port = htons(port);
  140.     addr.sin_addr.s_addr = *(long*)(host->h_addr);
  141.     if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
  142.     {
  143.         close(sd);
  144.         perror(hostname);
  145.         return -1;
  146.     }
  147.     return sd;
  148. }
  149.  
  150. SSL_CTX* InitCTX(void)
  151. {   const SSL_METHOD *method;
  152.     SSL_CTX *ctx;
  153.  
  154.     OpenSSL_add_all_algorithms();  /* Load cryptos, et.al. */
  155.     SSL_load_error_strings();   /* Bring in and register error messages */
  156.     ERR_load_BIO_strings();
  157.     ERR_load_crypto_strings();
  158.     method = SSLv3_client_method();  /* Create new client-method instance */
  159.     ctx = SSL_CTX_new(method);   /* Create new context */
  160.     if ( ctx == NULL )
  161.     {
  162.         ERR_print_errors_fp(stderr);
  163.         return NULL;
  164.     }
  165.     return ctx;
  166. }
  167.  
  168. void ShowCerts(SSL* ssl)
  169. {
  170.     X509 *cert;
  171.     char *line;
  172.  
  173.     cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
  174.     if ( cert != NULL )
  175.     {
  176.         printf("Server certificates:\n");
  177.         line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
  178.         printf("Subject: %s\n", line);
  179.         free(line);       /* free the malloc'ed string */
  180.         line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
  181.         printf("Issuer: %s\n", line);
  182.         free(line);       /* free the malloc'ed string */
  183.         X509_free(cert);     /* free the malloc'ed certificate copy */
  184.     }
  185.     else
  186.         printf("No certificates.\n");
  187. }
  188.  
  189. // End of Functions for HTTPS
  190.  
  191. int RESTClient::BlockingRequest(const std::string& strRequestUrl, std::string& strResponse, long nTimout)
  192. {
  193.     printf(" --- Blocking Request Called\n");
  194.     strResponse = "";
  195.     std::string strHost = "", strUri = "";
  196.     std::string strPort = "";  
  197.     int nPort = 80;
  198.     bool bSecuredProtocol = false;
  199.    
  200.     int pos = 7; // http:// skipped
  201.     if(strRequestUrl[4] == 's')
  202.     {
  203.         bSecuredProtocol = true;
  204.         pos = 8;
  205.     }
  206.  
  207.     if(pos >= strRequestUrl.size()){
  208.         printf("http or https not found in the request url %s\n", strRequestUrl.c_str());
  209.         return -1;
  210.     }
  211.  
  212.     while(pos < strRequestUrl.size() && ( strRequestUrl[pos] != ':' && strRequestUrl[pos] != '/') ){
  213.         strHost.push_back(strRequestUrl[pos++]);
  214.     }
  215.    
  216.     if(pos == strRequestUrl.size()){
  217.         printf("http or https found at the end of the request url %s\n", strRequestUrl.c_str());
  218.         return -1;
  219.     }
  220.  
  221.     // Port number is determined
  222.     if(strRequestUrl[pos] == ':')
  223.     {
  224.         pos++;
  225.         while(pos < strRequestUrl.size() && strRequestUrl[pos] != '/')
  226.             strPort.push_back(strRequestUrl[pos++]);
  227.         nPort = atoi( strPort.c_str() );
  228.     }
  229.    
  230.     if(pos == strRequestUrl.size()){
  231.         printf("http or https found still at the end of the request url %s\n", strRequestUrl.c_str());
  232.         return -1;
  233.     }
  234.     strUri = strRequestUrl.substr(pos);
  235.    
  236.     printf("Blocking Request host: %s %s %d\n", bSecuredProtocol ? "https" : "http", strHost.c_str(), nPort);
  237.     printf("Blocking Request request: %s\n", strUri.c_str());
  238.  
  239.     int ret;
  240.     if(bSecuredProtocol == false)
  241.         ret = BlockingRequest_HTTP(strHost, strUri, nPort, strResponse, nTimout);
  242.     else
  243.         ret = BlockingRequest_HTTPS(strHost, strUri, nPort, strResponse, nTimout);
  244.  
  245.     printf("Response: %s\n", strResponse.c_str());
  246.    
  247.     std::string end_of_header = "\r\n\r\n";
  248.     size_t pos_of_end_of_header = strResponse.find(end_of_header);
  249.  
  250.     if(pos_of_end_of_header != std::string::npos){
  251.         strResponse = strResponse.substr(pos_of_end_of_header + end_of_header.size());
  252.     }
  253.     else{
  254.         strResponse = "";
  255.         return -1;
  256.     }
  257.  
  258.     return ret;
  259. }
  260.  
  261. int RESTClient::BlockingRequest_HTTP(const std::string &hst, std::string &org_uri, int nPort, std::string &response, long nTimeout)
  262. {
  263.     printf("host: %s\nuri = %s\n", hst.c_str(), org_uri.c_str());
  264.     const char *hstname = hst.c_str(), *uri, *myReq;
  265.     struct hostent *host = gethostbyname(hstname);
  266.        
  267.     std::string sUri = org_uri.substr(0, org_uri.find("?"));
  268.     std::string sReq = org_uri.substr(org_uri.find("?") + 1);
  269.  
  270.     uri = ( sUri.c_str() );
  271. #ifdef USE_JSON
  272.     char szJsonReq[MAXSZ];
  273.     ParseIntoJson(sReq, szJsonReq);
  274.     myReq = szJsonReq;
  275. #else
  276.     myReq = ( sReq.c_str() );
  277. #endif
  278.  
  279.     if( (host == NULL) )
  280.     {
  281.         printf("Error retrieving DNS information.\n");
  282.         return -1;
  283.     }
  284.  
  285.     struct sockaddr_in client;
  286.     memset(&client, 0, sizeof client);
  287.     client.sin_family = AF_INET;
  288.     client.sin_port = htons(nPort);
  289.     memcpy(&client.sin_addr, host->h_addr, host->h_length);
  290.  
  291.     int sock = socket(AF_INET, SOCK_STREAM, 0);
  292.     if(sock < 0)
  293.     {
  294.         printf("Error creating socket\n");
  295.         return -1;
  296.     }
  297.  
  298.     struct timeval timeout;
  299.     timeout.tv_sec = 2;
  300.     timeout.tv_usec = 0;
  301.     if(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof timeout) < 0)
  302.     {
  303.         printf("setsockopt failed\n");
  304.         return -1;
  305.     }
  306.  
  307.     timeout.tv_sec = nTimeout;
  308.     timeout.tv_usec = 0;
  309.     if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof timeout) < 0)
  310.     {
  311.         printf("setsockopt failed\n");
  312.         return -1;
  313.     }
  314.  
  315.     int conn = connect(sock, (struct sockaddr *)&client, sizeof client);
  316.  
  317.     if(conn>=0)
  318.     {
  319.         printf("Sending HTTP Request\n");
  320.  
  321.         char sendline[MAXSZ + 1], recvline[MAXSZ + 1];
  322.         int n;
  323.         sprintf(sendline,
  324.             "POST %s HTTP/1.0\r\n"
  325.             "Host: %s:%d\r\n"
  326.             "Content-Type: "CONTENT_TYPE"\r\n"
  327.             "Content-Length: %d\r\n"
  328.             "\r\n"
  329.             "%s\r\n"
  330.             "\r\n\r\n", uri, hstname, nPort, strlen(myReq), myReq);
  331.  
  332.         if( (send(sock, sendline, strlen(sendline), 0)) != (strlen(sendline)) )
  333.         {
  334.             printf("Error sending request\n");
  335.             return -1;
  336.         }
  337.  
  338.         while( (n = recv(sock, recvline, MAXSZ, 0)) > 0 )
  339.         {
  340.             recvline[n] = '\0';
  341.             response += recvline;
  342.         }
  343.     }
  344.  
  345.     close(sock);
  346.  
  347.     return 0;
  348. }
  349.  
  350. #define CASSERT(X, ...) \
  351.     if(!X) { \
  352.         printf(__VA_ARGS__); \
  353.         return false; \
  354.     }
  355.  
  356. bool VerifiyCertificate(SSL *ssl) {
  357.    
  358.     OpenSSL_add_all_algorithms();
  359.     ERR_load_BIO_strings();
  360.     ERR_load_crypto_strings();
  361.    
  362.     X509_STORE         *store = NULL;
  363.     X509_STORE_CTX  *vrfy_ctx = NULL;
  364.     int ret;
  365.    
  366.     /* get the server's certificate */
  367.     X509 *server_cert = SSL_get_peer_certificate(ssl);
  368.    
  369.     const char *path = "/foo/bar/ss.pem";
  370.     FILE *fp = fopen(path, "r");
  371.     if(!fp) return false;
  372.     fseek(fp, 0, SEEK_END);
  373.     size_t size = ftell(fp);
  374.     char *cert_data = new char[size];
  375.     rewind(fp);
  376.     fread(cert_data, sizeof(char), size, fp);
  377.     fclose(fp);
  378.    
  379.     store = X509_STORE_new();
  380.     CASSERT(store != NULL, "Error creating X509_STORE_CTX object\n");
  381.    
  382.     vrfy_ctx = X509_STORE_CTX_new();
  383.    
  384.     ret = X509_STORE_load_locations(store, cert_data, NULL);
  385.     CASSERT(ret == 1, "Error loading CA cert or chain file\n");
  386.    
  387.     X509_STORE_set_flags(store, 0);
  388.     X509_STORE_CTX_init(vrfy_ctx, store, server_cert, NULL);
  389.     ret = X509_verify_cert(vrfy_ctx);
  390.    
  391.     X509_free(server_cert);
  392.     delete [] cert_data;
  393.     X509_STORE_CTX_free(vrfy_ctx);
  394.     X509_STORE_free(store);
  395.    
  396.     return ret == 1;
  397. }
  398.  
  399. int RESTClient::BlockingRequest_HTTPS(const std::string &hst, std::string &org_uri, int nPort, std::string &response, long nTimeout)
  400. {
  401.     // https://202.53.167.179:4443/restapi/setup.php?service=getSensorHistory&user_id=moshiur&baby_id=baby3
  402.     // https://202.53.167.179:4443/restapi/test.php
  403.     SSL_CTX *ctx;
  404.     int server;
  405.     SSL *ssl;
  406.     int bytes;
  407.  
  408.     const char *hostname, *uri, *myReq;
  409.     hostname = hst.c_str();
  410.     response = "";
  411.  
  412.     std::string sUri = org_uri.substr(0, org_uri.find("?"));
  413.     std::string sReq = org_uri.substr(org_uri.find("?") + 1);
  414.  
  415.     uri = ( sUri.c_str() );
  416. #ifdef USE_JSON
  417.     char szJsonReq[MAXSZ];
  418.     ParseIntoJson(sReq, szJsonReq);
  419.     myReq = szJsonReq;
  420. #else
  421.     myReq = ( sReq.c_str() );
  422. #endif
  423.  
  424.     printf("URI: %s // myReq: %s\n", uri, myReq);
  425.  
  426.     SSL_library_init();
  427.  
  428.     ctx = InitCTX();
  429.     if(ctx == NULL){
  430.         printf("Init of ssl context failed\n");
  431.         return -1;
  432.     }
  433.    
  434.     server = OpenConnection(hostname, nPort, nTimeout);
  435.     ssl = SSL_new(ctx);      /* create new SSL connection state */
  436.     SSL_set_fd(ssl, server);    /* attach the socket descriptor */
  437.     int SSL_connect_ret = SSL_connect(ssl);
  438.     printf("SSL_connect_ret = %d   reason = %d\n", SSL_connect_ret, SSL_get_error(ssl,SSL_connect_ret));
  439.     if (SSL_connect_ret == -1 )   /* perform the connection */
  440.         ERR_print_errors_fp(stderr);
  441.     else
  442.     {
  443.         char buf[MAXSZ + 1], msg[MAXSZ + 1];
  444.         sprintf(msg,
  445.             "POST %s HTTP/1.0\r\n"
  446.             "Host: %s:%d\r\n"
  447.             "Content-Type: "CONTENT_TYPE"\r\n"
  448. #ifdef EPHEMERAL_SECURITY
  449.             "Client-Secret: %s\r\n"
  450.             "Client-ID: %s\r\n"
  451. #endif
  452.             "Content-Length: %d\r\n"
  453.             "\r\n"
  454.             "%s\r\n"
  455.             "\r\n\r\n", uri, hostname, nPort
  456. #ifdef EPHEMERAL_SECURITY
  457.             , CreateClientSecretHeader(myReq).c_str(), CSettings::GetInstance()->m_sUsername.c_str()
  458. #endif
  459.             , strlen(myReq), myReq);   
  460.  
  461.         printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
  462.         ShowCerts(ssl);        /* get any certs */
  463.        
  464.         // TODO: certificate verification
  465.         if(VerifiyCertificate(ssl)) {
  466.             printf("Certificate verification success.\n")
  467.         } else {
  468.             printf("Certificate verification failed.\n");
  469.             close(server);
  470.             break;
  471.         }
  472.        
  473.        
  474.         int nError = SSL_write(ssl, msg, strlen(msg));   /* encrypt & send message */
  475.         if(nError < 1)
  476.             printf("SSL write returned = %d reason = %d\n", nError, SSL_get_error(ssl,nError));
  477.         while( (bytes = SSL_read(ssl, buf, sizeof(buf))) > 0) { /* get reply & decrypt */
  478.             buf[bytes] = '\0';
  479.             response += buf;
  480.         }
  481.         SSL_free(ssl);        /* release connection state */
  482.     }
  483.     printf("///// DONE SENDING USING HTTPS ////////\n");
  484.     close(server);         /* close socket */
  485.     SSL_CTX_free(ctx);        /* release context */
  486.  
  487. #ifdef EPHEMERAL_SECURITY
  488.     std::string sStatus = ParseValueForKey(response, "status");
  489.     if(sStatus == "failed")
  490.     {
  491.         std::string sReason = ParseValueForKey(response, "reason");
  492.         if(sReason == "Credential expired")
  493.         {
  494.             printf("Ephemeral credentials expired\n");
  495.             if(!LoginEngine::GetInstance()->GetEphemeralCredentials())
  496.             {
  497.                 printf("Forcefully logging out\n");
  498.                 LoginEngine::GetInstance()->xmppLogout();
  499.                 LoginEngine::GetInstance()->handleXmppLoginResponse(-1);
  500.             }
  501.         }
  502.     }
  503. #endif
  504.  
  505.     return 0;
  506. }
  507.  
  508. int RESTClient::ParseIntoJson(const std::string& strSrc, char* pcDest)
  509. {
  510.     const char *pcSrc = strSrc.c_str();
  511.     *pcDest++ = '{';
  512.     *pcDest++ = '\"';
  513.  
  514.     while(*pcSrc != '\0')
  515.     {
  516.         if(*pcSrc == '&')
  517.         {
  518.             *pcDest++ = '\"';
  519.             *pcDest++ = ',';
  520.             *pcDest++ = '\"';
  521.         }
  522.         else if(*pcSrc == '=')
  523.         {
  524.             *pcDest++ = '\"';
  525.             *pcDest++ = ':';
  526.             *pcDest++ = '\"';
  527.         }
  528.         else
  529.         {
  530.             *pcDest++ = *pcSrc;
  531.         }
  532.         pcSrc ++;
  533.     }
  534.  
  535.     *pcDest++ = '\"';
  536.     *pcDest++ = '}';
  537.     *pcDest = '\0';
  538.     return strlen(pcDest);
  539. }
  540.  
  541. // assuming, the json has the format = { "key1" :  "value1", "key2": "value2" ... }
  542. std::string RESTClient::ParseValueForKey(const std::string& strJson, const std::string strKey)
  543. {
  544.     size_t pos = ToLower(strJson).find("\"" + ToLower(strKey) + "\"");
  545.     if(pos == string::npos)
  546.         return "";
  547.     pos += strKey.size() + 2;
  548.     while(pos < strJson.size() && strJson[pos] != ':')
  549.         ++pos;     
  550.     if(pos == strJson.size())
  551.         return "";
  552.     ++pos;
  553.     while(pos < strJson.size() && strJson[pos] != '"')
  554.         ++pos;
  555.     if(pos == strJson.size())
  556.         return "";
  557.     ++pos;
  558.     std::string ret = "";
  559.     while(pos < strJson.size() && strJson[pos] != '"')
  560.         ret += strJson[pos++];
  561.     if(pos == strJson.size())
  562.         return "";
  563.  
  564.     return ret;
  565. }
  566.  
  567. std::string RESTClient::CreateClientSecretHeader(const std::string &sMsg)
  568. {
  569.     string sUsername = CSettings::GetInstance()->m_sUsername;
  570.     string sPassword = CSettings::GetInstance()->m_sPassword;
  571.     string sDomain = CSettings::GetInstance()->m_sXmppDomain;
  572.  
  573.     string sHash_md5 = GenerateHash_md5((sUsername + ':' + sDomain + ':' + sPassword).c_str());
  574.     string sHash_sha256 = GenerateHash_sha256((sHash_md5 + ':' + sMsg).c_str());
  575.  
  576.     return sHash_sha256;
  577. }
  578.  
  579. #if 0
  580. int RESTClient::NonBlockingRequest(const std::string& strRequestUrl, long nTimout, void (*ResponseCallback) (std::string strResponse, void* args))
  581. {
  582.  
  583. }
  584. #endif
Advertisement
Add Comment
Please, Sign In to add comment