⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sftpc.cpp

📁 伯克利做的SFTP安全文件传输协议
💻 CPP
📖 第 1 页 / 共 5 页
字号:
  /*   *  The idea here is I have a bunch of text files with   *  various line ending conditions.  I want to force sftpc   *  to do every kind of text transformation it knows how to   *  do, and verify I get what I should.   *   *  The purpose here is *not* to test the *server*'s ability   *  to do text transformations, so the binaryAnyway flag is   *  always set whenever we tell sftpc to do an ascii transfer.   *   *  These tests will print warnings about malformed text;   *  I neither check nor suppress this output.   */  // sizeof returns the length *including* the automatically-  // appended null terminator, which I don't want included  #define BLK(arr) DataBlock b_##arr(arr, sizeof(arr)-1)  // well-structured CRLF text  char const crlf1[] =    "This is a text file.\r\n"    "Its lines are separated by CRLF.\r\n"    "This is the third and final line.\r\n";  BLK(crlf1);  // badly-structured CRLF text  char const crlf2[] =    "This is another file with CRLF separators.\r\n"    "Here (\r) is an embedded CR.\r\n"    "Here (\n) is an embedded LF.\r\n"    "And finally, a line missing any separator.";  BLK(crlf2);  // crlf1 -> CRLF_to_LF -> lf1  char const lf1[] =    "This is a text file.\n"    "Its lines are separated by CRLF.\n"    "This is the third and final line.\n";  BLK(lf1);  // crlf2 -> CRLF_to_LF -> lf2  char const lf2[] =    "This is another file with CRLF separators.\n"    "Here () is an embedded CR.\n"    "Here () is an embedded LF.\n"    "And finally, a line missing any separator.";  BLK(lf2);  // lf1 -> LF_to_CRLF -> crlf1 (correct inverse)  // lf2 -> LF_to_CRLF -> crlf2b  char const crlf2b[] =    "This is another file with CRLF separators.\r\n"    "Here () is an embedded CR.\r\n"    "Here () is an embedded LF.\r\n"    "And finally, a line missing any separator.";  BLK(crlf2b);  // crlf2 -> LF_to_CRLF -> crlf2c  char const crlf2c[] =    "This is another file with CRLF separators.\r\n"    "Here () is an embedded CR.\r\n"    "Here (\r\n) is an embedded LF.\r\n"    "And finally, a line missing any separator.";  BLK(crlf2c);  // crlf2 -> CRLF_to_CRLF -> crlf2d  char const crlf2d[] =    "This is another file with CRLF separators.\r\n"    "Here () is an embedded CR.\r\n"    "Here () is an embedded LF.\r\n"    "And finally, a line missing any separator.";  BLK(crlf2d);  #undef BLK  // here are the set of inputs, transforms, and outputs  // I believe to be correct  enum TransType { CRLF2LF, LF2CRLF, CRLF2CRLF };  struct {    DataBlock const *start;    // can't use & because of something about ctors    TransType tt;    DataBlock const *end;  } arr[] = {    { &b_crlf1, CRLF2LF, &b_lf1 },    { &b_crlf2, CRLF2LF, &b_lf2 },    { &b_lf1, LF2CRLF, &b_crlf1 },    { &b_lf2, LF2CRLF, &b_crlf2b },    { &b_crlf2, LF2CRLF, &b_crlf2c },    { &b_crlf2, CRLF2CRLF, &b_crlf2d }  };  // this loop runs each line in the above array  loopi(TABLESIZE(arr)) {    switch (arr[i].tt) {      case LF2CRLF:        testSendReceiveBlocks(     // ascii  local  binaryAnyway          *arr[i].start, TransferState(true,  false, true),          *arr[i].end,   TransferState(false, false, false));        break;      case CRLF2LF:        testSendReceiveBlocks(     // ascii  local  binaryAnyway          *arr[i].start, TransferState(false, false, false),          *arr[i].end,   TransferState(true,  false, true));        break;      case CRLF2CRLF:        testSendReceiveBlocks(     // ascii  local  binaryAnyway          *arr[i].start, TransferState(true,  true,  true),          *arr[i].end,   TransferState(false, false, false));        break;    }  }}// send and receive some data, and compare what we get// to what we expectvoid SFTPC::testSendReceiveBlocks(  DataBlock const &start, TransferState const &sendState,  DataBlock const &end, TransferState const &receiveState){  // I had been using the same name for the local and remote file  // names, but that created problems when the local and remote  // directories were the same  // write the initial data to a temporary file  start.writeToFile("tempfile.local");  // transfer this file to the server  setTransferState(sendState);  userCommand("put tempfile.local tempfile.remote");  // retrieve the file from the server  setTransferState(receiveState);  userCommand("get tempfile.remote tempfile.local");  // read what we got into a buffer  DataBlock got;  got.readFromFile("tempfile.local");  // compare what we got to what we expect  if (end != got) {    if (start.getDataLen() +        end.getDataLen() +        got.getDataLen() < 3000) {      // print the failing data if it's not too big      start.print("initial");      end.print("expected");      got.print("actually got");    }    else {      // we already have 'got' as tempfile.local ; write the      // others to disk, for later human inspection      start.writeToFile("tempfile.start");      end.writeToFile("tempfile.end");    }    xfailure("put/get failed to preserve data");  }  else {    printf("   (files are identical)   \n");    // if it worked, go ahead and delete the temp files    userCommand("rm tempfile.remote");    // from server    removeFile("tempfile.local");         // from cwd  }}void SFTPC::setTransferState(TransferState const &state){  #define C(v) v = state.v  C(asciiTransfers);  C(localConventionIsCRLF);  C(binaryTransferAnyway);  #undef C}// a series of automated tests to verify that various functions// in sftpc and sftpd are working correctlyvoid SFTPC::runTests(bool passive){  transferPassively = passive;  // test a simple ls -l command  userCommand("dir");  // test failed send  bool eatIt = true;  try {    userCommand("put crazy.nonexist.file");    eatIt = false;    xfailure("failed to fail to put crazy.nonexist.file");  }  catch (...) {    if (!eatIt) {      throw;    }  }  // test real data transfers  testBinaryTransfers();  // interpose a failed receive  eatIt = true;  try {    userCommand("get crazier.nonexist.file");    eatIt = false;    xfailure("failed to fail to get crazy.nonexist.file");  }  catch (...) {    if (!eatIt) {      throw;    }  }  // bunch of text transfers  testTextTransfers();  // test multiple-file commands  testMultipleFileCmds();}static void verifyFile(DataBlock const &blk, char const *fname){  DataBlock temp;  temp.readFromFile(fname);  xassert(blk == temp);}// primary intent here is to test the code that selects// file names and initiates transfers, rather than that// each file's contents are transferred correctlyvoid SFTPC::testMultipleFileCmds(){  // some data to toss around  DataBlock a("block A");  DataBlock b("block B");  DataBlock c("block C");  // write them to files  a.writeToFile("testmf.a");  b.writeToFile("testmf.b");  c.writeToFile("testmf.c");  // send them  interactivePrompting = false;  asciiTransfers = false;  userCommand("mput testmf.*");  // just to verify it doesn't crash...  userCommand("mls testmf.*");  // delete the local versions  removeFile("testmf.a");  removeFile("testmf.b");  removeFile("testmf.c");  // get them back from the server  userCommand("mget testmf.*");  // verify they all arrived correctly  verifyFile(a, "testmf.a");  verifyFile(b, "testmf.b");  verifyFile(c, "testmf.c");  // remove them from server  userCommand("mdelete testmf.*");  // and locally  removeFile("testmf.a");  removeFile("testmf.b");  removeFile("testmf.c");}// -------------- command line interpretation -----------------// little helperstatic string getCurDir(){  char buf[200];  if (!getCurrentDirectory(buf, 200)) {    return string("(error retrieving current directory!)");  }  else {    return string(buf);  }}void SFTPC::userCommand(char const *command){  // parse the command into words  StrtokParse tok(command, " \t");  if (tok == 0) {    return;       // user didn't type anything  }  // macros for querying command  // (scoped by #undefining at end of fn)  #define WORDnIS(str,n) (0==strcmp(tok[n], (str)))  #define CMDIS(str) WORDnIS(str,0)  #define CMD(str) else if (CMDIS(str))  #define NO_ARG1 if (tok <= 1)  #define ARG1IS(str) WORDnIS(str,1)  #define ARG1(str) else if (ARG1IS(str))  // setting variables conveniently  #define SET_VAR(var, newval)     \    var = newval;                  \    cout << #var " is now " << var << endl /*user supplies semicolon*/  #define TOGGLE_VAR(var) SET_VAR(var, !var)  // toggle if no arguments, or set to match on/off arg  #define TOGGLE_ON_OFF_VAR(var)  \    NO_ARG1 {                     \      TOGGLE_VAR(var);            \    }                             \    ARG1("on") {                  \      SET_VAR(var, true);         \    }                             \    ARG1("off") {                 \      SET_VAR(var, false);        \    }   /* no semicolon! */  // command constraints  #define REQUIRE_ARGS(n)                                           \    if (tok <= n) {                                                 \      cout << "The " << tok[0] << " command requires at least "     \           << n << " arguments.\n"                                  \           << "Try \"help " << tok[0] << "\"\n";                    \      return;                                                       \    }  #define ELSE_BAD_ARG1                             \    else {                                          \      cout << "Unknown argument to " << tok[0]      \           << ": " << tok[1]                        \           << "\nTry \"help " << tok[0] << "\"\n";  \    }  // convenient forms of arguments  char const *arg1 = (tok<=1? NULL : tok[1]);  char const *arg2 = (tok<=2? NULL : tok[2]);  // convenient forms of text following some argument  char const *afterCmd = (tok<=1? "" : command + tok.offset(1));  //char const *afterArg1 = (tok<=2? "" : command + tok.offset(2));  // the alias table that used to be here is now in sftpcdoc.cpp  // -------------- non-protocol actions --------------  if (CMDIS("debug")) {    TOGGLE_ON_OFF_VAR(printOutgoing)    ARG1("1") {      TOGGLE_VAR(showDiagnostics);    }    ARG1("breaker") {      breaker();    }    ARG1("dump") {      dumpVariables();    }    ARG1("binaryAnyway") {      TOGGLE_VAR(binaryTransferAnyway);    }    ARG1("localCRLF") {      TOGGLE_VAR(localConventionIsCRLF);    }    ARG1("localGlobbing") {      TOGGLE_VAR(localGlobbing);    }    ELSE_BAD_ARG1  }  CMD("passive") {    TOGGLE_ON_OFF_VAR(transferPassively)    ELSE_BAD_ARG1  }  CMD("ascii") {    SET_VAR(asciiTransfers, true);  }  CMD("binary") {    SET_VAR(asciiTransfers, false);  }  CMD("type") {    REQUIRE_ARGS(1)    SET_VAR(asciiTransfers, ARG1IS("a"));  }  CMD("lcd") {    char const *destDir = arg1;    if (!destDir) {      // with no arguments, change to home directory      destDir = getenv("HOME");      if (!destDir) {        cout << "Can't change to home directory because environment\n"                "variable HOME is not defined.\n";        goto endOfLcd;      }    }    if (!changeDirectory(destDir)) {      cout << "Couldn't change to " << destDir << endl;    }    else {      cout << "Current local directory changed to " << getCurDir() << endl;    }    endOfLcd:      ;       // gnu requires this (grumble grumble..)  }  CMD("lpwd") {    cout << "Current local directory is " << getCurDir() << endl;  }  CMD("prompt") {    TOGGLE_ON_OFF_VAR(interactivePrompting)    ELSE_BAD_ARG1  }  CMD("quit") {    quitProgram = true;  }  else if (command[0] == '!') {    // advance to next non-ws after '!'    char const *p = command+1;    while (isspace(*p)) {      p++;    }    if (system(p) == -1) {      xsyserror("system");    }  }  CMD("hash") {    TOGGLE_ON_OFF_VAR(printHashMarks)    ELSE_BAD_ARG1  }  // ------------- special protocol actions --------------  CMD("sync") {    if (emptyResponseQueue() == 0) {      cout << "The response queue appears to be empty.\n";    }  }  CMD("test") {    NO_ARG1 {      // run all tests in all modes      static DataSecurityLevel const map[3] =        { DSL_CLEAR, DSL_INTEGRITY, DSL_PRIVATE };      for (int lvl=0; lvl<3; lvl++) {        for (int psv=0; psv<2; psv++) {          if (setDataEncryption(map[lvl])) {            // only run the tests if the server supports the mode            runTests(psv==1 /*passive*/);          }        }      }    }    ARG1("active") {      runTests(false /*passive*/);    }    ARG1("passive") {      runTests(true /*passive*/);    }    ARG1("text") {      testTextTransfers();    }    ARG1("binary") {      testBinaryTransfers();    }    ARG1("multi") {      testMultipleFileCmds();    }    ELSE_BAD_ARG1  }  CMD("quote") {    checkedRequest(Request(afterCmd));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -