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

📄 sftpc.cpp

📁 伯克利做的SFTP安全文件传输协议
💻 CPP
📖 第 1 页 / 共 5 页
字号:
  StreamInputSource &src, StreamOutputDest &dest,  FromCRLFTranslator translator){  int bareCRs=0, bareLFs=0;  translator(src, dest, bareCRs, bareLFs);  if (bareCRs != 0  ||  bareLFs != 0) {    cout << "warning: Data had " << bareCRs << " bare CRs and "                                 << bareLFs << " bare LFs.\n"         << "         (Confusing?  Try \"help crlf\".)\n";  }}STATICDEF void SFTPC::LF_to_CRLF(  StreamInputSource &src, StreamOutputDest &dest){  int CRs=0;  ::LF_to_CRLF(src, dest, CRs);  if (CRs != 0) {    cout << "warning: Data had " << CRs << " CRs.\n"         << "         (Confusing?  Try \"help crlf\".)\n";  }}SFTPC::CRLFTranslator SFTPC::getCRLFTranslator(bool fromCRLF){  if (localConventionIsCRLF) {    diagnostic("using CRLF_to_CRLF");    return &CRLF_to_CRLF;  }  else {    if (fromCRLF) {      diagnostic("using CRLF_to_LF");      return &CRLF_to_LF;    }    else {      diagnostic("using LF_to_CRLF");      return &LF_to_CRLF;    }  }}// copy data from a socket to a file// handles ascii and binary transfers// returns number of bytes received over networkint SFTPC::copyFromSocketToStream(  SOCKET sourceSocket, StreamOutputDest &destStream, bool asciiMode){  if (asciiMode) {    // must convert from CRLF to native    // funky source    int totlen=0;    EncryptedInputStreamer sourceStream(*this, sourceSocket, totlen);    // call Flex-generated scanner to do translation    CRLFTranslator translator = getCRLFTranslator(true /*fromCRLF*/);    translator(sourceStream, destStream);    return totlen;  }  else {    // straight copying    int totlen=0;    for(;;) {      int len = readEitherWay(sourceSocket);      if (len == 0) {        // end of file        break;      }      destStream.write((char const*)dataBuffer.getDataC(), len);      totlen+=len;    }    return totlen;  }}// copy data from a file to a socket// handles ascii and binary transfers// returns number of bytes sent over networkint SFTPC::copyFromStreamToSocket(  StreamInputSource &sourceStream, SOCKET destSocket, bool asciiMode){  // calculate how much cleartext we can get  int cleartextLen;  if (isDataChannelEncrypted()) {    cleartextLen = security->      data().maximumCleartextSizeForBlock(PBSZ);  }  else {    cleartextLen = UNENCRYPTED_BUFSIZE;  }  diagnostic("cleartextLen is " << cleartextLen);  if (asciiMode) {    // must convert from native to CRLF    // funky dest    int totlen=0;    {      // inside braces to be sure of dtor order, since the dtor does      // protocol stuff      EncryptedOutputStreamer destStream(        *this, destSocket, cleartextLen, totlen);      // call Flex-generated scanner to do translation      CRLFTranslator translator = getCRLFTranslator(false /*fromCRLF*/);      translator(sourceStream, destStream);    }    return totlen;  }  else {    // straight copying    // copy data from the file to the socket    int totlen=0;    for(;;) {      // read from file      xassert(cleartextLen <= dataBuffer.getAllocated());      int len = sourceStream.read((char*)dataBuffer.getData(), cleartextLen);      dataBuffer.setDataLen(len);      // write to socket      writeEitherWay(destSocket);      totlen += len;      if (len == 0) {   // eof        break;      }    }    return totlen;  }}// read data from s into dataBuffervoid SFTPC::readCleartext(SOCKET socket){  recvAllToEOFBlock(socket, dataBuffer,                    dataBuffer.getAllocated());}// write data from dataBuffer to svoid SFTPC::writeCleartext(SOCKET socket){  sendAll(socket, (char const*)dataBuffer.getDataC(),                  dataBuffer.getDataLen());}// read data from 'socket', decrypt it into dataBuffervoid SFTPC::readAndDecrypt(SOCKET socket){  // read block size  long blockSize = recvNBO32(socket);  xassert(blockSize <= PBSZ);  // read that much data  recvAllBlock(socket, dataBuffer, blockSize);  // decrypt data  xassert(security);  security->data().decode(dataBuffer);}// encrypt the data in dataBuffer, send it to 'socket'void SFTPC::encryptAndWrite(SOCKET socket){  // encrypt data  xassert(security);  security->data().encode(dataBuffer);  // send block size  long blockSize = dataBuffer.getDataLen();  xassert(blockSize <= PBSZ);  sendNBO32(socket, blockSize);  // send the data  sendAll(socket, (char const*)dataBuffer.getDataC(), blockSize);}// auto-multiplexingint SFTPC::readEitherWay(SOCKET socket){  if (isDataChannelEncrypted()) {    readAndDecrypt(socket);  }  else {    readCleartext(socket);  }  return dataBuffer.getDataLen();}void SFTPC::writeEitherWay(SOCKET socket){  if (isDataChannelEncrypted()) {    encryptAndWrite(socket);  }  else {    writeCleartext(socket);  }}// ---------------- multiple-file commands ----------------------void SFTPC::mlsCommand(char const *pattern){  // get strings that match the pattern  Queue<string> queue = getRemoteNames(pattern);  // process each file in the queue  while (!queue.isEmpty()) {    // grab name    string name = queue.dequeue();    // print it    cout << name << endl;  }}void SFTPC::mgetCommand(char const *pattern){  // get strings that match the pattern  Queue<string> queue = getRemoteNames(pattern);  // process them  multipleFileCommand(queue, CMD_RETR);}void SFTPC::mputCommand(char const *pattern){  // get strings that match the pattern  Queue<string> queue = getLocalNames(pattern);  // process them  multipleFileCommand(queue, CMD_STOR);}void SFTPC::mdeleteCommand(char const *pattern){  // get strings that match the pattern  Queue<string> queue = getRemoteNames(pattern);  // process them  multipleFileCommand(queue, CMD_DELE);}// get a single-character responsechar SFTPC::getOneChar(char const *prompt, char const *allowable){  // write prompt  cout << prompt;  cout.flush();  // read single character  setRawMode(true);      // terminal buffering off  for(;;) {    char ch = getConsoleChar();    if (strchr(allowable, ch)) {      // ok      setRawMode(false);      cout << ch << endl;    // echo what we accepted      return ch;    }    if (ch == 3) {           // in raw mode, I *do* see ^C, at least on some systems      setRawMode(false);      xfailure("user typed ^C");    // if I see it, bail    }    // beeping the terminal might be an option here, but whatever  }}void SFTPC::multipleFileCommand(Queue<string> &queue, RequestCommand cmd){  // process each file in the queue  bool localOverride = false;  while (!queue.isEmpty()) {    // grab name    string name = queue.dequeue();    // print it    cout << name;    // prompt (if user wants it)    if (interactivePrompting && !localOverride) {      char ch = getOneChar("   ((y)es/(n)o/yes to (a)ll/(q)uit)? ",                           "ynaq");      if (ch == 'n') {        continue;       // go to next name      }      if (ch == 'q') {        return;         // stop altogether      }      if (ch == 'a') {        localOverride = true;     // and proceed with this transfer      }    }    else {      cout << endl;    }    // do the data transfer    for (;;) {     // poor-man's goto label      try {        if (cmd != CMD_DELE) {          dataTransfer(cmd, name, name /*local name, if needed*/);        }        else {          checkedRequest(cmd, name);        }      }      catch (xReply &) {        // the message will already have been printed, so just prompt        // (can't use a goto here because of initialization of 'x' stuff)        switch (getOneChar("(c)ontinue, (a)bort, or (r)etry? ", "car")) {          case 'a':            return;    // bail completely          case 'r':            continue;  // go to top of loop        }      }      catch (xBase &x) {        // the justification for all this mechanism?  when we are using        // remote-side globbing, we sometimes get names like "a/b"; this        // can be useful, but if the directory "a" doesn't exist, it will        // fail; so this loop lets the user go make the directory, then        // proceed        cout << x << endl;        switch (getOneChar("(c)ontinue, (a)bort, or (r)etry? ", "car")) {          case 'a':            return;    // bail completely          case 'r':            continue;  // go to top of loop        }      }      break;    }  }}Queue<string> SFTPC::getRemoteNames(char const *pattern){  // PORT, etc.  SOCKET dataChannel =    startDataTransfer(CMD_NLST, localGlobbing? (char const*)NULL : pattern);  diagnostic("waiting for directory listing");  // line parser  int networkBytes = 0;  EncryptedInputStreamer stream(*this, dataChannel, networkBytes);  StreamLineReader liner(stream);  // add all the strings to the queue  Queue<string> queue;  string s;  while (liner.getNextLine(s)) {    //diagnostic("enqueueing: " << s);    queue.enqueue(s);  }  diagnostic("received entire directory listing (" << queue.count() <<             " names, " << networkBytes << " bytes)");  // close socket, and check 226 reply  close_socket(dataChannel);  readAndCheckFinalReplyCode();  // filter based on pattern (if local globbing)  if (localGlobbing) {    filterStrings(queue, pattern);    // quick feedback    cout << queue.count() << " names match the pattern\n";  }  else {    cout << queue.count() << " names returned\n";  }  return queue;}void SFTPC::filterStrings(Queue<string> &queue, char const *pattern){  // move queue elements into source queue  Queue<string> src(queue);  queue.empty();  // process them in order  while (!src.isEmpty()) {    string name = src.dequeue();    if (glob(name, pattern)) {      queue.enqueue(name);    }  }}STATICDEF bool SFTPC::getLocalNamesHelper(  char const *fname, void *extra){  Queue<string> *q = (Queue<string>*)extra;  if (fileOrDirectoryExists(fname) &&        // we need this check because some programs (emacs..) create symlinks        // that don't link anywhere valid; calling isDirectory on such a file        // will fail (and throw an exception, since sftpc installs an        // exception-throwing 'fail' routine); but fileOrDirectoryExists simply        // returns false when stat(2) fails, so this safely avoids the        // exception (could also just catch the exception.. I'm undecided on        // which is best)      !isDirectory(fname)) {    q->enqueue(fname);  }  return true;    // continue;}Queue<string> SFTPC::getLocalNames(char const *pattern){  // retrieve all local names  Queue<string> ret;  applyToCwdContents(getLocalNamesHelper, &ret);  // filter based on pattern  filterStrings(ret, pattern);  cout << ret.count() << " file names match the pattern\n";  return ret;}// ------------- automatic online testing ------------------// test binary-mode transfervoid SFTPC::testBinaryTransfers(){  // binary transfer mode  TransferState bin(false /*ascii*/, false /*localcrlf*/,                    false /*binaryAnyway*/);  // small but pathological  static char const smal[] =    "\0abc\n\r\r\n\xff\xfe\x01\x02\0\tyadda smacker\0\0\0foo";  DataBlock smallBlock(smal, sizeof(smal)-1);  testSendReceiveBlocks(smallBlock, bin, smallBlock, bin);  // medium and large sizes, simple structure  int sizes[2] = { 2345, 480000 };  loopi(TABLESIZE(sizes)) {    // construct data    int sz = sizes[i];    DataBlock block(sz);    loopj(sz) {      block.getData()[j] = (byte)j;    }    block.setDataLen(sz);    // send/recv    testSendReceiveBlocks(block, bin, block, bin);  }}// test text-mode transfervoid SFTPC::testTextTransfers(){

⌨️ 快捷键说明

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