MCS  0.3.3-alpha7
Client.cc
1 // ----------------------------------------------------------------------^
2 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Giorgio Calderone
3 // (mailto: <gcalderone@ifc.inaf.it>)
4 //
5 // This file is part of MCS.
6 //
7 // MCS is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // MCS is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with MCS; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 // ----------------------------------------------------------------------$
22 
23 #include "mcs.hh"
24 using namespace mcs;
25 
26 
27 
28 //--------------------------------------------------------
29 mcs::Client::Client(string path, string server, int port,
30  bool synchro, bool SSL,
31  unsigned int timeout) :
32  Socket(server, port, timeout, timeout, SSL),
33  RecordSet(),
34  code(synchro),
35  msg(synchro),
36  out(synchro),
37  recv(synchro),
38  aux(synchro)
39 {
40  connected = false;
41  init(0);
42  lpath=path;
43  if (lpath.empty())
44  lpath=Pwd();
45 
46  //Remove trailing slash
47  remTrailing(lpath, "/");
48 
49 
50  connected = true;
51  writetofile = true;
52  lrecord = NULL;
53  exec(""); //Read welcome message
55 
56  unsigned int size;
57  if (! File_Dir_Exist(lpath, size))
58  throw MCS_ERROR(MSG_DIRECTORY_NOT_FOUND, lpath.csz);
59 
60 }
61 
62 
64 {}
65 
66 
67 void mcs::Client::writeToFile(int des)
68 {
69  writetofile = true;
70  fileDescriptor = des;
71 }
72 
73 
74 
75 
76 bool mcs::Client::login(string user, string pass, string db)
77 {
78  bool ret;
79  string bl = " ";
80  string cmd;
81 
82  cmd = MCS_CMD_USERNAME + bl + user;
83  ret = exec(cmd);
84  if (ret) {
85  cmd = MCS_CMD_PASSWORD + bl + pass;
86  ret = exec(cmd);
87  if (ret) {
88  if (! db.empty()) {
89  cmd = MCS_CMD_DBNAME + bl + db;
90  ret = exec(cmd);
91  }
92 
93  if (ret)
94  ret = exec(MCS_CMD_DBCONNECT);
95  }
96  }
97  return ret;
98 }
99 
100 
102 {
103  this->code.clear();
104  this->msg.clear();
105  this->out.clear();
106  this->recv.clear();
107  this->aux.clear();
108 }
109 
110 
111 
112 bool sendRecord(Client* cli, Record* rec)
113 {
114  int i;
115 
116  for (i=0; i<rec->count(); i++)
117  if (! cli->exec(MCS_CMD_PUTDATA, &((*rec)[i])))
118  return false;
119 
120  return true;
121 }
122 
123 
124 bool mcs::Client::exec(string cmd, Data* data)
125 {
126  string s="", msg, filename, fn;
127  int i, code=0;
128  unsigned int ui;
129  bool ret=true;
130  unsigned int size = 0;
131  static string bl = " ";
132  CommandParser hc;
133  char* buf;
134  Record* newRecordSet = NULL;
135  static bool batch = false;
136  Serializable* sss;
137 
138  if (! connected)
139  throw MCS_ERROR(MSG_NOT_CONNECTED);
140 
141  if (! batch) {
142  clearRecords();
143  if (lrecord) delete lrecord;
144  lrecord = NULL;
145  }
146 
147  batch = true;
148 
149 
150  if (! cmd.empty()) {
151  hc.parseCmd(cmd);
152 
153  if (hc.cmpCmd(MCS_CMD_PUT)) {
154  filename = lpath + string("/") + hc.arg(0).sval();
155  if (! (size = File_Dir_Exist(filename, ui)))
156  throw MCS_ERROR(MSG_CANT_OPEN_FILE, filename.csz);
157 
158  cmd = MCS_CMD_PUT + bl + hc.arg(0).sval() + bl + itos(size);
159  for (i=0; i<hc.optc(); i++)
160  cmd += " -" + hc.opt(i);
161  }
162 
163  else if (hc.cmpCmd(MCS_CMD_PUTDATA)) {
164  if (! data)
165  throw MCS_ERROR(MSG_OBJECT_MISSING);
166 
167  buf = (char *)data->getEntireBuffer(size);
168  cmd = MCS_CMD_PUTDATA + bl + itos(size);
169  for (i=0; i<hc.optc(); i++)
170  cmd += " -" + hc.opt(i);
171  }
172  print(cmd);
173  }
174 
175 
176  s = getline();
177  while((s != string(MCS_PROMPT_OK)) &&
178  (s != string(MCS_PROMPT_WARN)) &&
179  (s != string(MCS_PROMPT_ERROR)) &&
180  (code != MSG_BYE)) {
181 
182  if (s.csz[0] == *MCS_PRE) {
183  code = extractCode(s.csz);
184  msg = s.substr(4, 100000);
185 
186  this->code.addField(code);
187  this->msg.addField(msg);
188 
189  if (code == MSG_BYE) {
190  Socket::Close();
191  connected = false;
192  event(MCS_CLIENT_DISCONNECT, Data((void*) NULL));
193  return true;
194  }
195 
196  //Search for auxiliary field in the answer....
197  vector<string> v = split(msg, MCS_SEP);
198 
199  //...and put them in the recv vector
200  for (ui=0; ui<v.size(); ui++)
201  if ((ui % 2) == 1) //only items with an even index
202  aux.addField(v[ui]);
203 
204 
205  if (code >= 100) {
206  ret=false;
207  event(MCS_CLIENT_ERROR, Data(msg), code);
208  }
209 
210 
211  switch (code) {
212  case MSG_SENDFILE_START:
213  fn = aux.field(aux.count()-1).sval();
214  if (writetofile)
215  recvData(fileDescriptor);
216  else
217  recvData(lpath + string ("/") + fn);
218 
219  event(MCS_CLIENT_FILE, Data(fn));
220  break;
221 
222  case MSG_SENDDATA_START:
223  buf = NULL;
224  size = recvData((char**) &buf, 0);
225  i = aux.field(aux.count()-1).ival();
226  if (i == 1) {
227  Data d(buf);
228  this->recv.addField(d);
229  event(MCS_CLIENT_DATA, d);
230  }
231  else {
232  lrecord = new Record(buf);
233  }
234 
235  free(buf);
236  break;
237 
238  case MSG_RECVFILE_START:
239  sss = new Serializable(filename, lchunksize);
240  sendData(sss);
241  delete sss;
242  break;
243 
244  case MSG_RECVDATA_START:
245  sss = new Serializable(buf, size, true, lchunksize);
246  sendData(sss);
247  delete sss;
248  //free(buf); //It has been freed by the Serializable object
249  break;
250 
251  case MSG_OUT:
252  out.addField(s.substr(4, 100000));
253  break;
254 
255  case MSG_NEW_RECORDSET:
256  if (lrecord) {
257  newRecordSet = new Record(*lrecord);
258  delete lrecord;
259  lrecord = NULL;
260  }
261  break;
262 
263 
264  }
265  }
266  else
267  throw MCS_ERROR(MSG_PROTOCOL, s.csz);
268 
269  s = getline();
270  }
271 
272  writetofile = false;
273  if (newRecordSet) {
274  Data d = newRecordSet->pop();
275  if (d.getTag() & MCS_RS_INSERT)
276  d.setTag( d.getTag() - MCS_RS_INSERT);
277 
278  init(d.getTag(), d.ival(), newRecordSet);
279  delete newRecordSet;
280  startFetch();
281  }
282 
283  if (hc.cmpCmd(MCS_CMD_CID)) {
284  lcid = aux[0].ival();
285  lchunksize = aux[1].ival();
286  }
287 
288 
289 
290  batch = false;
291  return ret;
292 }
293 
294 
295 
296 bool mcs::Client::fetch(unsigned int newpos, bool random)
297 {
298  static string bl = " ";
299  if (! exec(MCS_CMD_RECORD + bl + itos(newpos))) {
300  if (code[code.count()-1].ival() == MSG_ALREADY_AT_END_OF_FILE)
301  return false;
302  else
303  throw MCS_ERROR( MSG_FETCH_ERROR, msg[0].sval());
304  }
305 
306 
307  if (lrecord) {
308  rec() = *lrecord;
309  return true;
310  }
311  else
312  return false;
313 }
314 
315 
316 
317 void mcs::Client::event(int op, Data d, int code)
318 {}
319 
320 
321 
323 {
324  return connected;
325 }
326 
327 
328 
329 int mcs::Client::cid() { return lcid; }
330 
331 
332 int mcs::Client::chunksize() { return lchunksize; }
333 
334 
335 
336 
337 
338 
340 //mcs::ClientThread::ClientThread(string path, string server,
341 // int port, bool SSL) :
342 // Client(path, server, port, true, SSL) , Thread()
343 //{
344 // start();
345 //}
346 //
347 //
348 //mcs::ClientThread::~ClientThread()
349 //{}
350 //
351 //
352 //bool mcs::ClientThread::exec(string cmd, Data* d)
353 //{
354 // bool ret = false;
355 // enter();
356 //
357 // try {
358 // ret = Client::exec(cmd, d);
359 // }
360 // catch (Event e) {
361 // leave();
362 // throw e;
363 // }
364 //
365 // leave();
366 // return ret;
367 //}
368 //
369 //
370 //void mcs::ClientThread::run()
371 //{
372 // for (;;) {
373 // sleep_ms(500);
374 //
375 // if (tryenter()) {
376 // try {
377 // if (chkRecv(true, false))
378 // Client::exec(MCS_CMD_NOP);
379 // }
380 // catch (Event e) {
381 // leave();
382 // cerr << e.where() << " " << e.msg() << endl;
383 // exit();
384 // }
385 // leave();
386 // }
387 // }
388 //}
389 //
390 //
string opt(int i)
Return option at i-th position.
#define MCS_RS_INSERT
Flag for RecordSet::init().
Definition: mcs.hh:4480
Client(const Client &)
Declared to avoid using of default copy constructor.
#define MCS_CMD_RECORD
Definition: mcs.hh:337
string itos(int i)
Convert an integer to a string.
Definition: Utils.cc:77
int optc()
Return number of options.
Connect to a MCS server as a client.
Definition: mcs.hh:7538
Serialize memory buffers or files into chunks.
Definition: mcs.hh:1290
void parseCmd(string c)
Parse a command line into tokens, arguments and options.
bool File_Dir_Exist(string fn, unsigned int &size)
Check if a file or directory exists.
Definition: Utils.cc:39
bool isConnected()
Tell if the object is connected to the MCS server.
Definition: Client.cc:322
string Pwd()
Return the current working dir.
Definition: Utils.cc:66
string sval(bool addWhiteSpaces=false) const
Convert internal data to a string object.
Definition: Data.cc:1555
void setTag(unsigned char tag)
Set a new value to internal tag.
Definition: Data.cc:2544
Record out
Record containing all output lines (code: MSG_OUT) sent by the server while executing the last comman...
Definition: mcs.hh:7598
A dynamic array of Data objects.
Definition: mcs.hh:4170
void print(string s)
Writes a string in the socket adding a newline.
Definition: Socket.cc:630
int chunksize()
Return the server side chunk size used to send data across network.
Definition: Client.cc:332
void clearRecords()
Clear all records.
Definition: Client.cc:101
#define MCS_SEP
This character is used to split a message into "fields".
Definition: mcs.hh:273
The base class that implement the data abstraction layer.
Definition: mcs.hh:4510
#define MCS_ERROR(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:964
#define MCS_CMD_PUTDATA
Command: Upload Data objects.
Definition: mcs.hh:431
#define MCS_CMD_PUT
Command: Upload a file to the work directory.
Definition: mcs.hh:421
Record msg
Record containing all reply&#39;s messages sent by the server while executing the last command...
Definition: mcs.hh:7592
unsigned char getTag()
Retrieve the value of the tag.
Definition: Data.cc:2549
bool connected
Flag telling if the client is connected or not.
Definition: mcs.hh:7545
Record code
Record containing all reply&#39;s numeric codes sent by the server while executing the last command...
Definition: mcs.hh:7579
string remTrailing(string &s, const char *p)
Remove any trailing character "p".
Definition: Utils.cc:185
Data field(string name)
Returns the Data object in the vector whose name is "name".
Definition: Record.cc:419
#define MCS_CMD_CID
Command: Retrieve the Client identifier.
Definition: mcs.hh:327
bool exec(string cmd, Data *data=NULL)
Execute commands on the server.
Definition: Client.cc:124
Parse command lines.
Definition: mcs.hh:5185
string lpath
Local path to read/write files.
Definition: mcs.hh:7542
void startFetch()
Must be called when record fetching is possible.
Definition: Record.cc:693
vector< string > split(string s, string sep=" ")
Split a string into tokens.
Definition: Utils.cc:192
#define MCS_PROMPT_ERROR
Prompt sent after a command raised one error.
Definition: mcs.hh:282
Main include file for all MCS based applications.
void sendData(Serializable *from)
Send a block of data through the socket.
Definition: Socket.cc:637
void addField(Data *d)
Wrapper around Dynamic_Array.push.
Definition: Record.cc:364
int extractCode(const char *msg)
Extract the numeric code from a server reply.
Definition: Utils.cc:26
bool cmpCmd(string cmd)
Check if the string in the parameter is the same as the command (case insensitive).
void init(unsigned char code, unsigned int nrows=0, Record *meta=NULL, short int id=0)
Initailize the Record set.
Definition: Record.cc:638
A general purpose data type.
Definition: mcs.hh:3092
#define MCS_CMD_DBNAME
Command: Provide the application (database) name.
Definition: mcs.hh:311
#define MCS_CMD_USERNAME
Command: Provide user name.
Definition: mcs.hh:301
Record recv
Record containing all Data objects sent by the server.
Definition: mcs.hh:7601
#define MCS_PROMPT_OK
Prompt sent after a command has been executed correctly.
Definition: mcs.hh:276
void Close()
Close the socket.
Definition: Socket.cc:368
virtual ~Client()
Destructor.
Definition: Client.cc:63
int cid()
Return the server side client identificator.
Definition: Client.cc:329
#define MCS_PROMPT_WARN
Prompt sent after a command raised one or more warnings.
Definition: mcs.hh:279
#define MCS_PRE
Prefix of a message for the client, this is the first character.
Definition: mcs.hh:270
int count()
Wrapper around Dynamic_Array.count.
Definition: Record.cc:359
int ival() const
Convert internal data to a integer value.
Definition: Data.cc:1209
unsigned int recvData(char **buffer, unsigned int maxsize)
Receive data and store in a buffer.
Definition: Socket.cc:662
Data & arg(int i)
Return argument at i-th position.
Manage TCP sockets.
Definition: mcs.hh:1662
#define MCS_CMD_DBCONNECT
Command: Finalize the authentication process and log in.
Definition: mcs.hh:317
string getline()
Reads from a socket until a newline is encountered.
Definition: Socket.cc:615
#define MCS_CMD_PASSWORD
Command: Provide password.
Definition: mcs.hh:306
bool login(string user, string pass, string db="")
Log in to a MCS server.
Definition: Client.cc:76
Record aux
Record containing all auxiliary fields sent by the server.
Definition: mcs.hh:7604
Namespace for MCS library.

mcslogo

MCS (My Customizable Server) ver. 0.3.3-alpha7
Documentation generated on Mon May 28 07:39:41 UTC 2018