source: trunk/stoposserver.cpp

Last change on this file was 7, checked in by willem, 11 years ago

willem

File size: 10.5 KB
Line 
1
2/*
3   Copyright 2013 Willem Vermin, SURFsara
4
5   Licensed under the Apache License, Version 2.0 (the "License");
6   you may not use this file except in compliance with the License.
7   You may obtain a copy of the License at
8
9       http://www.apache.org/licenses/LICENSE-2.0
10
11   Unless required by applicable law or agreed to in writing, software
12   distributed under the License is distributed on an "AS IS" BASIS,
13   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   See the License for the specific language governing permissions and
15   limitations under the License.
16 */
17#include <iostream>
18#include <stdlib.h>
19#include <vector>
20#include <string>
21#include "stopos.h"
22#include "wutils.h"
23#include "stopos_pool.h"
24#ifdef MAKE_GDBM
25#include "gdbm_pool.h"
26#endif
27#ifdef MAKE_FLAT
28#include "flatfile_pool.h"
29#endif
30#ifdef MAKE_FILES
31#include "files_pool.h"
32#endif
33#ifdef MAKE_MYSQL
34#include "mysql_pool.h"
35#endif
36
37void output(const std::string &return_message, const std::string &key,
38             longuint committed, 
39             longuint count,
40             longuint present,
41             longuint present0,
42             const std::string &return_value)
43{
44  std::cout << "STOPOS:"                            << outsep <<
45               zstrtohex(return_message)            << outsep <<
46               zstrtohex(key)                       << outsep <<
47               zstrtohex(NumberToString(committed)) << outsep <<
48               zstrtohex(NumberToString(count))     << outsep <<
49               zstrtohex(NumberToString(present))   << outsep <<
50               zstrtohex(NumberToString(present0))  << outsep <<
51               zstrtohex(return_value)              << 
52               std::endl;
53}
54
55void output(const std::string &msg)
56{
57  output(msg,"",0,0,0,0,"");
58}
59struct commandline
60{
61  std::string header;
62  std::string prot;
63  std::string id;
64  std::string pool;
65  std::string command;
66  std::string multi;
67  std::string value;
68  std::string full_dbname;
69  std::string return_value;
70  stopos_pool *handler;
71
72  int create_full_dbname(void)
73  {
74    if (this->prot == "gdbm" ||
75        this->prot == "flat" ||
76        this->prot == "files")
77    {
78      std::string db_dir = DB_DIR;
79      if (db_dir == "" ) db_dir = "/tmp";
80      db_dir += "/";
81
82      this->full_dbname = db_dir                +
83                          zstrtohex(this->id)   +
84                          "/"                   +
85                          zstrtohex(this->pool) +
86                          "_"                   +
87                          this->prot;
88    }
89    else if (this->prot == "mysql")
90    {
91      this->full_dbname = zstrtohex(this->id) +
92                          "_"                 +
93                          zstrtohex(this->pool);
94    }
95    else
96      return 1;
97
98    if (this->command != "pools")
99      this->handler->set_db_name(this->full_dbname);
100    return 0;
101  }
102
103  int create_handler()
104  {
105#ifdef MAKE_GDBM
106    if (this->prot == "gdbm")
107    {
108      this->handler = new gdbm_pool();
109    }
110#endif
111#ifdef MAKE_FLAT
112    else if (this->prot == "flat")
113    {
114      this->handler = new flatfile_pool();
115    }
116#endif
117#ifdef MAKE_FILES
118    else if (this->prot == "files")
119    {
120      this->handler = new files_pool();
121    }
122#endif
123#ifdef MAKE_MYSQL
124    else if (this->prot == "mysql")
125    {
126      this->handler = new mysql_pool();
127    }
128#endif
129    else
130    {
131      this->return_value = "ERROR: Unknown handler:" + this->prot;
132      return 1;
133    }
134    return 0;
135  }
136
137  int init()
138  {
139
140    int rc;
141    if (this->command != "pools")
142    {
143      rc = this->create_handler();
144      if (rc != 0) 
145        return rc;
146      if (this->multi == "yes")
147        this->handler->set_kvp(1);
148      else
149        this->handler->set_kvp(0);
150    }
151    rc = this->create_full_dbname();
152    return rc;
153  }
154
155  int create_db()
156  {
157    int rc = this->handler->create_db();
158    return rc;
159  }
160
161  int purge_db()
162  {
163    int rc = this->handler->purge_db();
164    return rc;
165  }
166
167  int add_line(std::string &key, std::string &r)
168  {
169    r = "";
170    int rc;
171    rc = this->handler->open_db();
172    if (rc != 0)
173      return rc;
174
175    rc = this->handler->add_line(this->value,key);
176    return rc;
177  }
178
179  int get_line(std::string &key, longuint &comm, std::string &r)
180  {
181    r = "";
182    int rc;
183    rc = this->handler->open_db();
184    if (rc != 0)
185      return rc;
186
187    rc = this->handler->get_line(this->return_value, comm, key);
188    return rc;
189  }
190
191  int dump_line(std::string &key, longuint &comm, std::string &r)
192  {
193    r = "";
194    int rc;
195    rc = this->handler->open_db();
196    if (rc != 0)
197      return rc;
198
199    rc = this->handler->dump_line(this->return_value, comm, key);
200    return rc;
201  }
202
203  int remove_line(std::string & rkey,std::string &key, std::string &r)
204  {
205    r = "";
206    int rc;
207    rc = this->handler->open_db();
208    if (rc != 0)
209      return rc;
210
211    rkey = key;
212    rc = this->handler->remove_line(key);
213    return rc;
214  }
215
216  int get_status(longuint &count, 
217                 longuint &present, 
218                 longuint &present0, 
219                 std::string &r)
220  {
221    r = "";
222    int rc;
223    rc = this->handler->open_db();
224    if (rc != 0)
225      return rc;
226
227    rc = this->handler->get_counts(count, present, present0);
228
229    return rc;
230  }
231};
232
233std::string sanitycheck(commandline &l)
234{
235  if (l.header != "stopos")
236    return "invalid header: '" + l.header + "'";
237
238  if (l.prot.find_first_of(' ') != l.prot.npos)
239    return "ERROR: No valid protocol given";
240
241  if(l.id.find_first_of(' ') != l.id.npos)
242    return "ERROR: No valid id given";
243
244  if(l.command != "pools")
245    if(l.pool.find_first_of(' ') != l.pool.npos)
246    {
247      return "ERROR: No valid pool given";
248    }
249  if(l.command.find_first_of(' ') != l.command.npos)
250  {
251    return "ERROR: No valid command given";
252  }
253  return "";
254}
255
256int parsecom(commandline &l,std::string &line)
257{
258  std::vector <std::string> v;
259  split(v,line,httpsep); 
260                       
261  for (unsigned int i =0; i<v.size(); i++)
262  {
263    switch(i)
264    {
265      case 0: l.header   = zhextostr(v[i]); break;
266      case 1: l.prot     = zhextostr(v[i]); break;
267      case 2: l.id       = zhextostr(v[i]); break;
268      case 3: l.pool     = zhextostr(v[i]); break;
269      case 4: l.command  = zhextostr(v[i]); break;
270      case 5: l.multi    = zhextostr(v[i]); break;
271      case 6: l.value    = zhextostr(v[i]); break;
272    }
273  }
274  return 0;
275}
276
277
278int executecom(commandline &l)
279{
280  int rc;
281  longuint committed = 0;
282  longuint count     = 0;
283  longuint present   = 0;
284  longuint present0  = 0;
285
286  std::string return_message;
287  std::string key;
288  rc = l.init();
289
290  if (rc != 0)
291  {
292    if (l.return_value.size() == 0)
293      output("ERROR: cannot initialize server software");
294    else
295      output(l.return_value);
296    return rc;
297  }
298
299  if (l.command == "create")
300  {
301    rc = l.create_db();
302    if (rc != 0)
303      return_message = "ERROR: cannot create pool "+l.pool;
304  }
305  else if (l.command == "purge")
306  {
307    rc = l.purge_db();
308  }
309  else if (l.command == "add")
310  {
311    rc = l.add_line(key,return_message);
312  }
313  else if (l.command == "next")
314  {
315    rc = l.get_line(key, committed,return_message);
316  }
317  else if (l.command == "dump")
318  {
319    rc = l.dump_line(key, committed,return_message);
320  }
321  else if (l.command == "remove")
322  {
323    rc = l.remove_line(key,l.value, return_message);
324  }
325  else if (l.command == "status")
326  {
327    rc = l.get_status(count,present,present0,return_message);
328  }
329  else if (l.command == "pools")
330  {
331    if      (l.prot == "mysql")
332    {
333      l.return_value = "No pools for mysql";
334      rc = 0;
335    }
336    else if (l.prot == "files" ||
337             l.prot == "gdbm"  ||
338             l.prot == "flat"  )
339    {
340      // extract the directory from full_dbname:
341      size_t p = l.full_dbname.find_last_of('/');
342      if (p == l.full_dbname.npos)
343        rc = 1;
344      else
345      {
346        std::string dir = l.full_dbname.substr(0,p+1);
347        std::list <std::string> v;
348        get_dir_list(v,dir);
349        v.sort();
350
351        l.return_value = "";
352        for (std::list<std::string>::iterator it=v.begin(); it != v.end(); ++it)
353        {
354          std::string f = *it;
355          //
356          // if suffix ( eg: _files ) is found
357          // this could be a valid file name
358          //
359
360          size_t sufsize = l.prot.size()+1;
361          if (sufsize > f.size())
362            continue;
363          p = f.size() - sufsize;
364          if (f.substr(p) != "_"+l.prot)
365            continue;
366#if 0
367          p = f.rfind("_"+l.prot);
368          if (p == f.npos)
369            continue;
370#endif
371          f = f.substr(0,p);
372          //
373          // strip directory part
374          //
375          p = f.find_last_of('/');
376          f = f.substr(p+1);
377          l.return_value += zhextostr(f);
378          l.return_value.push_back(' ');
379        }
380        if (l.return_value.size() > 0)
381          l.return_value.erase(l.return_value.size()-1);
382      }
383      rc = 0;
384    }
385  }
386  else rc = 1;
387  if (rc == 0)
388    return_message="OK";
389  else
390    if (return_message == "")
391    {
392      switch (rc)
393      {
394        case stopos_pool::ERROR          : return_message = "ERROR";                                         break;
395        case stopos_pool::NOFILENAME     : return_message = "ERROR: No file name given";                     break;
396        case stopos_pool::OPENERROR      : return_message = "ERROR: Cannot find pool '"      + l.pool + "'"; break;
397        case stopos_pool::STOREERROR     : return_message = "ERROR: Cannot write to pool '"  + l.pool + "'"; break;
398        case stopos_pool::FETCHERROR     : return_message = "ERROR: Cannot read from pool '" + l.pool + "'"; break;
399        case stopos_pool::NOTFOUND       : return_message = "WARNING: Line not found";                       break;
400        case stopos_pool::NOTIMPLEMENTED : return_message = "ERROR: Feature not implemented";                break;
401        case stopos_pool::REMOVEERROR    : return_message = "ERROR: Cannot remove line";                     break;
402        case stopos_pool::LOCKERROR      : return_message = "ERROR: Cannot get lock";                        break;
403        case stopos_pool::CLOSEERROR     : return_message = "ERROR: Cannot close pool '"     + l.pool + "'"; break;
404        case stopos_pool::UNLOCKERROR    : return_message = "ERROR: Cannot unlock pool '"    + l.pool + "'"; break;
405        case stopos_pool::DBNOTOPEN      : return_message = "ERROR: Pool is not opened '"    + l.pool + "'"; break;
406        case stopos_pool::CREATEERROR    : return_message = "ERROR: Cannot create pool '"    + l.pool + "'"; break;
407        case stopos_pool::PURGEERROR     : return_message = "ERROR: Cannot purge pool '"     + l.pool + "'"; break;
408        case stopos_pool::RECORDTOOLONG  : return_message = "ERROR: Record too long";                        break;
409        default                          : return_message = "ERROR";                                         break;
410
411      }
412    }
413 
414
415  output(return_message, key, committed, count,
416         present, present0, l.return_value);
417  return rc;
418}
419
420int main()
421{
422  int rc;
423  std::cout << "Content-Type: text/plain\n\n";
424  std::string line;
425  line = envtostr("QUERY_STRING");
426  if (line.size() >0)
427    if (line[0] == '/')
428      line.erase(0,1);
429
430  commandline l;
431  parsecom(l,line);
432  std::string msg = sanitycheck(l);
433  if (msg != "")
434  {
435    output(msg);
436    return 1;
437  }
438  rc = executecom(l);
439
440  return rc;
441}
Note: See TracBrowser for help on using the repository browser.