| /* dimeclient.cpp |
| |
| Example streaming DIME client for DIME server (dimeserver.cpp). |
| Supports three methods: |
| |
| putData stores multiple data sets on the server and returns |
| named references to each data set |
| getData retrieves data sets given named references. |
| getImage is an example file-based image retrieval method |
| |
| Change the endpoint in dime.h to your needs. |
| |
| Copyright (C) 2000-2003 Robert A. van Engelen, Genivia, Inc. |
| All Rights Reserved. |
| |
| Usage (server): |
| |
| Start dimeserver on your host at port 8085 (see dimeserver.cpp): |
| |
| dimeserver 8085 & |
| |
| Usage (client): |
| |
| dimeclient [-p] [-g] [-i] name ... |
| |
| dimeclient |
| Without args retrieves image.jpg |
| dimeclient name |
| Retrieves image stored under name |
| dimeclient -p name1 name2 ... |
| Stores files name1, name2, etc. The storage keys are printed. |
| The keys provide access to the data on the server. |
| dimeclient -g name1 name2 ... |
| Retrieves files stored under keys name1, name2, etc. |
| The keys must correspond to the keys returned when storing |
| files. Files are stored locally under the key name. |
| |
| Unix/Linux: add a sigpipe handler to avoid broken pipes. |
| */ |
| |
| #include "soapH.h" |
| #include "dime.nsmap" |
| #include <assert.h> |
| |
| // use the default endpoint set in dime.h for demo: |
| const char *endpoint = NULL; |
| // use the localhost for -p and -g (put and get): |
| const char *localhost = "http://localhost:8085"; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Forward decls |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static void putData(struct soap*, int, char**); |
| static void getData(struct soap*, int, char**); |
| static void getImage(struct soap*, char*); |
| static void saveData(ns__Data&, const char*); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Streaming DIME attachment content handlers |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static void *dime_read_open(struct soap*, void*, const char*, const char*, const char*); |
| static void dime_read_close(struct soap*, void*); |
| static size_t dime_read(struct soap*, void*, char*, size_t); |
| static void *dime_write_open(struct soap*, const char*, const char*, const char*); |
| static void dime_write_close(struct soap*, void*); |
| static int dime_write(struct soap*, void*, const char*, size_t); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Main |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| int main(int argc, char **argv) |
| { struct soap soap; |
| // use HTTP 1.1 chunking |
| // HTTP chunking allows streaming of DIME content without requiring DIME attachment size to be set |
| // DIME attachments can be streamed without chunking ONLY if the attachment size is set |
| soap_init1(&soap, SOAP_IO_CHUNK); |
| // set DIME callbacks |
| soap.fdimereadopen = dime_read_open; |
| soap.fdimereadclose = dime_read_close; |
| soap.fdimeread = dime_read; |
| soap.fdimewriteopen = dime_write_open; |
| soap.fdimewriteclose = dime_write_close; |
| soap.fdimewrite = dime_write; |
| // connect timeout value (not supported by Linux) |
| soap.connect_timeout = 10; |
| // IO timeouts |
| soap.send_timeout = 30; |
| soap.recv_timeout = 30; |
| // Unix/Linux SIGPIPE, this is OS dependent: |
| // soap.accept_flags = SO_NOSIGPIPE; // some systems like this |
| // soap.socket_flags = MSG_NOSIGNAL; // others need this |
| // signal(SIGPIPE, sigpipe_handle); // or a sigpipe handler (portable) |
| if (argc < 3) |
| { char *name; |
| if (argc < 2) |
| name = "image.jpg"; |
| else |
| name = argv[1]; |
| getImage(&soap, name); |
| } |
| else |
| { switch (argv[1][1]) |
| { case 'p': |
| endpoint = localhost; |
| putData(&soap, argc, argv); |
| break; |
| case 'g': |
| endpoint = localhost; |
| getData(&soap, argc, argv); |
| break; |
| default: |
| fprintf(stderr, "Usage: [-p] [-g] name ...\n"); |
| exit(0); |
| } |
| } |
| soap_destroy(&soap); |
| soap_end(&soap); |
| soap_done(&soap); |
| return SOAP_OK; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Helper functions |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static void putData(struct soap *soap, int argc, char **argv) |
| { arrayOfData data; |
| arrayOfName names; |
| data.resize(argc - 2); |
| for (int i = 2; i < argc; i++) |
| { data[i - 2].__ptr = (unsigned char*)argv[i]; |
| // MUST set id or type to enable DIME |
| // zero size indicates streaming DIME (this requires HTTP chunking) |
| data[i - 2].type = ""; |
| } |
| if (soap_call_ns__putData(soap, endpoint, NULL, &data, &names)) |
| soap_print_fault(soap, stderr); |
| else |
| { printf("Data stored with keys:\n"); |
| for (int j = 0; j < names.size(); j++) |
| printf("\t%s\n", names[j]); |
| printf("Use these keys to retrieve the data\n"); |
| } |
| } |
| |
| static void getData(struct soap *soap, int argc, char **argv) |
| { arrayOfData data; |
| arrayOfName names; |
| names.resize(argc - 2); |
| for (int i = 2; i < argc; i++) |
| names[i - 2] = argv[i]; |
| soap->user = (void*)names.__ptr; |
| if (soap_call_ns__getData(soap, endpoint, NULL, &names, &data)) |
| soap_print_fault(soap, stderr); |
| else |
| { for (int j = 0; j < data.size(); j++) |
| if (!data[j].id) |
| saveData(data[j], argv[j + 2]); |
| printf("Data retrieved\n"); |
| } |
| } |
| |
| static void getImage(struct soap *soap, char *name) |
| { ns__Data image; |
| arrayOfName temp; |
| temp.resize(1); |
| temp[0] = name; |
| soap->user = (void*)temp.__ptr; |
| if (soap_call_ns__getImage(soap, endpoint, NULL, name, image)) |
| soap_print_fault(soap, stderr); |
| else if (image.id) |
| { if (image.__size) |
| printf("Got image %s size=%d type=%s through streaming DIME\n", name, image.__size, image.type?image.type:""); |
| else |
| printf("Got image %s type=%s through chunked streaming DIME\n", name, image.type?image.type:""); |
| } |
| else |
| { printf("Got image %s\n", name); |
| saveData(image, name); |
| } |
| } |
| |
| static void saveData(ns__Data& data, const char *name) |
| { char *buf = (char*)data.__ptr; |
| int len = data.__size; |
| FILE *fd = fopen(name, "wb"); |
| if (!fd) |
| { fprintf(stderr, "Cannot save file %s\n", name); |
| return; |
| } |
| while (len) |
| { size_t nwritten = fwrite(buf, 1, len, fd); |
| if (!nwritten) |
| { fprintf(stderr, "Cannot write to %s\n", name); |
| return; |
| } |
| len -= nwritten; |
| buf += nwritten; |
| } |
| printf("Saved file %s\n", name); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Streaming DIME attachment content handlers |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static void *dime_read_open(struct soap *soap, void *handle, const char *id, const char *type, const char *options) |
| { FILE *fd; |
| // we should return NULL without setting soap->error if we don't want to use the streaming callback for this DIME attachment. The handle contains the non-NULL __ptr field value which should have been set in the application. |
| // return value of this function will be passed on to the fdimeread and fdimereadclose callbacks. The return value will not affect the __ptr field. |
| fd = fopen((char*)handle, "rb"); |
| return (void*)fd; |
| } |
| |
| static void dime_read_close(struct soap *soap, void *handle) |
| { fclose((FILE*)handle); |
| } |
| |
| static size_t dime_read(struct soap *soap, void *handle, char *buf, size_t len) |
| { return fread(buf, 1, len, (FILE*)handle); |
| } |
| |
| static void *dime_write_open(struct soap *soap, const char *id, const char *type, const char *options) |
| { // we can return NULL without setting soap->error if we don't want to use the streaming callback for this DIME attachment |
| FILE *handle = NULL; |
| char *name; |
| // get file name from options (not '\0' terminated) |
| if (options) |
| { size_t len = ((unsigned char)options[2] << 8) | ((unsigned char)options[3]); // option string length |
| name = (char*)soap_malloc(soap, len + 1); |
| strncpy(name, options + 4, len); |
| name[len] = '\0'; |
| handle = fopen(name, "wb"); |
| if (!handle) |
| { soap->error = SOAP_EOF; // could not open file for writing |
| soap->errnum = errno; // get reason |
| return NULL; |
| } |
| } |
| else |
| soap->error = soap_receiver_fault(soap, "Cannot save to file, because no file name was present in attachment", NULL); |
| return (void*)handle; |
| } |
| |
| static void dime_write_close(struct soap *soap, void *handle) |
| { fclose((FILE*)handle); |
| } |
| |
| static int dime_write(struct soap *soap, void *handle, const char *buf, size_t len) |
| { while (len) |
| { size_t nwritten = fwrite(buf, 1, len, (FILE*)handle); |
| if (!nwritten) |
| { soap->errnum = errno; // get reason |
| return SOAP_EOF; |
| } |
| len -= nwritten; |
| buf += nwritten; |
| } |
| return SOAP_OK; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // ns__Data class |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| ns__Data::ns__Data() |
| { __ptr = NULL; |
| __size = 0; |
| id = NULL; |
| type = NULL; |
| options = NULL; |
| soap = NULL; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // arrayOfData class |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| arrayOfData::arrayOfData() |
| { __ptr = NULL; |
| __size = 0; |
| soap = NULL; |
| } |
| |
| arrayOfData::arrayOfData(struct soap *soap, int n) |
| { __ptr = NULL; |
| __size = 0; |
| this->soap = soap; |
| resize(n); |
| } |
| |
| arrayOfData::~arrayOfData() |
| { resize(0); |
| } |
| |
| int arrayOfData::size() |
| { return __size; |
| } |
| |
| void arrayOfData::resize(int n) |
| { if (__ptr) |
| { if (soap) // if created by soap environment |
| soap_delete(soap, __ptr); // then delete |
| else |
| delete[] __ptr; |
| } |
| __size = n; |
| if (n <= 0) |
| __ptr = NULL; |
| else if (soap) |
| __ptr = soap_new_ns__Data(soap, n); |
| else |
| __ptr = new ns__Data[n]; |
| } |
| |
| ns__Data& arrayOfData::operator[](int i) const |
| { assert(__ptr && i >= 0 && i < __size); |
| return __ptr[i]; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // arrayOfName class |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| arrayOfName::arrayOfName() |
| { __ptr = NULL; |
| __size = 0; |
| soap = NULL; |
| } |
| |
| arrayOfName::arrayOfName(struct soap *soap, int n) |
| { __ptr = NULL; |
| __size = 0; |
| this->soap = soap; |
| resize(n); |
| } |
| |
| arrayOfName::~arrayOfName() |
| { resize(0); |
| } |
| |
| int arrayOfName::size() |
| { return __size; |
| } |
| |
| void arrayOfName::resize(int n) |
| { if (__ptr) |
| { if (soap) // if created by soap environment |
| soap_delete(soap, __ptr); // then delete |
| else |
| free(__ptr); |
| } |
| __size = n; |
| if (n <= 0) |
| __ptr = NULL; |
| else |
| { if (soap) |
| __ptr = (char**)soap_malloc(soap, sizeof(char*) * n); |
| else |
| __ptr = (char**)malloc(sizeof(char*) * n); |
| memset(__ptr, 0, n); |
| } |
| } |
| |
| char*& arrayOfName::operator[](int i) const |
| { assert(__ptr && i >= 0 && i < __size); |
| return __ptr[i]; |
| } |
| |