|
MASA-Core
|
00001 /******************************************************************************* 00002 * 00003 * Copyright (c) 2010-2015 Edans Sandes 00004 * 00005 * This file is part of MASA-Core. 00006 * 00007 * MASA-Core is free software: you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation, either version 3 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * MASA-Core is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with MASA-Core. If not, see <http://www.gnu.org/licenses/>. 00019 * 00020 ******************************************************************************/ 00021 00022 #include "MasaNetCLI.hpp" 00023 00024 #include <stdio.h> 00025 #include <stdlib.h> 00026 #include <unistd.h> 00027 #include <string.h> 00028 #include <readline/readline.h> 00029 #include <readline/history.h> 00030 00031 /* 00032 * Default prompt. 00033 */ 00034 #define DEFAULT_PROMPT "masa-cli# " 00035 00036 00037 #define WELLCOME_MESSAGE "\n\ 00038 This is the \033[1mMASA\033[0m Command Line Interface (masa-cli).\n\ 00039 Type \"help\" or ? for further assistance\n\ 00040 \n" 00041 00042 /* 00043 * Allow parsing of the ~/.inputrc file . 00044 */ 00045 #define READLINE_NAME "masa" 00046 00047 00048 00049 command_t MasaNetCLI::commands[] = { 00050 { "connect", MasaNetCLI::cmd_connect, "Starts a new connection with the given hostname[:port]" }, 00051 { "show status", MasaNetCLI::cmd_status, "Shows the current connection status" }, 00052 { "show discovered", MasaNetCLI::cmd_show_discovered, "Shows the discovered peers" }, 00053 { "show connected", MasaNetCLI::cmd_show_connected, "Shows the connected peers" }, 00054 { "show ring", MasaNetCLI::cmd_show_ring, "Shows the data peers in the ring" }, 00055 { "test ring", MasaNetCLI::cmd_test_ring, "Test all the peers in the ring" }, 00056 { "create ring", MasaNetCLI::cmd_create_ring, "Creates the buffers ring" }, 00057 00058 { "align local", (command_f)NULL, "" }, 00059 00060 { "help", MasaNetCLI::cmd_help, "Lists the commands help" }, 00061 { "quit", MasaNetCLI::cmd_quit, "Quits the CLI" }, 00062 { (char *)NULL, (command_f)NULL, (char *)NULL }, 00063 }; 00064 00065 00066 00067 MasaNet* MasaNetCLI::masaNet = NULL; 00068 00069 void MasaNetCLI::initialize() { 00070 if (masaNet == NULL) { 00071 masaNet = new MasaNet(TYPE_CLI, "Command Line Interface"); 00072 } 00073 } 00074 00075 void MasaNetCLI::openConsole() { 00076 00077 /* Allow conditional parsing of the ~/.inputrc file. */ 00078 rl_readline_name = READLINE_NAME; 00079 00080 /* Tell the completer that we want a crack first. */ 00081 rl_attempted_completion_function = console_completion; 00082 00083 char* input; 00084 char shell_prompt[100]; 00085 00086 printf(WELLCOME_MESSAGE); 00087 00088 // Create prompt string from user name and current working directory. 00089 snprintf(shell_prompt, sizeof(shell_prompt), DEFAULT_PROMPT); 00090 00091 // Configure readline to auto-complete paths when the tab/? keys are hit. 00092 //rl_bind_key('\t', rl_complete); 00093 //rl_bind_key('?', rl_complete); 00094 00095 while (1) { 00096 00097 00098 // Display prompt and read input (n.b. input must be freed after use)... 00099 input = readline(shell_prompt); 00100 // Check for EOF. 00101 if (!input) { 00102 //printf("\n"); 00103 break; 00104 } 00105 00106 char* s = strip_whitespaces(input); 00107 if (*s) { 00108 // Add input to history. 00109 add_history(s); 00110 if (execute_line(s) == CMD_ABORT) { 00111 return; 00112 } 00113 } 00114 // Do stuff... 00115 00116 // Free input. 00117 free(input); 00118 } 00119 00120 00121 sleep(500); 00122 } 00123 00124 00125 00126 00127 00128 /* Execute a command line. */ 00129 int MasaNetCLI::execute_line (char *line) { 00130 register int i; 00131 command_t *command; 00132 char *word; 00133 00134 /* Isolate the command word. */ 00135 i = 0; 00136 while (line[i] && whitespace (line[i])) { 00137 i++; 00138 } 00139 word = line + i; 00140 00141 //if (line[i]) 00142 //line[i++] = '\0'; 00143 00144 command = find_command(line); 00145 00146 if (!command) { 00147 fprintf(stderr, "%s: No such command for FileMan.\n", word); 00148 return CMD_ERROR; 00149 } 00150 00151 i += strlen(command->name); 00152 while (line[i] && whitespace (line[i])) { 00153 i++; 00154 } 00155 word = line + i; 00156 00157 /* Call the function. */ 00158 return ((*(command->func)) (word)); 00159 } 00160 00161 00162 /* Look up NAME as the name of a command, and return a pointer to that 00163 command. Return a NULL pointer if NAME isn't a command name. */ 00164 command_t* MasaNetCLI::find_command (char *name) { 00165 register int i; 00166 00167 for (i = 0; commands[i].name; i++) { 00168 int len = strlen(commands[i].name); 00169 if (strncmp(name, commands[i].name, len) == 0) { 00170 if (name[len] == '\0' || whitespace(name[len])) { 00171 return (&commands[i]); 00172 } 00173 } 00174 } 00175 return ((command_t *) NULL); 00176 } 00177 00178 /* Strip whitespace from the start and end of STRING. Return a pointer 00179 into STRING. */ 00180 char *MasaNetCLI::strip_whitespaces (char * string) { 00181 00182 register char *s, *t; 00183 00184 for (s = string; whitespace (*s); s++) 00185 ; 00186 00187 if (*s == 0) 00188 return (s); 00189 00190 t = s + strlen (s) - 1; 00191 while (t > s && whitespace (*t)) 00192 t--; 00193 *++t = '\0'; 00194 00195 return s; 00196 } 00197 00198 00199 /* Attempt to complete on the contents of TEXT. START and END 00200 bound the region of rl_line_buffer that contains the word to 00201 complete. TEXT is the word to complete. We can use the entire 00202 contents of rl_line_buffer in case we want to do some simple 00203 parsing. Returnthe array of matches, or NULL if there aren't any. */ 00204 char ** MasaNetCLI::console_completion (const char *text, int start, int end) { 00205 char **matches; 00206 00207 //printf("%s\n", rl_line_buffer); 00208 00209 matches = (char **)NULL; 00210 /* If this word is at the start of the line, then it is a command 00211 to complete. Otherwise it is the name of a file in the current 00212 directory. */ 00213 //if (start == 0) 00214 matches = rl_completion_matches (text, command_generator); 00215 //rl_attempted_completion_over=true; 00216 00217 //printf("\n%s %s %s %d %d\n\n", rl_line_buffer, matches[0], text, start, end); 00218 00219 return (matches); 00220 } 00221 00222 /* Generator function for command completion. STATE lets us 00223 know whether to start from scratch; without any state 00224 (i.e. STATE == 0), then we start at the top of the list. */ 00225 char * MasaNetCLI::command_generator (const char *text, int state) { 00226 00227 static int list_index, len; 00228 char *name; 00229 00230 /* If this is a new word to complete, initialize now. This 00231 includes saving the length of TEXT for efficiency, and 00232 initializing the index variable to 0. */ 00233 if (!state) 00234 { 00235 list_index = 0; 00236 len = strlen (rl_line_buffer); 00237 } 00238 00239 /* Return the next name which partially matches from the 00240 command list. */ 00241 while (name = commands[list_index].name) 00242 { 00243 list_index++; 00244 00245 if (len == 0 || strncmp (name, rl_line_buffer, len) == 0) { 00246 int p = len-1; 00247 while (name[p] != ' ' && p != 0) { 00248 p--; 00249 } 00250 if (name[p] == ' ') p++; 00251 char* ptr = &name[p]; 00252 char* r = (char*)malloc (strlen (ptr) + 1); 00253 00254 strcpy (r, ptr); 00255 //printf(".%s\n", r); 00256 return r; 00257 } 00258 } 00259 00260 /* If no names matched, then return NULL. */ 00261 return ((char *)NULL); 00262 } 00263 00264 00265 void MasaNetCLI::printTopology(int type) { 00266 vector<Peer*> peers = masaNet->getConnectedPeers().getAllPeers(); 00267 vector< vector<Peer*> > topology; 00268 00269 for (vector<Peer*>::const_iterator it = peers.begin() ; it != peers.end(); ++it) { 00270 Peer* src = (*it); 00271 vector<Peer*> v; 00272 v.push_back(src); 00273 00274 vector<Peer*> remote_peers = masaNet->getRemotePeers(src->getRemoteId().c_str(), type); 00275 for (vector<Peer*>::const_iterator it2 = remote_peers.begin() ; it2 != remote_peers.end(); ++it2) { 00276 Peer* dst = (*it2); 00277 v.push_back(dst); 00278 } 00279 topology.push_back(v); 00280 } 00281 00282 for (vector< vector<Peer*> >::const_iterator it = topology.begin() ; it != topology.end(); ) { 00283 vector<Peer*> v = *it; 00284 Peer* src = v.front(); 00285 if (it != topology.begin()) { 00286 printf("|\n"); 00287 } 00288 it++; 00289 printf("+-+- %s:\n", src->toString().c_str()); 00290 if (v.size() > 1) { 00291 char space = ' '; 00292 if (it != topology.end()) { 00293 space = '|'; 00294 } 00295 printf("%c |\n", space); 00296 for (vector<Peer*>::const_iterator it2 = v.begin()+1 ; it2 != v.end(); ++it2) { 00297 Peer* dst = *it2; 00298 00299 printf("%c +----- %s\n", space, dst->toString().c_str()); 00300 } 00301 } 00302 } 00303 00304 } 00305 00306 00307 00308 00309 int MasaNetCLI::cmd_connect(char* arg) { 00310 if (strcmp(arg, "all") == 0) { 00311 vector<Peer*> peers = masaNet->getConnectedPeers().getProcessingPeers(); 00312 set<string> newPeers; 00313 00314 for (vector<Peer*>::const_iterator it = peers.begin() ; it != peers.end(); ++it) { 00315 vector<Peer*> remote_peers = masaNet->getRemotePeers((*it)->getRemoteId().c_str(), CMD_DISCOVERED_PEERS); 00316 for (vector<Peer*>::const_iterator it2 = remote_peers.begin() ; it2 != remote_peers.end(); ++it2) { 00317 if (masaNet->getConnectedPeers().get((*it2)->getRemoteId()) == NULL) { 00318 newPeers.insert((*it2)->getRemoteAddress()); 00319 } 00320 } 00321 } 00322 00323 for (set<string>::const_iterator it = newPeers.begin(); it != newPeers.end(); ++it) { 00324 printf("Should connect to %s\n", (*it).c_str()); 00325 masaNet->connectToPeer(*it, CONNECTION_TYPE_CTRL); 00326 } 00327 return CMD_OK; 00328 } else { 00329 Peer* ret = masaNet->connectToPeer(arg, CONNECTION_TYPE_CTRL); 00330 ret->waitHandshake(); 00331 if (ret != NULL) { 00332 //printf("Connection Established.\n"); 00333 return CMD_OK; 00334 } else { 00335 //printf("Connection Error.\n"); 00336 return CMD_ERROR; 00337 } 00338 } 00339 00340 00341 } 00342 00343 /* The user wishes to quit using this program. Just set DONE 00344 non-zero. */ 00345 int MasaNetCLI::cmd_quit (char *arg) { 00346 exit(0); 00347 return CMD_OK; 00348 } 00349 00350 00351 int MasaNetCLI::cmd_status(char* arg) { 00352 char host[256]; 00353 char pstr[16]; 00354 int port = 0; 00355 sscanf(arg, "%[^:]:%d", host, &port); 00356 sprintf(pstr, "%d", port); 00357 MasaNetStatus* status = masaNet->getPeerStatus(); 00358 00359 printf("\n%s\n", status->toString().c_str()); 00360 //masaNet->waitConnected(); 00361 return CMD_OK; 00362 } 00363 00364 00365 int MasaNetCLI::cmd_show_connected(char* arg) { 00366 00367 printTopology(CMD_CONNECTED_PEERS); 00368 00369 return CMD_OK; 00370 } 00371 00372 int MasaNetCLI::cmd_show_connected_remote(char* arg) { 00373 return CMD_OK; 00374 } 00375 00376 int MasaNetCLI::cmd_show_discovered(char* arg) { 00377 printTopology(CMD_DISCOVERED_PEERS); 00378 00379 return CMD_OK; 00380 } 00381 00382 int MasaNetCLI::cmd_show_ring(char* arg) { 00383 printTopology(CMD_DATA_PEERS); 00384 00385 return CMD_OK; 00386 } 00387 00388 int MasaNetCLI::cmd_create_ring(char* arg) { 00389 masaNet->createRing(); 00390 00391 return CMD_OK; 00392 } 00393 00394 00395 int MasaNetCLI::cmd_test_ring(char* arg) { 00396 const set<string>& ids = masaNet->testRing(arg); 00397 printf("Ring size: %d\n", ids.size()); 00398 int count = 0; 00399 for (std::set<string>::iterator it=ids.begin(); it!=ids.end(); ++it) { 00400 printf("%3d: %s\n", count++, (*it).c_str()); 00401 } 00402 00403 return CMD_OK; 00404 } 00405 00406 /* Print out help for ARG, or for all of the commands if ARG is 00407 not present. */ 00408 int MasaNetCLI::cmd_help (char *arg) { 00409 register int i; 00410 int printed = 0; 00411 00412 for (int i = 0; commands[i].name; i++) 00413 { 00414 if (!*arg || (strcmp (arg, commands[i].name) == 0)) 00415 { 00416 printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc); 00417 printed++; 00418 } 00419 } 00420 00421 if (!printed) 00422 { 00423 printf ("No commands match `%s'. Possibilties are:\n", arg); 00424 00425 for (i = 0; commands[i].name; i++) 00426 { 00427 /* Print in six columns. */ 00428 if (printed == 6) 00429 { 00430 printed = 0; 00431 printf ("\n"); 00432 } 00433 00434 printf ("%s\t", commands[i].name); 00435 printed++; 00436 } 00437 00438 if (printed) 00439 printf ("\n"); 00440 } 00441 return CMD_OK; 00442 } 00443 00444 00445 00446 int main(int argc, char** argv) { 00447 if (argc > 2) { 00448 fprintf(stderr, "usage: %s [host[:port]]\n", argv[0]); 00449 exit(1); 00450 } 00451 MasaNetCLI::initialize(); 00452 if (argc == 2) { 00453 MasaNetCLI::cmd_connect(argv[1]); 00454 } 00455 MasaNetCLI::openConsole(); 00456 } 00457
1.7.6.1