forest-net
an overlay networks for large-scale virtual worlds
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
ClientTable-sav.cpp
1 
9 #include "ClientTable.h"
10 
11 namespace forest {
12 
13 
15 ClientTable::ClientTable(int maxClients, int maxSessions)
16  : maxCli(maxClients), maxSess(maxSessions) {
17  svec = new Session[maxSess+1];
18  sessLists = new UiClist(maxSess);
19  sessMap = new IdMap(maxSess);
20  cvec = new Client[maxCli+1];
21  clients = new UiSetPair(maxCli);
22  nameMap = new map<string, int>();
23  maxClx = 0;
24  for (int i = 0; i <= maxSess; i++) svec[i].clx = 0;
25  defRates.set(50,500,25,250);
26  totalRates.set(100,1000,50,500);
27 }
28 
31  delete [] svec; delete sessLists; delete sessMap;
32  delete [] cvec; delete clients; delete nameMap;
33  pthread_mutex_destroy(&mapLock);
34 }
35 
38  if (pthread_mutex_init(&mapLock,NULL) != 0) return false;
39  for (int clx = 1; clx <= maxCli; clx++) {
40  cvec[clx].busyBit = false;
41  if (pthread_cond_init(&cvec[clx].busyCond,NULL) != 0)
42  return false;
43  }
44 
45  /* setup memory-mapped file of client data
46  clientFile.open("clientData");
47  if (!clientFile.good()) return false;
48 
49  int size = max(getpagesize(),(maxClients+1)*RECORD_SIZE);
50  firstRecord = (char *) mmap((caddr_t) 0, size, PROT_READ|PROT_WRITE,
51  MAP_SHARED, clientFile, 0);
52  if (firstRecord < 0) return false;
53  NetBuffer buf(firstRecord, RECORD_SIZE);
54  for (int i = 1; i <= maxClients; i++) {
55  buf.reset(firstRecord + i*RECORD_SIZE, RECORD_SIZE);
56  int status = readEntry(buf,i);
57  if (status == 0) break;
58  else if (status == -1) return false;
59  }
60 */
61  return true;
62 }
63 
93 int ClientTable::getClient(const string& cname) {
94  lockMap();
95  map<string, int>::iterator p = nameMap->find(cname);
96  if (p == nameMap->end()) { unlockMap(); return 0; }
97  int clx = p->second;
98  while (cvec[clx].busyBit) { // wait until client's entry is not busy
99  pthread_cond_wait(&cvec[clx].busyCond,&mapLock);
100  p = nameMap->find(cname);
101  if (p == nameMap->end()) {
102  pthread_cond_signal(&cvec[clx].busyCond);
103  unlockMap(); return 0;
104  }
105  }
106  cvec[clx].busyBit = true; // set busyBit to lock client table entry
107  unlockMap();
108  return clx;
109 }
110 
116  lockMap();
117  cvec[clx].busyBit = false;
118  pthread_cond_signal(&cvec[clx].busyCond);
119  unlockMap();
120 }
121 
130  lockMap();
131  int sess = sessMap->getId(key(cliAdr));
132  if (sess == 0) { unlockMap(); return 0; }
133  int clx = svec[sess].clx;
134  while (cvec[clx].busyBit) { // wait until client's entry is not busy
135  pthread_cond_wait(&cvec[clx].busyCond,&mapLock);
136  sess = sessMap->getId(key(cliAdr));
137  if (sess == 0) {
138  pthread_cond_signal(&cvec[clx].busyCond);
139  unlockMap(); return 0;
140  }
141  clx = svec[sess].clx;
142  }
143  cvec[clx].busyBit = true; // set busyBit to lock client table entry
144  unlockMap();
145  return sess;
146 }
147 
153  lockMap();
154  int clx = clients->firstIn();
155  if (clx == 0) { unlockMap(); return 0; }
156  while (cvec[clx].busyBit) {
157  pthread_cond_wait(&cvec[clx].busyCond,&mapLock);
158  clx = clients->firstIn(); // first client may have changed
159  if (clx == 0) {
160  pthread_cond_signal(&cvec[clx].busyCond);
161  unlockMap(); return 0;
162  }
163  }
164  cvec[clx].busyBit = true;
165  unlockMap();
166  return clx;
167 }
168 
177  lockMap();
178  int nuClx = clients->nextIn(clx);
179  if (nuClx == 0) {
180  cvec[clx].busyBit = false;
181  pthread_cond_signal(&cvec[clx].busyCond);
182  unlockMap();
183  return 0;
184  }
185  while (cvec[nuClx].busyBit) {
186  pthread_cond_wait(&cvec[nuClx].busyCond,&mapLock);
187  nuClx = clients->nextIn(clx);
188  if (nuClx == 0) {
189  cvec[clx].busyBit = false;
190  pthread_cond_signal(&cvec[clx].busyCond);
191  pthread_cond_signal(&cvec[nuClx].busyCond);
192  unlockMap();
193  return 0;
194  }
195  }
196  cvec[nuClx].busyBit = true;
197  cvec[clx].busyBit = false;
198  pthread_cond_signal(&cvec[clx].busyCond);
199  unlockMap();
200  return nuClx;
201 }
202 
217 int ClientTable::addClient(string& cname, string& pwd,
218  privileges priv, int clx) {
219  lockMap();
220  map<string,int>::iterator p = nameMap->find(cname);
221  if (p != nameMap->end()) { unlockMap(); return 0; }
222  if (clx != 0) {
223  if (clients->isIn(clx)) clx = 0;
224  } else {
225  clx = clients->firstOut();
226  }
227  if (clx == 0) { unlockMap(); return 0;}
228  nameMap->insert(pair<string,int>(cname,clx));
229  clients->swap(clx);
230  cvec[clx].busyBit = true;
231  unlockMap();
232 
233  setClientName(clx,cname); setPassword(clx,pwd); setPrivileges(clx,priv);
234  setRealName(clx,"noname"); setEmail(clx,"nomail");
236  cvec[clx].firstSess = cvec[clx].numSess = 0;
237 
238  maxClx = max(clx,maxClx);
239  return clx;
240 }
241 
248  lockMap();
249  nameMap->erase(cvec[clx].cname);
250  while (cvec[clx].firstSess != 0)
251  removeSession(cvec[clx].firstSess);
252  clients->swap(clx);
253  cvec[clx].busyBit = false;
254  pthread_cond_signal(&cvec[clx].busyCond);
255  unlockMap();
256 }
257 
268  lockMap();
269  int sess = sessMap->addPair(key(cliAdr));
270  if (sess == 0) { unlockMap(); return 0; }
271  svec[sess].cliAdr = cliAdr;
272  svec[sess].rtrAdr = rtrAdr;
273  svec[sess].clx = clx;
274  if (cvec[clx].firstSess == 0) {
275  cvec[clx].firstSess = sess;
276  } else {
277  sessLists->join(sess,cvec[clx].firstSess);
278  }
279  cvec[clx].numSess++;
280  unlockMap();
281 
282  return sess;
283 }
284 
290  lockMap();
291  int clx = svec[sess].clx;
292  if (clx == 0) { unlockMap(); return; }
293  if (cvec[clx].firstSess == sess) {
294  if (sessLists->suc(sess) == sess) {
295  cvec[clx].firstSess = 0;
296  } else {
297  cvec[clx].firstSess = sessLists->suc(sess);
298  sessLists->remove(sess);
299  }
300  } else {
301  sessLists->remove(sess);
302  }
303  sessMap->dropPair(key(svec[sess].cliAdr));
304  svec[sess].clx = 0; // used to detect unused entries
305  cvec[clx].numSess--;
306  unlockMap();
307 }
308 
417 bool ClientTable::writeRecord(int clx) {
418  string s;
419  if (clx < 0 || clx > maxClients) return false;
420  client2string(clx,s);
421  if (s.length() > RECORD_SIZE) {
422  s.erase(RECORD_SIZE-1); s += "\n";
423  }
424  s.copy(firstRecord + clx*RECORD_SIZE, RECORD_SIZE);
425  return true;
426 }
427 
435 string& ClientTable::client2string(int clx, string& s, bool includeSess) const {
436  string s1;
437  s = getClientName(clx) + ", " + getPassword(clx) + ", ";
438 
439  privileges priv = getPrivileges(clx);
440  switch (priv) {
441  case LIMITED: s += "limited"; break;
442  case STANDARD: s += "standard"; break;
443  case ADMIN: s += "admin"; break;
444  case ROOT: s += "root"; break;
445  default: s += "-";
446  }
447 
448  s += ", \"" + getRealName(clx) + "\", " + getEmail(clx) + ", " +
449  getDefRates(clx).toString(s1) + ", ";
450  s += getTotalRates(clx).toString(s1) + "\n";
451  if (includeSess) {
452  for (int sess = firstSession(clx); sess != 0;
453  sess = nextSession(sess,clx)) {
454  s += session2string(sess, s1);
455  }
456  }
457  return s;
458 }
459 
466 string& ClientTable::session2string(int sess, string& s) const {
467  string s1;
468  s = Forest::fAdr2string(getClientAdr(sess),s1) + ", ";
469  s += Forest::fAdr2string(getRouterAdr(sess),s1) + ", ";
470  s += getSessRates(sess).toString(s1) + ", ";
471  time_t t = getStartTime(sess);
472  s += ctime(&t);
473  s += "\n";
474  return s;
475 }
476 
483 string& ClientTable::toString(string& s, bool includeSess) {
484  string s1; s = "";
485  for (int clx = firstClient(); clx != 0; clx = nextClient(clx))
486  s += client2string(clx,s1,includeSess);
487  return s;
488 }
489 
495 void ClientTable::write(ostream& out, bool includeSess) {
496  string s;
497  for (int clx = firstClient(); clx != 0; clx = nextClient(clx))
498  out << client2string(clx,s,includeSess);
499 }
500 
501 } // ends namespace
502