IOBuf.hpp 7.3 KB
Newer Older
D
duke 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
/*
 * Copyright 2000-2003 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 */

#ifndef _IO_BUF_
#define _IO_BUF_

// This file is currently used for os/solaris/agent/ too.  At some point in time
// the source will be reorganized to avoid these ifdefs.
// Note that this class can read/write from a file as well as a socket.  This
// file capability is only implemented on win32.

#ifdef WIN32
  #include <winsock2.h>
#else
  #include <sys/types.h>
  #include <sys/socket.h>
  // These are from win32 winsock2.h
  typedef unsigned int SOCKET;
  typedef void * HANDLE;
  typedef unsigned long DWORD;
  #define INVALID_SOCKET (SOCKET)(~0)
#endif

#include <vector>
#include "Buffer.hpp"

/** Manages an input/output buffer pair for a socket or file handle. */
class IOBuf {
public:
  IOBuf(int inBufLen, int outBufLen);
  ~IOBuf();

  enum ReadLineResult {
    RL_GOT_DATA,
    RL_NO_DATA,
    RL_ERROR
  };

  /** Change the socket with which this buffer is associated */
  void setSocket(SOCKET sock);

  // Reading/writing files is only supported on windows.
#ifdef WIN32
  /** Change the output file handle with which this buffer is
      associated. Currently IOBufs can not be used to read from a file
      handle. */
  void setOutputFileHandle(HANDLE handle);
#endif

  /** Reset the input and output buffers, without flushing the output
      data to the socket */
  void reset();

  /** Try to read a line of data from the given socket without
      blocking. If was able to read a complete line of data, returns a
      character pointer to the beginning of the (null-terminated)
      string. If not, returns NULL, but maintains enough state that
      subsequent calls to tryReadLine() will not ignore the data
      already read. NOTE: this skips end-of-line characters (typically
      CR/LF) as defined by "isEOL()". When switching back and forth
      between binary and text modes, to be sure no data is lost, pad
      the beginning and end of the binary transmission with bytes
      which can not be confused with these characters. */
  ReadLineResult tryReadLine();

  /** Read a line of data from the given socket, blocking until a
      line, including EOL, appears.  Return the line, or NULL if
      something goes wrong. */
  char *readLine();

  /** Get the pointer to the beginning of the (null-terminated) line.
      This should only be called if tryReadLine() has returned
      RL_GOT_DATA. This sets the "parsing cursor" to the beginning of
      the line. */
  char* getLine();

  // NOTE: any further data-acquisition routines must ALWAYS call
  // fixupData() at the beginning!

  //----------------------------------------------------------------------
  // Output routines
  //

  /** Flush the output buffer to the socket. Returns true if
      succeeded, false if write error occurred. */
  bool flush();

  /** Write the given string to the output buffer. May flush if output
      buffer becomes too full to store the data. Not guaranteed to
      work if string is longer than the size of the output buffer.
      Does not include the null terminator of the string. Returns true
      if succeeded, false if write error occurred. */
  bool writeString(const char* str);

  /** Write the given int to the output buffer. May flush if output
      buffer becomes too full to store the data. Returns true if
      succeeded, false if write error occurred. */
  bool writeInt(int val);

  /** Write the given unsigned int to the output buffer. May flush if
      output buffer becomes too full to store the data. Returns true
      if succeeded, false if write error occurred. */
  bool writeUnsignedInt(unsigned int val);

  /** Write the given boolean to the output buffer. May flush if
      output buffer becomes too full to store the data. Returns true
      if succeeded, false if write error occurred. */
  bool writeBoolAsInt(bool val);

  /** Write the given address to the output buffer. May flush if
      output buffer becomes too full to store the data. Returns true
      if succeeded, false if write error occurred. */
  bool writeAddress(void* val);

  /** Writes a space to the output buffer. May flush if output buffer
      becomes too full to store the data. Returns true if succeeded,
      false if write error occurred. */
  bool writeSpace();

  /** Writes an end-of-line sequence to the output buffer. May flush
      if output buffer becomes too full to store the data. Returns
      true if succeeded, false if write error occurred. */
  bool writeEOL();

  /** Writes a binary character to the output buffer. */
  bool writeBinChar(char c);

  /** Writes a binary unsigned short in network (big-endian) byte
      order to the output buffer. */
  bool writeBinUnsignedShort(unsigned short i);

  /** Writes a binary unsigned int in network (big-endian) byte order
      to the output buffer. */
  bool writeBinUnsignedInt(unsigned int i);

  /** Writes a binary buffer to the output buffer. */
  bool writeBinBuf(char* buf, int size);

#ifdef WIN32
  enum FillState {
    DONE = 1,
    MORE_DATA_PENDING = 2,
    FAILED = 3
  };

  /** Very specialized routine; fill the output buffer from the given
      file handle. Caller is responsible for ensuring that there is
      data to be read on the file handle. */
  FillState fillFromFileHandle(HANDLE fh, DWORD* numRead);
#endif

  /** Binary utility routine (for poke) */
  static bool isBinEscapeChar(char c);

private:
  IOBuf(const IOBuf&);
  IOBuf& operator=(const IOBuf&);

  // Returns -1 if non-blocking and no data available
  int readChar(bool block);
  // Line-oriented reading
  std::vector<char> curLine;
  bool gotDataLastTime;

  ReadLineResult doReadLine(bool);

  bool flushImpl(bool moreDataToCome);

  SOCKET fd;
  HANDLE outHandle;
  bool usingSocket;

  // Buffers
  Buffer* inBuf;
  Buffer* outBuf;

  // Simple finite-state machine to handle binary data
  enum State {
    TEXT_STATE,
    BIN_STATE,
    EOL_STATE
  };
  enum Action {
    NO_ACTION,
    GOT_LINE,     // TEXT_STATE -> EOL_STATE transition
    SKIP_EOL_CHAR // EOL_STATE -> EOL_STATE transition
  };

  State state;
  Action processChar(char c);

  // Handling incoming binary buffers (poke command)
  int   binPos;    // Number of binary characters read so far;
                   // total number to read is binLength + 4
  int   binLength; // Number of binary characters in message;
                   // not valid until binPos >= 4

  bool isEOL(char c);
};

#endif  // #defined _IO_BUF_