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

📄 reply.cpp

📁 伯克利做的SFTP安全文件传输协议
💻 CPP
字号:
// reply.cc// code for reply.h// copyright SafeTP Development Group, Inc., 2000  Terms of use are as specified in license.txt#include <ctype.h>      // isdigit#include <stdlib.h>     // atoi#include <stdio.h>      // printf#include <string.h>     // memcmp#include "xassert.h"    // xassert#include "sockutil.h"   // socket funcs#include "reply.h"      // this module   DOB: leave this line here (solves client include dependency problem)#include "security.h"   // xSecurity#ifndef SAFETPC#  include "lineread.h"   // StreamLineReader#endif// not a truly general decimal-wise OR, but works// when 'mask' is a power of 10static unsigned decimalwiseOR(unsigned x, unsigned mask){  return x / mask * mask % (mask * 10);}// test that x has just one decimal digit, namely// the one set to 1 in maskstatic bool isOneDigit(unsigned x, unsigned mask){  return decimalwiseOR(x, mask) == x;}bool valid(ReplyCodeFirst f){  return RCF_POSITIVE_PRELIMINARY <= f &&         f <= RCF_ENCRYPTED &&         isOneDigit(f, 100);}bool valid(ReplyCodeSecond f){  return RCS_SYNTAX <= f &&         f <= RCS_FILE_SYSTEM &&         isOneDigit(f, 10);}bool valid(ReplyCodeThird t){  return isOneDigit(t, 1);}bool valid(ReplyCode c){  // check constituents.. don't like the code  // duplication here but I don't want to spend  // all day here  return    valid((ReplyCodeFirst)decimalwiseOR(c, 100)) &&    valid((ReplyCodeSecond)decimalwiseOR(c, 10)) &&    valid((ReplyCodeThird)decimalwiseOR(c, 1));}ReplyCodeFirst first(ReplyCode code){  ReplyCodeFirst ret = (ReplyCodeFirst)    decimalwiseOR(code, 100);  xassert(valid(ret));  return ret;}ReplyCodeSecond second(ReplyCode code){  ReplyCodeSecond ret = (ReplyCodeSecond)    decimalwiseOR(code, 10);  xassert(valid(ret));  return ret;}ReplyCodeThird third(ReplyCode code){  ReplyCodeThird ret = (ReplyCodeThird)    decimalwiseOR(code, 1);  xassert(valid(ret));      // shouldn't be able to fail for any input  return ret;}ReplyCode makeCode(ReplyCodeFirst f, ReplyCodeSecond s, ReplyCodeThird t){  ReplyCode ret = ReplyCode(f + s + t);  xassert(valid(ret));  return ret;}// returns true when s begins with a three-digit// reply code, and either legal separatorbool replyCodeStart(char const *s){  return isdigit(s[0]) &&         isdigit(s[1]) &&         isdigit(s[2]) &&         (s[3]==' ' || s[3]=='-');}Reply::Reply(ReplyCode replyCode, char const *firstLine)  : code(replyCode){  init();  append(firstLine);}Reply::Reply(SOCKET s){  init();  parse(&Reply::socketLineGetter, (void*&)s);}// extract CRLF-delimited lines from a socketSTATICDEF string Reply::socketLineGetter(void *&arg){  SOCKET s = (SOCKET)arg;  return recvLine(s);}Reply::Reply(char const *&text){  init();  parse(&Reply::bufferLineGetter, (void*&)text);}// Parse a reply in a buffer.  Multiline replies have lines separated by// CRLF, but the last line can either be terminated by CRLF, OR null ('\0').// We will know where the last line is by the reply code separator syntax;// however, 2228 allows the last CRLF to be missing, in which case we may// have to inspect the nul.  This is somewhat undesirable, because without it// we could have been parsing lots of concatenated replies.  Oh well.// NOTE:  This function updates the value of 'arg' (the char* passed into the//        constructor) to point at the char just beyond the last inspected.STATICDEF string Reply::bufferLineGetter(void *&arg){  char const *&ptr = (char const*&)arg;  char const *start = ptr;  // find the next CRLF or null  char const *end = ptr;  while (end[0] != 0 &&         !( end[0] == '\r' && end[1] == '\n' )) {    end++;  }  // update ptr  if (end[0] == 0) {    // ends in null (implicitly should be last line, but we don't    // check that here)    ptr = end + 1;  }  else {    // ends in CRLF; could be last or could be multiline    ptr = end + 2;  }  // return the string, NOT containing the CRLF (if present); is always  // null terminated  return string(start, end-start);}#ifndef SAFETPCReply::Reply(StreamLineReader &reader){  init();  void *v = (void*)&reader;        // g++ warning hack  parse(&Reply::streamLineGetter, v);}STATICDEF string Reply::streamLineGetter(void *&arg){  StreamLineReader &reader = *((StreamLineReader*)arg);  string ret;  if (!reader.getNextLine(ret)) {    // EOF.. we aren't expecting this... so, let's    // throw an exception    xfailure("stream closed unexpectedly");  }  return ret;}#endif// read next reply; should be faithful to 959 specvoid Reply::parse(LineGetter getter, void *&arg){  // collect lines of reply  for(;;) {    string str = getter(arg);    // add text to reply, without reply code    if (replyCodeStart(str)) {      append(str.pcharc()+4);      if (str[3] == ' ') {        // last line        code = (ReplyCode)atoi(str.pcharc());        if (!( RC_MINIMUM <= code && code <= RC_MAXIMUM )) {          // given an assumption that malformed data is due to          // an attack, we'll throw xSecurity          THROW(xSecurity(stringb("illegal reply code: " << (int)code)));        }        return;      }    }    else {      append(str);    }  }}// first thing in every constructorvoid Reply::init(){  text = alloc(10);  numLines = 0;  // we do *not* set 'code', because some ctors  // set it first and expect it to stick}Reply::Reply(Reply const &obj){  text = alloc(obj.arraySize);  numLines = obj.numLines;  for (int i=0; i<numLines; i++) {    text[i] = new string(*obj.text[i]);  }  code = obj.code;}// allocate the array and set 'arraySize'string **Reply::alloc(int size){  arraySize = size;  string **ret = new string*[arraySize];  for(int i=0; i<arraySize; i++) {    ret[i] = NULL;  }  return ret;}Reply::~Reply(){  for(int i=0; i<numLines; i++) {    delete text[i];  }  delete[] text;}// this is the only place the array growsvoid Reply::append(char const *s){  if (numLines == arraySize) {    // grow    string **newtext = alloc(arraySize*2);    for(int i=0; i<numLines; i++) {      newtext[i] = text[i];    }    delete[] text;    text = newtext;  }  text[numLines++] = new string(s);}// and it allvoid Reply::send(SOCKET s) const{  sendAllString(s, getAllText());}// compose the reply; send format is more restrictive// than 959 specstring Reply::getAllText() const{  stringBuilder sb;  for (int curLine=0; curLine<numLines; curLine++) {    // output the reply code (and ensure only 3 digits)    sb << (int)((unsigned)code % 1000);    // output separator    if (curLine == numLines-1) {      // last line      sb << ' ';    }    else {      // not last line      sb << '-';    }    // output line text    sb << *text[curLine] << "\r\n";  }  return sb;}string Reply::getNthLine(int n) const{  return *text[n];}string Reply::getLastText() const{  if (numLines > 0) {    return *text[numLines-1];  }  else {    return string("");  }}// this is the most suitable format for the client// to apply un-64 and then decodestring Reply::getAllTextAsOneLine() const{  stringBuilder sb;  for (int curLine=0; curLine<numLines; curLine++) {    // append line text    sb << *text[curLine];  }  return sb;}bool Reply::containsADAT() const{  // see if the reply contains some data  bool replyHasAdat =    (code == RC_SECURITY_DATA_EXCHANGE_COMPLETE ||     code == RC_LAST_ADAT ||     code == RC_FIRST_ADAT ||     code == RC_MIDDLE_ADAT) &&    0==memcmp(text[0]->pcharc(), "ADAT=", ADATTagLen);  return replyHasAdat;}// ----------------- xReply --------------------xReply::xReply(ReplyCode c, char const *t)  : xBase(stringb((int)c << " " << t)),    code(c),    text(t){}xReply::xReply(Reply const &reply)  : xBase(stringb((int)(reply.getCode()) << " " <<                  reply.getLastText())),    code(reply.getCode()),    text(reply.getLastText()){}xReply::xReply(xReply const &obj)  : xBase(obj),    code(obj.code),    text(obj.text){}xReply::~xReply(){}// ------------ test code ---------------------#ifdef TEST_REPLY#include "test.h"        // USUAL_MAINvoid entry(){  char const *text = "200-Some stuff\r\n"                     "200 Second line\r\n";  Reply reply(text);  cout << reply.getAllText();  Reply reply2(reply);    // test copy ctor  cout << reply2.getAllText();  char const *adatReply = "334 ADAT=blah blah\r\n";  Reply aReply(adatReply);  xassert(aReply.containsADAT());  cout << "tests passed\n";}USUAL_MAIN#endif // TEST_REPLY

⌨️ 快捷键说明

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