OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
ossimToolServer Class Reference

Utility class provides the server interface to ossimTool-derived functionality via TCP sockets Results are returned either as streamed text (for non-image responses such as image info) or streamed binary file representing imagery or vector products. More...

#include <ossimToolServer.h>

Public Member Functions

 ossimToolServer ()
 
 ~ossimToolServer ()
 
void startListening (const char *portid)
 

Private Member Functions

void initSocket (const char *portid)
 
bool processOssimRequest (struct sockaddr_in &cli_addr)
 
bool runCommand (ossimString &command)
 
void writeSocket (const char *buf, int bufsize)
 
bool sendFile (const ossimFilename &fname)
 
void error (const char *msg)
 
bool acknowledgeRcvd ()
 

Static Private Member Functions

static void sigchld_handler (int s)
 

Private Attributes

int m_svrsockfd
 
int m_clisockfd
 
char * m_buffer
 

Detailed Description

Utility class provides the server interface to ossimTool-derived functionality via TCP sockets Results are returned either as streamed text (for non-image responses such as image info) or streamed binary file representing imagery or vector products.

Clients interfacing to this class should know the commands available (or execute the command "help" and view the text response).

See also
ossimToolClient for concrete client implementation.

Definition at line 21 of file ossimToolServer.h.

Constructor & Destructor Documentation

◆ ossimToolServer()

ossimToolServer::ossimToolServer ( )

Definition at line 53 of file ossimToolServer.cpp.

54 : m_svrsockfd(-1),
55  m_clisockfd(-1),
56  m_buffer(new char[MAX_BUF_LEN])
57 {}
#define MAX_BUF_LEN

◆ ~ossimToolServer()

ossimToolServer::~ossimToolServer ( )

Definition at line 59 of file ossimToolServer.cpp.

References m_svrsockfd.

60 {
61  close(m_svrsockfd);
62 }

Member Function Documentation

◆ acknowledgeRcvd()

bool ossimToolServer::acknowledgeRcvd ( )
private

Definition at line 291 of file ossimToolServer.cpp.

References _DEBUG_, error(), m_buffer, m_clisockfd, and n.

Referenced by runCommand(), and sendFile().

292 {
293  if (_DEBUG_) cout<<"ossimToolServer:"<<__LINE__<<" Waiting to recv"<<endl; //TODO REMOVE DEBUG
294  int n = recv(m_clisockfd, m_buffer, 11, 0);
295  if (_DEBUG_) cout<<"ossimToolServer:"<<__LINE__<<" Received <"<<m_buffer<<">"<<endl; //TODO REMOVE DEBUG
296  if (n < 0)
297  error("ossimToolServer: EOF encountered reading from port");
298  if (strcmp(m_buffer, "ok_to_send"))
299  return false;
300  if (_DEBUG_) cout << "Send acknowledged by client."<<endl;
301  return true;
302 }
os2<< "> n<< " > nendobj n
#define _DEBUG_
void error(const char *msg)

◆ error()

void ossimToolServer::error ( const char *  msg)
private

Definition at line 207 of file ossimToolServer.cpp.

Referenced by acknowledgeRcvd(), initSocket(), processOssimRequest(), runCommand(), sendFile(), startListening(), and writeSocket().

208 {
209  perror(msg);
210  exit (1);
211 }

◆ initSocket()

void ossimToolServer::initSocket ( const char *  portid)
private

Definition at line 141 of file ossimToolServer.cpp.

References error(), m_svrsockfd, OINFO, and sigchld_handler().

Referenced by startListening().

142 {
143  // Establish full server address including port:
144  struct addrinfo hints;
145  memset(&hints, 0, sizeof hints); // make sure the struct is empty
146  hints.ai_family = AF_INET; // don't care IPv4 or IPv6
147  hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
148  hints.ai_flags = AI_PASSIVE; // fill in my IP for me
149  struct addrinfo *res;
150 
151  int failed = getaddrinfo(NULL, portid, &hints, &res);
152  if (failed)
153  error(gai_strerror(failed));
154 
155  // Create socket for this server by walking the linked list of available addresses:
156  struct addrinfo *server_info = res;
157  while (server_info)
158  {
159  m_svrsockfd = socket(server_info->ai_family, server_info->ai_socktype, server_info->ai_protocol);
160  if (m_svrsockfd >= 0)
161  break;
162  server_info = server_info->ai_next;
163  }
164  if ((m_svrsockfd < 0) || (server_info == NULL))
165  error("Error opening socket");
166 
167  // lose the pesky "Address already in use" error message when requently restarting the daemon:
168  int yes=1;
169  if (setsockopt(m_svrsockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof yes) == -1)
170  error("Error on setsockopt() call");
171 
172 #if defined (__APPLE__) || defined(__FreeBSD__)
173  int bindResult = ::bind(m_svrsockfd, server_info->ai_addr, server_info->ai_addrlen);
174 #else
175  int bindResult = bind(m_svrsockfd, server_info->ai_addr, server_info->ai_addrlen);
176 #endif
177  // Bind the server's socket to the specified port number:
178  if ( bindResult < 0)
179  error("Error on binding to socket:port.");
180 
181  struct sockaddr_in *server_addr = (sockaddr_in*) &(server_info->ai_addr);
182 
183  OINFO<<"ossimToolServer daemon started. Listening on port "<<portid<<". Process ID: "<<getpid()<<"\n"<<endl;
184  freeaddrinfo(server_info);
185 
186  // Start listening:
187  if (listen(m_svrsockfd, 5) == -1)
188  error("Error on listen()");
189 
190  // Reap all dead processes:
191  struct sigaction sa;
192  sa.sa_handler = ossimToolServer::sigchld_handler;
193  sigemptyset(&sa.sa_mask);
194  sa.sa_flags = SA_RESTART;
195  if (sigaction(SIGCHLD, &sa, NULL) == -1)
196  error("Error on sigaction()");
197 }
#define OINFO
static void sigchld_handler(int s)
void error(const char *msg)

◆ processOssimRequest()

bool ossimToolServer::processOssimRequest ( struct sockaddr_in &  cli_addr)
private

Definition at line 434 of file ossimToolServer.cpp.

References _DEBUG_, error(), m_buffer, m_clisockfd, MAX_BUF_LEN, n, runCommand(), and ossimString::trim().

Referenced by startListening().

435 {
436  char dst[INET6_ADDRSTRLEN];
437 
438  // TEST CODE:
439  cout << "\nprocessOssimRequest() -- Process ID: "<<getpid()<<endl;
440  cout << " Parent process ID: "<<getppid()<<endl;
441 
442  // Clear the input m_buffer and read the message sent:
443  memset(m_buffer, 0, MAX_BUF_LEN);
444  if (_DEBUG_) cout<<"ossimToolServer:"<<__LINE__<<" Waiting to recv"<<endl; //TODO REMOVE DEBUG
445  int n = recv(m_clisockfd, m_buffer, MAX_BUF_LEN, 0);
446  if (_DEBUG_) cout<<"ossimToolServer:"<<__LINE__<<" Received <"<<m_buffer<<">"<<endl; //TODO REMOVE DEBUG
447  if (n < 0)
448  error("ossimToolServer: EOF encountered reading from port");
449 
450  // If message received, acknowledge back:
451  if (n != 0)
452  {
453  // Log the message received:
454  void* addr = &(cli_addr.sin_addr);
455  if (!inet_ntop(AF_INET, addr, dst, INET6_ADDRSTRLEN))
456  error("ossimToolServer: Error returned from inet_ntop(). ");
457  cout << "\nossimToolServer: received message from: "<<dst<<"\n---------------\n"<<m_buffer
458  <<"\n---------------\n"<< endl;
459 
460  // process request:
461  ossimString command (m_buffer);
462  command.trim();
463 
464  if (command == "goodbye")
465  {
466  close(m_clisockfd);
467  return true;
468  }
469 
470  runCommand(command);
471  return true;
472  }
473  return false;
474 }
bool runCommand(ossimString &command)
#define MAX_BUF_LEN
os2<< "> n<< " > nendobj n
#define _DEBUG_
void error(const char *msg)

◆ runCommand()

bool ossimToolServer::runCommand ( ossimString command)
private

Definition at line 304 of file ossimToolServer.cpp.

References acknowledgeRcvd(), ossimString::after(), ossimString::before(), ossimToolFactoryBase::createTool(), ossimString::empty(), error(), ossimTool::execute(), ossimRefPtr< T >::get(), ossimToolFactoryBase::getCapabilities(), ossimChipProcTool::getProductFilename(), ossimTool::helpRequested(), ossimTool::initialize(), ossimToolRegistry::instance(), ossimTool::isChipProcessor(), m_buffer, m_clisockfd, MAX_BUF_LEN, n, sendFile(), ossimString::trim(), ossimRefPtr< T >::valid(), writeSocket(), and x.

Referenced by processOssimRequest().

305 {
306  ostringstream xmsg;
307  bool status_ok = false;
308  static const char* msg = "\nossimToolServer.runCommand(): ";
309 
310  // Intercept test mode:
311  if (command == "sendfile")
312  {
313  ossimFilename fname = command.after("sendfile").trim();
314  const char* response = "FILE ";
315  writeSocket(response, strlen(response));
316  sendFile(fname);
317  return true;
318  }
319 
320  // Redirect stdout:
321  memset(m_buffer, 0, MAX_BUF_LEN);
322  int pipeDesc[2] = {0,0};
323  int savedStdout = dup( fileno(stdout) );
324  if( pipe( pipeDesc ) == -1 )
325  error("Could not redirect stdout (1).");
326  setbuf( stdout, NULL );
327  dup2( pipeDesc[1], fileno(stdout) );
328 
329 #ifdef _MSC_VER
330  u_long iMode = 1;
331  ioctlsocket(pipeDesc[0], FIONBIO, &iMode);
332 #else
333  fcntl( pipeDesc[0], F_SETFL, O_NONBLOCK );
334 #endif
335 
337  ossimRefPtr<ossimTool> utility = 0;
338 
339  // Intercept help request:
340  ossimString c1 = command.before(" ");
341  ossimString c2 = command.after(" ");
342  while (1)
343  {
344  if (c1 == "help")
345  {
346  if (!c2.empty())
347  {
348  command = c2 + " --help";
349  }
350  else
351  {
352  map<string, string> capabilities;
353  factory->getCapabilities(capabilities);
354  map<string, string>::iterator iter = capabilities.begin();
355  cout<<"\nAvailable commands:\n"<<endl;
356  for (;iter != capabilities.end(); ++iter)
357  cout<<" "<<iter->first<<" -- "<<iter->second<<endl;
358  cout<<"\nUse option \"--help\" with above commands to get detailed tool command."<<endl;
359  status_ok = true;
360  break;
361  }
362  }
363  // Fetch OSSIM utility for requested operation:
364  ossimArgumentParser ap (command);
365  ossimString util_name = ap[0];
366  utility = factory->createTool(util_name);
367 
368  try
369  {
370  // Perform OSSIM command execution:
371  if (!utility.valid())
372  cout<<msg<<"Did not understand command <"<<util_name<<">"<<endl;
373  else if (!utility->initialize(ap))
374  cout<<msg<<"Could not execute command sequence <"<<command<<">."<<endl;
375  else if (!utility->helpRequested() && !utility->execute())
376  cout<<msg<<"Error encountered executing\n <"<<command <<">\nCheck options."<<endl;
377  else
378  status_ok = true;
379  }
380  catch (ossimException& x)
381  {
382  cout << msg << "Caught OSSIM exception: "<<x.what()<<endl;
383  }
384  catch (exception& x)
385  {
386  cout << msg << "Caught unknown exception: "<<x.what()<<endl;
387  }
388 
389  break;
390  }
391 
392  // Stop redirecting stdout and copy the output stream buffer to local memory:
393  dup2( savedStdout, fileno(stdout) );
394  int n = MAX_BUF_LEN;
395  string full_output;
396  while (n == MAX_BUF_LEN)
397  {
398  n = read(pipeDesc[0], m_buffer, MAX_BUF_LEN);
399  if (n > 0)
400  full_output.append(m_buffer, n);
401  }
402 
403  if (status_ok)
404  {
405  if (utility.valid() && !utility->helpRequested() && utility->isChipProcessor())
406  {
407  const char* response = "FILE ";
408  writeSocket(response, strlen(response));
409  ossimChipProcTool* ocp = (ossimChipProcTool*) utility.get();
410  ossimFilename prodFilename = ocp->getProductFilename();
411  sendFile(prodFilename);
412  }
413  else
414  {
415  const char* response = "TEXT ";
416  writeSocket(response, strlen(response));
417  writeSocket(full_output.c_str(), full_output.size());
418  if (!acknowledgeRcvd())
419  error("ERROR receiving acknowledge from client.");
420  }
421  }
422  else
423  {
424  const char* response = "ERROR";
425  writeSocket(response, strlen(response));
426  writeSocket(full_output.c_str(), full_output.size());
427  cout << "Sending ERROR to client and closing connection: <"<<full_output<<">"<<endl;
428  close(m_clisockfd);
429  }
430 
431  return status_ok;
432 }
ossim_uint32 x
ossimString before(const ossimString &str, std::string::size_type pos=0) const
METHOD: before(str, pos) Returns string beginning at pos and ending one before the token str If strin...
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
bool valid() const
Definition: ossimRefPtr.h:75
virtual void getCapabilities(std::map< std::string, std::string > &capabilities) const =0
Appends map with available utilities along with descriptions as <name, decription> pairs...
virtual bool isChipProcessor() const
Overrides base class implementation to indicate this class supports getChip() calls.
Definition: ossimTool.h:123
static ossimToolRegistry * instance()
#define MAX_BUF_LEN
os2<< "> n<< " > nendobj n
ossimString trim(const ossimString &valueToTrim=ossimString(" \\)) const
this will strip lead and trailing character passed in.
virtual bool initialize(ossimArgumentParser &ap)
Initializes from command line arguments.
Definition: ossimTool.cpp:58
virtual bool execute()=0
Writes product to output file if applicable.
bool helpRequested() const
Returns true when the initialization detects a "--help" option, so caller can avoid subsequent execut...
Definition: ossimTool.h:134
bool sendFile(const ossimFilename &fname)
bool empty() const
Definition: ossimString.h:411
virtual ossimTool * createTool(const std::string &typeName) const =0
ossimString after(const ossimString &str, std::string::size_type pos=0) const
METHOD: after(str, pos) Returns string immediately after the token str.
void writeSocket(const char *buf, int bufsize)
const ossimFilename & getProductFilename() const
void error(const char *msg)

◆ sendFile()

bool ossimToolServer::sendFile ( const ossimFilename fname)
private

Definition at line 230 of file ossimToolServer.cpp.

References _DEBUG_, acknowledgeRcvd(), ossimString::chars(), error(), ossimFilename::file(), m_buffer, MAX_BUF_LEN, n, and writeSocket().

Referenced by runCommand().

231 {
232  ostringstream xmsg;
233 
234  // Open the server-side image file:
235  ifstream svrfile (fname.chars(), ios::binary|ios::in);
236  if (svrfile.fail())
237  {
238  xmsg<<"ossimToolServer.sendFile() -- Error opening file <"<<fname<<">."<<endl;
239  error(xmsg.str().c_str());
240  }
241 
242  // Determine file size:
243  std::streampos fsize = svrfile.tellg();
244  svrfile.seekg( 0, std::ios::end );
245  fsize = svrfile.tellg() -fsize;
246  svrfile.seekg( 0, std::ios::beg );
247 
248  // Send file size to the client:
249  char size_response[19];
250  sprintf(size_response, "SIZE: %012d", (int) fsize);
251  if (_DEBUG_) cout<<"ossimToolServer:"<<__LINE__<<" sending <"<<size_response<<">"<<endl; //TODO REMOVE DEBUG
252  writeSocket(size_response, strlen(size_response));
253  if (!acknowledgeRcvd())
254  return false;
255 
256  // Send file name to the client:
257  char name_response[256];
258  memset(name_response, 0, 256);
259  sprintf(name_response, "NAME: %s", fname.file().chars());
260  if (_DEBUG_) cout<<"ossimToolServer:"<<__LINE__<<" sending <"<<name_response<<">"<<endl; //TODO REMOVE DEBUG
261  writeSocket(name_response, strlen(name_response));
262  if (!acknowledgeRcvd())
263  return false;
264 
265  memset(m_buffer, 0, MAX_BUF_LEN);
266 
267  // Send image in MAX_BUF_LEN byte packets
268  int n = 0;
269  int r = 0;
270  if (_DEBUG_) cout<<"ossimToolServer:"<<__LINE__<<" sending binary data..."<<endl; //TODO REMOVE DEBUG
271  while (!svrfile.eof())
272  {
273  // Read server-side file block:
274  svrfile.read(m_buffer, MAX_BUF_LEN);
275  if (svrfile.bad())
276  error("ossimToolServer.sendFile() -- Error during file read()");
277 
278  n = svrfile.gcount();
279  r += n;
280 
281  // transmit the block to the client:
283  }
284  if (!acknowledgeRcvd())
285  return false;
286 
287  cout << "Send complete."<<endl;
288  svrfile.close();
289  return true;
290 }
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
#define MAX_BUF_LEN
os2<< "> n<< " > nendobj n
const char * chars() const
For backward compatibility.
Definition: ossimString.h:77
#define _DEBUG_
ossimFilename file() const
void writeSocket(const char *buf, int bufsize)
void error(const char *msg)

◆ sigchld_handler()

void ossimToolServer::sigchld_handler ( int  s)
staticprivate

Definition at line 199 of file ossimToolServer.cpp.

Referenced by initSocket().

200 {
201  // waitpid() might overwrite errno, so we save and restore it:
202  int saved_errno = errno;
203  while(waitpid(-1, NULL, WNOHANG) > 0);
204  errno = saved_errno;
205 }

◆ startListening()

void ossimToolServer::startListening ( const char *  portid)

Definition at line 65 of file ossimToolServer.cpp.

References error(), FORK_PROCESS, initSocket(), m_buffer, m_clisockfd, m_svrsockfd, n, OINFO, and processOssimRequest().

66 {
67  initSocket(portid);
68 
69  socklen_t clilen;
70  ostringstream xmsg;
71  bool status_ok = true;
72 
73  // Loop forever to listen for OSSIM requests:
74  OINFO<<"Waiting for connections...\n"<<endl;
75  while (1)
76  {
77  // Message received at server socket, establish connection to client's socket:
78  struct sockaddr_in cli_addr;
79  clilen = sizeof(cli_addr);
80  m_clisockfd = accept(m_svrsockfd, (struct sockaddr *) &cli_addr, &clilen);
81  if (m_clisockfd < 0)
82  error("Error accepting message on port.");
83 
84  // Test code:
85  char clientname[256];
86  char clientport[256];
87  getnameinfo((struct sockaddr *) &cli_addr, clilen, clientname, 256, clientport, 256, 0);
88  cout<<"ossimToolServer: Got connection from "<<clientname<<":"<<clientport
89  <<" Forking child process..."<<endl;
90 
91 
92 #if 1
93  // Fork process to handle client request:
94  if (FORK_PROCESS)
95  {
96  if (!fork())
97  {
98  // this is the child process
99  close(m_svrsockfd); // child doesn't need the listener
100 
101  // Receive request from client:
102  bool connected = true;
103  while (connected)
104  connected = processOssimRequest(cli_addr);
105 
106  exit(0); // exit forked process
107  }
108  }
109  else
110  {
111  bool connected = true;
112  while (connected)
113  connected = processOssimRequest(cli_addr);
114  }
115 #else
116  int n=0;
117  while (1)
118  {
119  // Clear the input m_buffer and read the message sent:
120  memset(m_buffer, 0, 256);
121  n = recv(m_clisockfd,m_buffer,256,0);
122  if (n < 0)
123  {
124  printf("recv returned -1 from port %d.\n", m_clisockfd);
125  }
126 
127  // Send acknowledgement back to client:
128  printf("Received: %s\n",m_buffer);
129  string msg ="server received message: ";
130  msg.append(m_buffer, strlen(m_buffer));
131  n = send(m_clisockfd, msg.c_str(), msg.size(), 0);
132  if (n < 0)
133  error("ERROR writing to socket");
134  }
135 #endif
136  // Finished serving this client. Close the connection:
137  close(m_clisockfd);
138  }
139 }
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
bool processOssimRequest(struct sockaddr_in &cli_addr)
#define OINFO
#define FORK_PROCESS
os2<< "> n<< " > nendobj n
void initSocket(const char *portid)
void error(const char *msg)

◆ writeSocket()

void ossimToolServer::writeSocket ( const char *  buf,
int  bufsize 
)
private

Definition at line 213 of file ossimToolServer.cpp.

References error(), m_clisockfd, and n.

Referenced by runCommand(), and sendFile().

214 {
215  int remaining = bufsize;
216  int n;
217 
218  //int optval = 1;
219  //setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(int));
220 
221  while (remaining)
222  {
223  n = send(m_clisockfd, buf, remaining, 0);
224  if (n < 0)
225  error("ERROR writing to socket");
226  remaining -= n;
227  }
228 }
os2<< "> n<< " > nendobj n
void error(const char *msg)

Member Data Documentation

◆ m_buffer

char* ossimToolServer::m_buffer
private

◆ m_clisockfd

int ossimToolServer::m_clisockfd
private

◆ m_svrsockfd

int ossimToolServer::m_svrsockfd
private

Definition at line 39 of file ossimToolServer.h.

Referenced by initSocket(), startListening(), and ~ossimToolServer().


The documentation for this class was generated from the following files: