⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dimeserver.cpp

📁 linux下简单对象应用协议的开发库
💻 CPP
字号:
/*	dimeserver.cpp	Example streaming DIME server. Supports three methods:	putData stores multiple data sets on the server and returns named keys		to each data set. The keys are unique and provide access to		the data. Once data is stored, it cannot be removed.	getData retrieves data sets given a set of named keys.	getImage is an example file-based image retrieval method	Data is stored in the current directory or the directory specified	by the TMPDIR environment variable.	Runs as CGI (not multi-threaded) or multi-threaded stand-alone	Web service	Copyright (C) 2000-2003 Robert A. van Engelen, Genivia, Inc.	All Rights Reserved.	NOTE: THE SERVER WILL ONLY SEND FILES THAT ARE IN THE CURRENT DIR FOR	SECURITY REASONS. HOWEVER, THE AUTHOR IS NOT RESPONSIBLE FOR ANY DAMAGES	THAT MAY RESULT FROM THE USE OF THIS PROGRAM.		Usage:	For stand-alone Web service functionality, run from the command line	with port number as command line argument, e.g.	> dimeserver 8085 &	Use port 80 to run as HTTP Web server accessible over the Web	Change the 'endpoint' in 'dimeclient.cpp' to	endpoint="http://machine:8085"	where 'machine' is the host name of the machine on which the service	runs, or 'localhost' if the server runs on the same machine. Be careful	to run the client in a separate directory from the server. Otherwise,	the client and server may interfere in their file access.	The service is multi-threaded. Multi-threading is not required, but can	improve QoS. Remove the pthread code to obtain a non-multi-threaded	service.	Unix/Linux: add a sigpipe handler to avoid broken pipes with	stand-alone server.*/#include "soapH.h"#include "dime.nsmap"#include <pthread.h>	// use Pthreads#include <sys/stat.h>	// use fstat() for streaming DIME#include <assert.h>#define BACKLOG		(100)	// max request backlog#define MAX_FILE_SIZE	(10000)	// max file size when buffering file for HTTP 1.0 and file size cannot be determined////////////////////////////////////////////////////////////////////////////////////	Forward decls//////////////////////////////////////////////////////////////////////////////////static void *process_request(void*);static int getdata(struct soap*, const char*, ns__Data&);static void saveData(ns__Data&, const char*);static void sigpipe_handle(int);////////////////////////////////////////////////////////////////////////////////////	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);////////////////////////////////////////////////////////////////////////////////////	Data for streaming DIME write handler//////////////////////////////////////////////////////////////////////////////////struct dime_write_handle{ char *name;	// file name  FILE *fd;	// file fd};////////////////////////////////////////////////////////////////////////////////////	Static data//////////////////////////////////////////////////////////////////////////////////static char *TMPDIR = ".";////////////////////////////////////////////////////////////////////////////////////	Main//////////////////////////////////////////////////////////////////////////////////int main(int argc, char **argv){ struct soap soap;  char *s = getenv("TMPDIR");  if (s)    TMPDIR = s;  // use HTTP chunking when possible  // 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_KEEPALIVE | 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;  if (argc < 2)  { // no args: assume this is a CGI application    // serve request    soap_serve(&soap);    // cleanup class instances    soap_destroy(&soap);    // cleanup    soap_end(&soap);  }  else  { struct soap *tsoap;    pthread_t tid;    int port;    int m, s, i;    // Unix 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)    // port is first command line argument    port = atoi(argv[1]);    // bind to current host and specified port    m = soap_bind(&soap, NULL, port, BACKLOG);    // if we could not bind, exit    if (m < 0)    { soap_print_fault(&soap, stderr);      exit(1);    }    fprintf(stderr, "Socket connection successful %d\n", m);    // die after 24 hrs waiting for activity on port    soap.accept_timeout = 24*60*60;    // IO timeouts    soap.send_timeout = 30;    soap.recv_timeout = 30;    // loop through requests    for (i = 1; ; i++)    { // accept request      s = soap_accept(&soap);      // if timeout or error, report      if (s < 0)      { if (soap.errnum)          soap_print_fault(&soap, stderr);	else          fprintf(stderr, "Server timed out\n");	break;      }      fprintf(stderr, "Thread %d accepts socket %d connection from IP %d.%d.%d.%d\n", i, s, (int)(soap.ip>>24)&0xFF, (int)(soap.ip>>16)&0xFF, (int)(soap.ip>>8)&0xFF, (int)soap.ip&0xFF);      // copy soap environment and spawn thread      tsoap = soap_copy(&soap);      pthread_create(&tid, NULL, (void*(*)(void*))process_request, (void*)tsoap);    }  }  // detach  soap_done(&soap);  return 0;}void *process_request(void *soap){ pthread_detach(pthread_self());  // serve request (or multiple requests with keep-alive enabled)  soap_serve((struct soap*)soap);  // cleanup class instances  soap_destroy((struct soap*)soap);  // cleanup  soap_end((struct soap*)soap);  // detach thread's copy of soap environment  soap_done((struct soap*)soap);  // free soap environment  free(soap);  return NULL;}////////////////////////////////////////////////////////////////////////////////////	Server methods//////////////////////////////////////////////////////////////////////////////////int ns__putData(struct soap *soap, arrayOfData *data, arrayOfName *names){ // gSOAP switches to SOAP_IO_STORE when SOAP_IO_CHUNK (HTTP chunking) is not supported by the client  // Since it is undesirable to use SOAP_IO_STORE with streaming, we reset it to SOAP_IO_BUFFER  if ((soap->omode & SOAP_IO) == SOAP_IO_STORE)    soap->omode = (soap->omode & ~SOAP_IO) | SOAP_IO_BUFFER;  // return name (key) for each data item  names->resize(data->size());  for (int i = 0; i < data->size(); i++)  { char *s, *name;    // the id field is set when DIME was used so the dime_write callbacks already saved the file    if ((*data)[i].id)    { assert((*data)[i].__ptr);      name = ((struct dime_write_handle*)(*data)[i].__ptr)->name;    }    else    { name = tempnam(TMPDIR, "data");      fprintf(stderr, "Saving file %s\n", name);      saveData((*data)[i], name);    }    s = strrchr(name, '/');    if (!s)      s = strrchr(name, '\\');    if (!s)      s = name;    else      s++;    (*names)[i] = soap_strdup(soap, s);    if (!(*data)[i].id)    { // free data alloced with tempnam()      free(name);    }  }  return SOAP_OK;}int ns__getData(struct soap *soap, arrayOfName *names, arrayOfData *data){ // gSOAP switches to SOAP_IO_STORE when SOAP_IO_CHUNK (HTTP chunking) is not supported by the client.  // Since it is undesirable to use SOAP_IO_STORE, we reset it to SOAP_IO_BUFFER  if ((soap->omode & SOAP_IO) == SOAP_IO_STORE)    soap->omode = (soap->omode & ~SOAP_IO) | SOAP_IO_BUFFER;  if (!names)    return soap_sender_fault(soap, "Names required", NULL);  data->resize(names->size());  for (int i = 0; i < names->__size; i++)  { if (!(*names)[i])      return soap_sender_fault(soap, "Name required", NULL);    if (getdata(soap, (*names)[i], (*data)[i]))      return soap_sender_fault(soap, "Access denied", NULL);  }  return SOAP_OK;}int ns__getImage(struct soap *soap, char *name, ns__Data& image){ if (!name)    return soap_sender_fault(soap, "Name required", NULL);  if (getdata(soap, name, image))    return soap_sender_fault(soap, "Access denied", NULL);  image.type = "image/jpeg";  image.options = soap_dime_option(soap, 0, name);  return SOAP_OK;}////////////////////////////////////////////////////////////////////////////////////	Helper functions//////////////////////////////////////////////////////////////////////////////////static int getdata(struct soap *soap, const char *name, ns__Data& data){ struct stat sb;  FILE *fd = NULL;  if (name && !strchr(name, '/') && !strchr(name, '\\') && !strchr(name, ':'))  { char *s = (char*)soap_malloc(soap, strlen(TMPDIR) + strlen(name) + 2);    strcpy(s, TMPDIR);    strcat(s, "/");    strcat(s, name);    fd = fopen(s, "rb");    if (!fd)    { strcpy(s, name);      fd = fopen(s, "rb");    }  }  if (!fd)    return SOAP_EOF;  if ((soap->omode & SOAP_IO) == SOAP_IO_CHUNK) // chunked response is possible  { data.__ptr = (unsigned char*)fd; // must set to non-NULL (this is our fd handle which we need in the callbacks)    data.__size = 0; // zero size streams data with HTTP chunking  }  else if (!fstat(fileno(fd), &sb) && sb.st_size > 0)  { // since we can get the length of the file, we can stream it    data.__ptr = (unsigned char*)fd; // must set to non-NULL (this is our fd handle which we need in the callbacks)    data.__size = sb.st_size;  }  else // we can't use HTTP chunking and we don't know the size, so buffer it  { int i;    data.__ptr = (unsigned char*)soap_malloc(soap, MAX_FILE_SIZE);    for (i = 0; i < MAX_FILE_SIZE; i++)    { int c;      if ((c = fgetc(fd)) == EOF)        break;      data.__ptr[i] = c;    }    fclose(fd);    data.__size = i;  }  data.type = ""; // specify non-NULL id or type to enable DIME  data.options = soap_dime_option(soap, 0, name);  return SOAP_OK;}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;  }}static void sigpipe_handle(int x) { }////////////////////////////////////////////////////////////////////////////////////	Streaming DIME attachment content handlers//////////////////////////////////////////////////////////////////////////////////static void *dime_read_open(struct soap *soap, void *handle, const char *id, const char *type, const char *options){ // 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.  return handle;}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  struct dime_write_handle *handle = (struct dime_write_handle*)soap_malloc(soap, sizeof(struct dime_write_handle));  if (!handle)  { soap->error = SOAP_EOM;    return NULL;  }  char *name = tempnam(TMPDIR, "data");  fprintf(stderr, "Saving file %s\n", name);  handle->name = soap_strdup(soap, name);  free(name);  handle->fd = fopen(handle->name, "wb");  if (!handle->fd)  { soap->error = SOAP_EOF; // could not open file for writing    soap->errnum = errno; // get reason    return NULL;  }  return (void*)handle;}static void dime_write_close(struct soap *soap, void *handle){ fclose(((struct dime_write_handle*)handle)->fd);}static int dime_write(struct soap *soap, void *handle, const char *buf, size_t len){ while (len)  { size_t nwritten = fwrite(buf, 1, len, ((struct dime_write_handle*)handle)->fd);    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];}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -