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

📄 sockutil.cpp

📁 伯克利做的SFTP安全文件传输协议
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// sockutil.cc// code for sockutil.h// copyright SafeTP Development Group, Inc., 2000  Terms of use are as specified in license.txt#include "xassert.h"      // xassert#include <string.h>       // strlen, memset#include <stdio.h>        // printf#include <stdlib.h>       // exit, rand, srand#include "socket.h"       // socket functions#include "strtokp.h"      // StrtokParse#include "nonport.h"      // portableSleep, getProcessId#include "sockutil.h"     // this module// ---------- diagnostic facilities ------------------// general diagnostic#ifdef SOCKUTIL_DIAGNOSTICS#  define DIAGNOSTIC 1#else#  define DIAGNOSTIC 0#endif// connection activity: socket open, close#define CONN_DIAGNOSTIC 1// data activity: send and receive#define DATA_DIAGNOSTIC 0// select block/unblock#define SELECT_DIAGNOSTIC 0#if DIAGNOSTIC#  include <iostream.h>      // cout#  define diagnostic(expr) cout << "socket(" << numSocketsOpen() << "): " << expr << endl#else#  define diagnostic(expr) ((void)0)#endif#if CONN_DIAGNOSTIC#  define connDiagnostic(expr) diagnostic(expr)#else#  define connDiagnostic(expr) ((void)0)#endif#if DATA_DIAGNOSTIC#  define dataDiagnostic(expr) diagnostic(expr)#else#  define dataDiagnostic(expr)#endif#if SELECT_DIAGNOSTIC#  define selectDiagnostic(expr) diagnostic(expr)#else#  define selectDiagnostic(expr)#endif// ------------------- xSocket ----------------------------xSocket::xSocket(SOCKET s, char const *msg)  : xBase(msg),    socket(s),    graceful(false),    temporary(false){}xSocket::xSocket(SOCKET s)  : xBase("closed gracefully"),    socket(s),    graceful(true),    temporary(false){}xSocket::xSocket(xSocket const &obj)  : xBase(obj),    socket(obj.socket),    graceful(obj.graceful),    temporary(obj.temporary){}xSocket::~xSocket(){}// -------------------- xResolveFailure -----------------------xResolveFailure::xResolveFailure(char const *hn)  : xBase(stringb("Failed to resolve hostname \"" << hn << "\"")),    hostname(hn){}xResolveFailure::xResolveFailure(xResolveFailure const &obj)  : xBase(obj),    hostname(obj.hostname){}xResolveFailure::~xResolveFailure(){}// ----------------- open-sockets counting ------------------// for thread safety, reduce visibility by making static and adding// an underscopre to change the namestatic int _socketsOpen = 0;int numSocketsOpen(){  LOCKER  return _socketsOpen;}void incOpenSockets(){  LOCKER  _socketsOpen++;}void decOpenSockets(){  LOCKER  _socketsOpen--;}// ----------------- other standalone routines ------------------------char recvChar(SOCKET s){  char c;  int len = basicRecv(s, &c, 1);  if (len == 0) {    // graceful close    xsocketClosed(s);  }  return c;}// not efficient at all..string recvLine(SOCKET s){  // phasing out usage, so want to see usage  //breaker();  //printf(" ** recvLine called **\n");  // (reasonably) efficient growing string  stringBuilder buf;  // read 2 chars, since we can't begin testing  // for a final CRLF until there are at least 2  buf << recvChar(s);  buf << recvChar(s);  int len = 2;  // test..  while (!( buf[len-2]=='\r' && buf[len-1]=='\n' )) {    // read another character    buf << recvChar(s);    len++;  }  return string(buf, len-2);    // return string without the EOL sequence}// NOTE: the network buffers are only guaranteed to hold 1 byte for// peeking.  virtually all implementations can hold more, typically 1k// or 4k.  but that's still not infinite, so this should only be used// in situations where the expected string is short.string peekLine(SOCKET s){  enum { BUFSIZE=1024 };    // arbitrary maximum (but remember we expect short strings)  char buf[BUFSIZE];  char const *crlf;  do {    // grab what's in the buffer    int len = recv(s, buf, BUFSIZE-1, MSG_PEEK);    if (len == -1) {      xsocket(s, "recv");    }    buf[len] = 0;   // null terminate so can use strstr    // see if a CRLF is in the buffer    crlf = strstr(buf, "\r\n");    if (!crlf) {      // it's not there      // if what we read maxed-out the buffer      if (len == BUFSIZE-1) {                    // then we're not going to find the CRLF.. I don't know        // a good action to take here        xfailure("peekLine: the buffer filled without seeing a complete line");      }      // wait a little bit before checking again      portableSleep(1);    }  } while (!crlf);  // ok, a string was found; return it (without CRLF)  return string(buf, crlf-buf);}unsigned long recvNBO32(SOCKET s){  unsigned char buf[4];  recvAll(s, (char*)buf, 4);  // construct from big-endian  return (buf[0] << 24) |         (buf[1] << 16) |         (buf[2] << 8) |         buf[3];}void sendNBO32(SOCKET s, unsigned long value){  // represent as big-endian  byte buf[4];  buf[0] = (byte)((value >> 24) & 0xff);  buf[1] = (byte)((value >> 16) & 0xff);  buf[2] = (byte)((value >> 8) & 0xff);  buf[3] = (byte)(value & 0xff);  //printf("NBO32 sending: %X %X %X %X\n",  //       buf[0], buf[1], buf[2], buf[3]);  sendAll(s, (char const*)buf, 4);}void recvAll(SOCKET s, char *buf, int len){  int result = recvAllToEOF(s, buf, len);  if (result < len) {    // this fn throws an exception on EOF    xsocketClosed(s);  }}int basicRecv(SOCKET s, char *buf, int len){  // block until at least 1 byte read  xassert(buf != NULL && len >= 1);  int received = recv(s, buf, len, 0);  if (received == SOCKET_ERROR) {    xsocket(s, "recv");  }  return received;}int recvAllToEOF(SOCKET s, char *buf, int len){  int totalRead = 0;  while (len != 0) {    // block until at least 1 byte read    int xmitted = basicRecv(s, buf, len);    if (xmitted == 0) {      // EOF      break;    }    // quick check to guard against recv writing past end    // due to math error in here    xassert(xmitted <= len);    // advance counters    buf += xmitted;    len -= xmitted;    totalRead += xmitted;  }  return totalRead;}void sendChar(SOCKET s, char c){  int len = basicSend(s, &c, 1);  if (len == 0) {    // graceful closure    xsocketClosed(s);  }}// send all of the specified buffer, blocking// as necessaryvoid sendAll(SOCKET s, char const *buf, int len){  while (len != 0) {    // is send guaranteed to block until at least 1 byte sent?  yes    int sent = basicSend(s, buf, len);    if (sent == 0) {      xsocketClosed(s);    }    xassert(sent <= len);      // can't send more than was in buffer...    buf += sent;    len -= sent;  }}void sendAllString(SOCKET s, char const *str){  sendAll(s, str, strlen(str));}void sendEOL(SOCKET s){  static char const eol[] = "\r\n";  sendAll(s, eol, 2);}int basicSend(SOCKET s, char const *data, int len){  xassert(data != NULL && len >= 1);  int sent = send(s, data, len, 0);  if (sent == SOCKET_ERROR) {    xsocket(s, "send");  }  return sent;}// create a socket, and possibly set SO_RESUSEADDRSOCKET create_socket(){  // create the socket  SOCKET s = socket(AF_INET, SOCK_STREAM, 0);  if (s == INVALID_SOCKET) {    xsocket(s, "socket");  }  incOpenSockets();  // during development, it's annoying when the harder crashes cause  // us to not be able to reuse a port for a while; it also increases  // the # of possible connections for bind-range-of-ports servers  // (I'm questioning this decision, since it affects TCP's reliability,  // but I can't think of a good way to handle it..)  //  // it turns out that on win32 SO_REUSEADDR's semantics are different,  // namely that it *does* allow two sockets to listen to the same  // address (unlike all unix implementations I've encountered); since  // this can especially be a problem with the -r switch, we'll skip  // this on win32; I also added another escape hatch to disable if  // necessary elsewhere  #if !defined(__WIN32__) && !defined(DONT_REUSEADDR)  {    int boolval = 1;    int res = setsockopt(      s /*socket*/,      SOL_SOCKET /*level*/,      SO_REUSEADDR /*optname*/,    // reuse if possible      (char*)&boolval /*optval*/,      sizeof(boolval) /*optlen*/);    if (res == SOCKET_ERROR) {      xsocket(s, "setsockopt", true /*close*/);    }  }  #endif  return s;}// return false on failurebool inner_bind_socket(SOCKET s, IPAddress interface, int port){  // create the address structure  sockaddr_in saddr;  memset((char *)&saddr, 0, sizeof(saddr));  saddr.sin_family     	= AF_INET;  saddr.sin_addr.s_addr = htonl(interface);      // which interface to bind to  saddr.sin_port       	= htons((short)port);    // correct byte order  // attach that local address to the socket  return bind(s, (sockaddr *)&saddr, sizeof(saddr)) != SOCKET_ERROR;}// throw exception on failurevoid bind_socket(SOCKET s, IPAddress interface, int port){  if (!inner_bind_socket(s, interface, port)) {    xsocket(s, "bind", true /*close*/);  }}void bind_socket_range(SOCKET s, IPAddress interface, PortRange const &range){  if (!range.restricted) {    // binding to PORT_ANY makes it unrestricted    bind_socket(s, interface, PORT_ANY);    return;  }  // pick a port to try; use randomness instead of maintaining state  int maxTries = range.high - range.low + 1;  int port = range.low + rand() % maxTries;  // we will as many attempts as there are ports in the range  for (int attempt = 0; attempt < maxTries; attempt++) {    // increment to next port    // (originally I was picking a random port for each attempt; Dan    // suggests that when most ports are used sequential scan may be    // better)    port++;    if (port > range.high) {      port = range.low;    }               if (inner_bind_socket(s, interface, port)) {      return;    }  }  // give up  xSocket x(s, stringb("Failed to bind any ports in the range [" <<                       range.low << "," << range.high << "] after " <<                       maxTries << " attempts; giving up."));  x.temporary = true;    // hopefully  THROW(x);} // put a socket into a listening state; 'interface' is passed// so we can print some diagnosticsvoid listen_socket(SOCKET s, IPAddress interface){  if (listen(s, 5 /*backlog queue size*/) == SOCKET_ERROR) {    xsocket(s, "listen", true /*close*/);  }  if (interface == INADDR_ANY) {    // can't just print 'port' because it could be PORT_ANY    connDiagnostic("listening on port " << getLocalPort(s) <<                   " on all interfaces");  }

⌨️ 快捷键说明

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