diff agent/src/os/win32/IOBuf.cpp @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/os/win32/IOBuf.cpp	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,490 @@
+/*
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+
+// This file is currently used for os/solaris/agent too.  At some point in time
+// the source will be reorganized to avoid these ifdefs.
+
+#ifdef __sun
+  #include <string.h>
+  #include <inttypes.h>
+  #include <sys/byteorder.h>
+#endif
+
+#include "IOBuf.hpp"
+
+// Formats for printing pointers
+#ifdef _LP64
+#  define INTPTR_FORMAT "0x%016lx"
+#else /* ! _LP64 */
+#  define INTPTR_FORMAT "0x%08lx"
+#endif /* _LP64 */
+
+// Uncomment the #define below to get messages on stderr
+// #define DEBUGGING
+
+IOBuf::IOBuf(int inLen, int outLen) {
+  inBuf = new Buffer(inLen);
+  outBuf = new Buffer(outLen);
+  fd = INVALID_SOCKET;
+  outHandle = NULL;
+  usingSocket = true;
+  reset();
+}
+
+IOBuf::~IOBuf() {
+  delete inBuf;
+  delete outBuf;
+}
+
+void
+IOBuf::setSocket(SOCKET sock) {
+  fd = sock;
+  usingSocket = true;
+}
+
+// Reading/writing files is only needed and used on windows.
+#ifdef WIN32
+void
+IOBuf::setOutputFileHandle(HANDLE handle) {
+  outHandle = handle;
+  usingSocket = false;
+}
+#endif
+
+void
+IOBuf::reset() {
+  gotDataLastTime = false;
+  state          = TEXT_STATE;
+  binPos         = 0;
+  binLength      = 0;
+}
+
+IOBuf::ReadLineResult
+IOBuf::tryReadLine() {
+  return doReadLine(false);
+}
+
+char*
+IOBuf::readLine() {
+  ReadLineResult rr = doReadLine(true);
+  if (rr != RL_GOT_DATA) {
+    return NULL;
+  }
+  return getLine();
+}
+
+IOBuf::ReadLineResult
+IOBuf::doReadLine(bool shouldWait) {
+
+  if (!usingSocket) {
+    return IOBuf::RL_ERROR;
+  }
+
+  if (gotDataLastTime) {
+    curLine.clear();
+  }
+
+  int c;
+  do {
+    c = readChar(shouldWait);
+    if (c >= 0) {
+      Action act = processChar((char) c);
+      if (act == GOT_LINE) {
+        curLine.push_back('\0');
+        gotDataLastTime = true;
+        return IOBuf::RL_GOT_DATA;
+      } else if (act == SKIP_EOL_CHAR) {
+        // Do nothing
+      } else {
+        curLine.push_back((char) c);
+      }
+    }
+  } while (shouldWait || c >= 0);
+
+  gotDataLastTime = false;
+  return IOBuf::RL_NO_DATA;
+}
+
+bool
+IOBuf::flushImpl(bool moreDataToCome) {
+  int numWritten = 0;
+
+#ifdef WIN32
+  // When running on Windows and using IOBufs for inter-process
+  // communication, we need to write metadata into the stream
+  // indicating how many bytes are coming down. Five bytes are written
+  // per flush() call, four containing the integer number of bytes
+  // coming (not including the five-byte header) and one (a 0 or 1)
+  // indicating whether there is more data coming.
+  if (!usingSocket) {
+    int numToWrite = outBuf->drainRemaining();
+    char moreToCome = (moreDataToCome ? 1 : 0);
+    DWORD numBytesWritten;
+    if (!WriteFile(outHandle, &numToWrite, sizeof(int), &numBytesWritten, NULL)) {
+      return false;
+    }
+    if (numBytesWritten != sizeof(int)) {
+      return false;
+    }
+    if (!WriteFile(outHandle, &moreToCome, 1, &numBytesWritten, NULL)) {
+      return false;
+    }
+    if (numBytesWritten != 1) {
+      return false;
+    }
+  }
+#endif
+
+  while (outBuf->drainRemaining() != 0) {
+#ifdef DEBUGGING
+      fprintf(stderr, "Flushing %d bytes\n", outBuf->drainRemaining());
+#endif
+    if (usingSocket) {
+      numWritten = send(fd, outBuf->drainPos(), outBuf->drainRemaining(), 0);
+    } else {
+#ifdef WIN32
+      DWORD numBytesWritten;
+      if (!WriteFile(outHandle, outBuf->drainPos(), outBuf->drainRemaining(), &numBytesWritten, NULL)) {
+        numWritten = -1;
+      } else {
+        numWritten = numBytesWritten;
+      }
+#endif
+    }
+    if (numWritten != -1) {
+#ifdef DEBUGGING
+      fprintf(stderr, "Flushed %d bytes\n", numWritten);
+#endif
+      outBuf->incrDrainPos(numWritten);
+    } else {
+      return false;
+    }
+  }
+
+  outBuf->compact();
+
+  return true;
+}
+
+int
+IOBuf::readChar(bool block) {
+  do {
+    int c = inBuf->readByte();
+    if (c >= 0) {
+      return c;
+    }
+    // See whether we need to compact the input buffer
+    if (inBuf->remaining() < inBuf->size() / 2) {
+      inBuf->compact();
+    }
+    // See whether socket is ready
+    fd_set fds;
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+    struct timeval timeout;
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+    if (block || select(1 + fd, &fds, NULL, NULL, &timeout) > 0) {
+      if (block || FD_ISSET(fd, &fds)) {
+#ifdef DEBUGGING
+        int b = (block ? 1 : 0);
+        fprintf(stderr, "calling recv: block = %d\n", b);
+#endif
+        // Read data from socket
+        int numRead = recv(fd, inBuf->fillPos(), inBuf->remaining(), 0);
+        if (numRead < 0) {
+#ifdef DEBUGGING
+          fprintf(stderr, "recv failed\n");
+#endif
+          return -1;
+        }
+        inBuf->incrFillPos(numRead);
+      }
+    }
+  } while (block);
+
+  return inBuf->readByte();
+}
+
+char*
+IOBuf::getLine() {
+#ifdef DEBUGGING
+  fprintf(stderr, "Returning (first 10 chars) \"%.10s\"\n", curLine.begin());
+#endif
+  return curLine.begin();
+}
+
+bool
+IOBuf::flush() {
+  return flushImpl(false);
+}
+
+bool
+IOBuf::writeString(const char* str) {
+  int len = strlen(str);
+
+  if (len > outBuf->size()) {
+    return false;
+  }
+
+  if (len > outBuf->remaining()) {
+    if (!flushImpl(true)) {
+      return false;
+    }
+  }
+
+  // NOTE we do not copy the null terminator of the string.
+
+  strncpy(outBuf->fillPos(), str, len);
+  outBuf->incrFillPos(len);
+  return true;
+}
+
+bool
+IOBuf::writeInt(int val) {
+  char buf[128];
+  sprintf(buf, "%d", val);
+  return writeString(buf);
+}
+
+bool
+IOBuf::writeUnsignedInt(unsigned int val) {
+  char buf[128];
+  sprintf(buf, "%u", val);
+  return writeString(buf);
+}
+
+bool
+IOBuf::writeBoolAsInt(bool val) {
+  if (val) {
+    return writeString("1");
+  } else {
+    return writeString("0");
+  }
+}
+
+bool
+IOBuf::writeAddress(void* val) {
+  char buf[128];
+  sprintf(buf, INTPTR_FORMAT, val);
+  return writeString(buf);
+}
+
+bool
+IOBuf::writeSpace() {
+  return writeString(" ");
+}
+
+bool
+IOBuf::writeEOL() {
+  return writeString("\n\r");
+}
+
+bool
+IOBuf::writeBinChar(char c) {
+  return writeBinBuf((char*) &c, sizeof(c));
+}
+
+bool
+IOBuf::writeBinUnsignedShort(unsigned short i) {
+  i = htons(i);
+  return writeBinBuf((char*) &i, sizeof(i));
+}
+
+bool
+IOBuf::writeBinUnsignedInt(unsigned int i) {
+  i = htonl(i);
+  return writeBinBuf((char*) &i, sizeof(i));
+}
+
+bool
+IOBuf::writeBinBuf(char* buf, int size) {
+  while (size > 0) {
+    int spaceRemaining = outBuf->remaining();
+    if (spaceRemaining == 0) {
+      if (!flushImpl(true)) {
+        return false;
+      }
+      spaceRemaining = outBuf->remaining();
+    }
+    int toCopy = (size > spaceRemaining) ? spaceRemaining : size;
+    memcpy(outBuf->fillPos(), buf, toCopy);
+    outBuf->incrFillPos(toCopy);
+    buf += toCopy;
+    size -= toCopy;
+    if (size > 0) {
+      if (!flushImpl(true)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+#ifdef WIN32
+IOBuf::FillState
+IOBuf::fillFromFileHandle(HANDLE fh, DWORD* numBytesRead) {
+  int totalToRead;
+  char moreToCome;
+
+  outBuf->compact();
+
+  DWORD numRead;
+  if (!ReadFile(fh, &totalToRead, sizeof(int), &numRead, NULL)) {
+    return FAILED;
+  }
+  if (numRead != sizeof(int)) {
+    return FAILED;
+  }
+  if (!ReadFile(fh, &moreToCome, 1, &numRead, NULL)) {
+    return FAILED;
+  }
+  if (numRead != 1) {
+    return FAILED;
+  }
+  if (outBuf->remaining() < totalToRead) {
+    return FAILED;
+  }
+
+  int tmp = totalToRead;
+
+  while (totalToRead > 0) {
+    if (!ReadFile(fh, outBuf->fillPos(), totalToRead, &numRead, NULL)) {
+      return FAILED;
+    }
+    outBuf->incrFillPos((int) numRead);
+    totalToRead -= numRead;
+  }
+
+  *numBytesRead = tmp;
+  return ((moreToCome == 0) ? DONE : MORE_DATA_PENDING);
+}
+#endif
+
+bool
+IOBuf::isBinEscapeChar(char c) {
+  return (c == '|');
+}
+
+IOBuf::Action
+IOBuf::processChar(char c) {
+  Action action = NO_ACTION;
+  switch (state) {
+  case TEXT_STATE: {
+    // Looking for text char, bin escape char, or EOL
+    if (isBinEscapeChar(c)) {
+#ifdef DEBUGGING
+      fprintf(stderr, "[a: '%c'] ", inBuf[0]);
+#endif
+      binPos = 0;
+#ifdef DEBUGGING
+      fprintf(stderr, "[b: '%c'] ", inBuf[0]);
+#endif
+      binLength = 0;
+#ifdef DEBUGGING
+      fprintf(stderr, "[c: '%c'] ", inBuf[0]);
+#endif
+      state = BIN_STATE;
+#ifdef DEBUGGING
+      fprintf(stderr, "[d: '%c'] ", inBuf[0]);
+#endif
+#ifdef DEBUGGING
+      fprintf(stderr, "\nSwitching to BIN_STATE\n");
+#endif
+    } else if (isEOL(c)) {
+      state = EOL_STATE;
+      action = GOT_LINE;
+#ifdef DEBUGGING
+      fprintf(stderr, "\nSwitching to EOL_STATE (GOT_LINE)\n");
+#endif
+    }
+#ifdef DEBUGGING
+    else {
+      fprintf(stderr, "'%c' ", c);
+      fflush(stderr);
+    }
+#endif
+    break;
+  }
+
+  case BIN_STATE: {
+    // Seeking to finish read of input
+    if (binPos < 4) {
+      int cur = c & 0xFF;
+      binLength <<= 8;
+      binLength |= cur;
+      ++binPos;
+    } else {
+#ifdef DEBUGGING
+      fprintf(stderr, "Reading binary byte %d of %d\n",
+              binPos - 4, binLength);
+#endif
+      ++binPos;
+      if (binPos == 4 + binLength) {
+        state = TEXT_STATE;
+#ifdef DEBUGGING
+        fprintf(stderr, "Switching to TEXT_STATE\n");
+#endif
+      }
+    }
+    break;
+  }
+
+  case EOL_STATE: {
+    // More EOL characters just cause us to re-enter this state
+    if (isEOL(c)) {
+      action = SKIP_EOL_CHAR;
+    } else if (isBinEscapeChar(c)) {
+      binPos = 0;
+      binLength = 0;
+      state = BIN_STATE;
+    } else {
+      state = TEXT_STATE;
+#ifdef DEBUGGING
+      fprintf(stderr, "'%c' ", c);
+      fflush(stderr);
+#endif
+    }
+    break;
+  }
+
+  } // switch
+
+  return action;
+}
+
+
+bool
+IOBuf::isEOL(char c) {
+#ifdef WIN32
+  return ((c == '\n') || (c == '\r'));
+#elif defined(__sun)
+  return c == '\n';
+#else
+  #error Please port isEOL() to your platform
+  return false;
+#endif
+}