Mercurial > hg > truffle
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 +}