मैंने इसके लिए हर जगह खोज की है और मुझे एक सभ्य कोड नहीं मिला। मैं GSOAP का उपयोग कर Amazon AWS S3 सेवा तक कैसे पहुंच सकता हूं?सी और सी ++ के लिए जीएसओएपी का उपयोग करके मैं अमेज़ॅन एडब्ल्यूएस एस 3 का उपयोग कैसे कर सकता हूं?
उत्तर
नीचे दिया गया कोड ओपी से है। मूल रूप से, पोस्ट में प्रश्न और उत्तर दोनों शामिल थे और मैं इसे एक प्रश्न & प्रारूप में बदल रहा हूं।
हस्ताक्षर प्रारूप
base64encode((HMAC-SHA1(ActionName+"AmazonS3"+XMLTimestamp)))
HMAC, SHA1and B64 utils openssl में उपलब्ध हैं की हो गया है।
एसओएपी अनुरोधों के लिए प्रारूप wsdl द्वारा दिया गया है।
आरईएसटी इंटरफेस अलग है।
wsdl2h
के बाद शीर्ष लेख और soapcpp2 उत्पन्न करने के लिए GSOAP ग्राहक कोड निम्नलिखित कोड सेवा का उपयोग करने होगा उत्पन्न करने के लिए:
कंपाइलर प्रीप्रोसेसर निर्देश WITH_OPENSSL
के साथ बनाएं। लाइब्रेरी libeay32
और ssleay32
के साथ लिंक करें।
#include "AmazonS3SoapBinding.nsmap" //generated from soapcpp2
#include "soapAmazonS3SoapBindingProxy.h" //generated from soapcpp2
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
/* convert to base64 */
std::string base64_encodestring(char* text, int len) {
EVP_ENCODE_CTX ectx;
int size = len*2;
size = size > 64 ? size : 64;
unsigned char* out = (unsigned char*)malloc(size);
int outlen = 0;
int tlen = 0;
EVP_EncodeInit(&ectx);
EVP_EncodeUpdate(&ectx,
out,
&outlen,
(const unsigned char*)text,
len
);
tlen += outlen;
EVP_EncodeFinal(&ectx, out+tlen, &outlen);
tlen += outlen;
std::string str((char*)out, tlen);
free(out);
return str;
}
/* return the utc date+time in xml format */
const char* xml_datetime() {
/*"YYYY-mm-ddTHH:MM:SS.000Z\"*/
const int MAX=25;
static char output[MAX+1];
time_t now = time(NULL);
strftime(output, MAX+1, "%Y-%m-%dT%H:%M:%S.000Z", gmtime(&now));
std::cout <<output<<std::endl;
return output;
}
/* first argument is the signing key */
/* all subsequent argumets are concatenated */
/* must end list with NULL */
char* aws_signature(char* key, ...) {
unsigned int i, len;
char *data, **list = &key;
static char hmac[EVP_MAX_MD_SIZE];
for (i = 1, len = 0; *(list+i) != NULL; ++i) {
len += strlen(*(list+i));
}
data = (char*)malloc(sizeof(char) * (len+1));
if (data) {
for (i = 1, len = 0 ; *(list+i) != NULL ; ++i) {
strncpy(data+len, *(list+i), strlen(*(list+i)));
len += strlen(*(list+i));
}
data[len]='\0';
std::cout<<data<<std::endl;
HMAC(EVP_sha1(),
key, strlen(key),
(unsigned char*)data, strlen(data),
(unsigned char*) hmac, &len
);
free(data);
}
std::string b64data=base64_encodestring(hmac, len);
strcpy(hmac,b64data.c_str());
return hmac;
};
int main(void) {
AmazonS3SoapBindingProxy client;
soap_ssl_client_context(&client,
/* for encryption w/o authentication */
SOAP_SSL_NO_AUTHENTICATION,
/* SOAP_SSL_DEFAULT | SOAP_SSL_SKIP_HOST_CHECK, */
/* if we don't want the host name checks since
* these will change from machine to machine */
/*SOAP_SSL_DEFAULT,*/
/* use SOAP_SSL_DEFAULT in production code */
NULL, /* keyfile (cert+key): required only when
client must authenticate to server
(see SSL docs to create this file) */
NULL, /* password to read the keyfile */
NULL, /* optional cacert file to store trusted
certificates, use cacerts.pem for all
public certificates issued by common CAs */
NULL, /* optional capath to directory with trusted
certificates */
NULL /* if randfile!=NULL: use a file with random
data to seed randomness */
);
/* use this if you are behind a proxy server.....
client.proxy_host="proxyserver"; // proxy hostname
client.proxy_port=4250;
client.proxy_userid="username"; // user pass if proxy
client.proxy_passwd="password"; // requires authentication
client.proxy_http_version="1.1"; // http version
*/
_ns1__ListAllMyBuckets buk_req;
_ns1__ListAllMyBucketsResponse buk_resp;
ns1__ListAllMyBucketsResult buk_res;
buk_res.soap=&client;
buk_req.AWSAccessKeyId=new std::string("ACCESSKEY");
buk_req.soap=&client;
/* ListAllMyBuckets is the method I want to call here.
* change it for other S3 services that you wish to call.*/
char *sig=aws_signature(
"SECRETKEY",
"AmazonS3",
"ListAllMyBuckets",
xml_datetime(),
NULL
);
buk_req.Signature=new std::string(sig);
buk_req.Timestamp=new time_t(time(NULL));
buk_resp.soap=&client;
buk_resp.ListAllMyBucketsResponse=&buk_res;
client.ListAllMyBuckets(&buk_req,&buk_resp);
client.soap_stream_fault(std::cout);
std::vector<ns1__ListAllMyBucketsEntry * >::iterator itr;
for(itr=buk_resp.ListAllMyBucketsResponse->Buckets->Bucket.begin();
itr!=buk_resp.ListAllMyBucketsResponse->Buckets->Bucket.end();
itr++
) {
std::cout<<(*itr)->Name<<std::endl;
}
}
मैं अमेज़न एडब्ल्यूएस C और C++ के लिए GSOAP का उपयोग कर S3 कैसे उपयोग कर सकते हैं?
चरण 1
एक अंतरफलक हेडर फाइल aws-s3.h लिए अमेज़न के S3 डबल्यूएसडीएल कन्वर्ट करने के लिए उपयोग gSOAP के wsd2lh उपकरण:
wsdl2h -t typemap.dat -o aws-s3.h http://doc.s3.amazonaws.com/2006-03-01/AmazonS3.wsdl
उपयोग विकल्प -c
के बजाय सी स्रोत कोड उत्पन्न करने के लिए डिफ़ॉल्ट सी ++ स्रोत कोड। typemap.dat
फ़ाइल gSOAP वितरण की gsoap निर्देशिका में स्थित है।
चरण 2
wsdl2h उपकरण से बनाए गए हेडर फाइल पर soapcpp2 उपकरण का उपयोग करें।
soapcpp2 -C -j aws-s3.h
यह एडब्ल्यूएस-s3.h हैडर से सी ++ सेवा प्रॉक्सी और वस्तुओं (-j
विकल्प) के साथ क्लाइंट-साइड कोड (-C
विकल्प) उत्पन्न करता है। सी कोड के लिए -j
छोड़ दें।
चरण 3
एडब्ल्यूएस S3 पहुँच सकते हैं और एडब्ल्यूएस S3 के लिए एक बेस 64 एन्कोडेड, HMAC-SHA1 हैश हस्ताक्षर बनाना स्वत: जनरेट AmazonS3SoapBindingProxy
प्रॉक्सी विधियों का उपयोग करें।
/*
createbucket.cpp
Example AWS S3 CreateBucket service invocation
*/
#include "soapAmazonS3SoapBindingProxy.h"
#include "AmazonS3SoapBinding.nsmap"
#include <fstream>
// Make allocation of primitive values quick and easy:
template<class T>
T * soap_make(struct soap *soap, T val) {
T *p = (T*)soap_malloc(soap, sizeof(T));
*p = val;
return p;
}
// Make base64-encoded, HMAC-SHA1 hashed signature for AWS S3
std::string soap_make_s3__signature(struct soap *soap, char const *operation, char const *key) {
std::string signature = "AmazonS3";
signature += operation;
char UTCstamp[40]; //to hold ISO 8601 time format
time_t now;
time(&now);
strftime(UTCstamp, sizeof UTCstamp, "%Y-%m-%dT%H:%M:%S.000Z", gmtime(&now));
signature += UTCstamp;
// Get the HMAC-SHA1 digest of the signature string
unsigned char * digest;
digest = HMAC(EVP_sha1(), key, strlen(key),
(unsigned char*)(signature.c_str()),
signature.length(), NULL, NULL);
char signatureBase64[20];
// Convert the digest to base64
soap_s2base64(soap, digest, signatureBase64, sizeof signatureBase64);
return std::string(signatureBase64);
}
// Read access keys from file generated by AWS CLI
bool getAWSKeys(std::string path, std::string user, std::string &accessKey, std::string &secretKey) {
std::ifstream credentialsFile(path.c_str());
if (!credentialsFile.is_open())
return false;
std::string line;
while (std::getline(credentialsFile, line)) {
// Keep going until we get to the desired user
if (line.find(user) == std::string::npos)
continue;
while (std::getline(credentialsFile, line)) {
// Keep going until we get to the access key lines
if (line.find("aws_access_key_id") == std::string::npos)
continue;
// Grab keys and trim whitespace
size_t first, last;
accessKey = line.substr(line.find_first_of('=')+1);
first = accessKey.find_first_not_of(' ');
if (first == std::string::npos)
return false;
last = accessKey.find_last_not_of(' ');
accessKey.substr(first, last-first+1).swap(accessKey);
std::getline(credentialsFile, line);
secretKey = line.substr(line.find_first_of('=')+1);
first = secretKey.find_first_not_of(' ');
if (first == std::string::npos)
return false;
last = secretKey.find_last_not_of(' ');
secretKey.substr(first, last-first+1).swap(secretKey);
return true;
}
}
return false;
}
int main(int argc, char **argv) {
// Load AWS keys from file
std::string accessKey, secretKey;
// Use the path to your AWS credentials file
std::string credentialsFile = (argc > 2 ? argv[2] : "path_to_aws_credentials_file");
std::string user = "default";
if (!getAWSKeys(credentialsFile, user, accessKey, secretKey)) {
std::cout << "Couldn't read AWS keys for user " << user
<< " from file " << credentialsFile << '\n';
return 0;
}
// Create a proxy to invoke AWS S3 services
AmazonS3SoapBindingProxy aws(SOAP_XML_INDENT);
// Create bucket
// Set the arguments of the CreateBucket service operation
_s3__CreateBucket createBucketReq;
std::string bucketName = (argc > 1 ? argv[1] : "BucketName");
createBucketReq.Bucket = bucketName;
createBucketReq.AWSAccessKeyId = soap_new_std__string(aws.soap);
*createBucketReq.AWSAccessKeyId = accessKey;
createBucketReq.Timestamp = soap_make(aws.soap, time(0));
createBucketReq.Signature = soap_new_std__string(aws.soap);
*createBucketReq.Signature = soap_make_s3__signature(aws.soap,
"CreateBucket",
secretKey.c_str());
// Store the result of the service
_s3__CreateBucketResponse createBucketRes;
// Create a bucket
if (aws.CreateBucket(&createBucketReq, createBucketRes)) {
aws.soap_stream_fault(std::cerr);
}
/*
NOTE: you must add the line:
_s3__CreateBucketResponse = $ s3__CreateBucketResult* CreateBucketResponse;
to the typemap.dat file because Amazon's response doesn't match
their promised schema. This adds the variable CreateBucketResponse
to the _s3__CreateBucketResponse class so we can access the response.
*/
else if (createBucketRes.CreateBucketResponse) {
s3__CreateBucketResult &result = *createBucketRes.CreateBucketResponse;
std::cout << "You are the owner of bucket '" << result.BucketName << "'." << std::endl;
}
// Delete all managed data
aws.destroy();
return 0;
}
सी कोड मुख्य अंतर यह फ़ंक्शन का उपयोग होने के साथ समान लग विधि आमंत्रण के बजाय कहता है, यानी soap_call___s3__CreateBucket(&createBucketReq, &createBucketRes)
: हस्ताक्षर HMAC-SHA1 का बेस 64 एन्कोडेड संस्करण के साथ एक स्ट्रिंग टुकड़ों में बांटा स्ट्रिंग "AmazonS3" + OPERATION_NAME + Timestamp
है । यह सब जेनरेट aws-s4.h फ़ाइल में समझाया गया है।
अपने स्रोत कोड के साथ उत्पन्न फ़ाइलों संकलित करें:
c++ -DSOAP_MAXDIMESIZE=104857600 -DWITH_OPENSSL -o createbucket createbucket.cpp soapAmazonS3SoapBindingProxy.cpp soapC.cpp stdsoap2.cpp -lssl -lcrypto
SOAP_MAXDIMESIZE=104857600
सुनिश्चित करता है कि पैसा लगाव आकार इतना बड़ा है, जबकि पैसा का उपयोग कर सेवा हमलों के इनकार को रोकने हो सकता है। DIME हेडर में अनुलग्नक आकार होता है, इसलिए एक हमलावर स्मृति संसाधनों को कम करने के लिए मनमाने ढंग से बड़े सेट कर सकता है। अन्य पदों का उल्लेख करने में असफल रहा।
createbucket
चलाएं, और एक नई बाल्टी बनाई जाएगी।
अंतिम .cpp फ़ाइल में, ध्यान दें कि हम क्रेडेंशियल्स सेट करते समय कमांड लाइन तर्क (argv) जांचते हैं फ़ाइल और बाल्टीनाम। यह अनुमति देता है प्रोग्राम तर्क के साथ कहा जा:
./createbucket BucketName path_to_credentials_file
इस सब के बारे में अधिक जानकारी के लिए, मैं क्रिस Moutsos द्वारा How to use AWS S3 in C++ with gSOAP पर उत्कृष्ट CodeProject लेख इस स्पष्टीकरण के कुछ हिस्सों निकलती है जहाँ से पढ़ने के लिए सुझाव देते हैं।
मुझे पता है कि यह वास्तव में एक प्रश्न नहीं है, लेकिन मैंने सी/सी ++ अमेज़ॅन ऐप बनाने के लिए gsoap + aws के बारे में भी सोचा है। इसके लिए धन्यवाद, भले ही यह लॉक/डाउनवॉटेड/tos'd हो: \ –
क्या आप इसे उचित प्रश्न/उत्तर जोड़ी में प्रारूपित कर सकते हैं? Http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/ –
इस विषय पर पोस्ट किया गया एक लेख है [कोडप्रोजेक्ट जीएसओएपी और एडब्ल्यूएस एस 3 के बारे में ] (https://www.codeproject.com/Articles/1108296/How-to-Use-Amazon- सरल- स्टोरेज- सेवा- एस-in-Cplu) अधिक जानकारी में। उस लेख की एक प्रति जीएसओएपी डेवलपर वेबसाइट पर भी दिखाई देती है। निश्चित नहीं है कि मॉडरेटर ने इन पॉइंटर्स के साथ मेरा जवाब क्यों हटा दिया। –