comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 #include <stdio.h>
26
27 // This file is currently used for os/solaris/agent too. At some point in time
28 // the source will be reorganized to avoid these ifdefs.
29
30 #ifdef __sun
31 #include <string.h>
32 #include <inttypes.h>
33 #include <sys/byteorder.h>
34 #endif
35
36 #include "IOBuf.hpp"
37
38 // Formats for printing pointers
39 #ifdef _LP64
40 # define INTPTR_FORMAT "0x%016lx"
41 #else /* ! _LP64 */
42 # define INTPTR_FORMAT "0x%08lx"
43 #endif /* _LP64 */
44
45 // Uncomment the #define below to get messages on stderr
46 // #define DEBUGGING
47
48 IOBuf::IOBuf(int inLen, int outLen) {
49 inBuf = new Buffer(inLen);
50 outBuf = new Buffer(outLen);
51 fd = INVALID_SOCKET;
52 outHandle = NULL;
53 usingSocket = true;
54 reset();
55 }
56
57 IOBuf::~IOBuf() {
58 delete inBuf;
59 delete outBuf;
60 }
61
62 void
63 IOBuf::setSocket(SOCKET sock) {
64 fd = sock;
65 usingSocket = true;
66 }
67
68 // Reading/writing files is only needed and used on windows.
69 #ifdef WIN32
70 void
71 IOBuf::setOutputFileHandle(HANDLE handle) {
72 outHandle = handle;
73 usingSocket = false;
74 }
75 #endif
76
77 void
78 IOBuf::reset() {
79 gotDataLastTime = false;
80 state = TEXT_STATE;
81 binPos = 0;
82 binLength = 0;
83 }
84
85 IOBuf::ReadLineResult
86 IOBuf::tryReadLine() {
87 return doReadLine(false);
88 }
89
90 char*
91 IOBuf::readLine() {
92 ReadLineResult rr = doReadLine(true);
93 if (rr != RL_GOT_DATA) {
94 return NULL;
95 }
96 return getLine();
97 }
98
99 IOBuf::ReadLineResult
100 IOBuf::doReadLine(bool shouldWait) {
101
102 if (!usingSocket) {
103 return IOBuf::RL_ERROR;
104 }
105
106 if (gotDataLastTime) {
107 curLine.clear();
108 }
109
110 int c;
111 do {
112 c = readChar(shouldWait);
113 if (c >= 0) {
114 Action act = processChar((char) c);
115 if (act == GOT_LINE) {
116 curLine.push_back('\0');
117 gotDataLastTime = true;
118 return IOBuf::RL_GOT_DATA;
119 } else if (act == SKIP_EOL_CHAR) {
120 // Do nothing
121 } else {
122 curLine.push_back((char) c);
123 }
124 }
125 } while (shouldWait || c >= 0);
126
127 gotDataLastTime = false;
128 return IOBuf::RL_NO_DATA;
129 }
130
131 bool
132 IOBuf::flushImpl(bool moreDataToCome) {
133 int numWritten = 0;
134
135 #ifdef WIN32
136 // When running on Windows and using IOBufs for inter-process
137 // communication, we need to write metadata into the stream
138 // indicating how many bytes are coming down. Five bytes are written
139 // per flush() call, four containing the integer number of bytes
140 // coming (not including the five-byte header) and one (a 0 or 1)
141 // indicating whether there is more data coming.
142 if (!usingSocket) {
143 int numToWrite = outBuf->drainRemaining();
144 char moreToCome = (moreDataToCome ? 1 : 0);
145 DWORD numBytesWritten;
146 if (!WriteFile(outHandle, &numToWrite, sizeof(int), &numBytesWritten, NULL)) {
147 return false;
148 }
149 if (numBytesWritten != sizeof(int)) {
150 return false;
151 }
152 if (!WriteFile(outHandle, &moreToCome, 1, &numBytesWritten, NULL)) {
153 return false;
154 }
155 if (numBytesWritten != 1) {
156 return false;
157 }
158 }
159 #endif
160
161 while (outBuf->drainRemaining() != 0) {
162 #ifdef DEBUGGING
163 fprintf(stderr, "Flushing %d bytes\n", outBuf->drainRemaining());
164 #endif
165 if (usingSocket) {
166 numWritten = send(fd, outBuf->drainPos(), outBuf->drainRemaining(), 0);
167 } else {
168 #ifdef WIN32
169 DWORD numBytesWritten;
170 if (!WriteFile(outHandle, outBuf->drainPos(), outBuf->drainRemaining(), &numBytesWritten, NULL)) {
171 numWritten = -1;
172 } else {
173 numWritten = numBytesWritten;
174 }
175 #endif
176 }
177 if (numWritten != -1) {
178 #ifdef DEBUGGING
179 fprintf(stderr, "Flushed %d bytes\n", numWritten);
180 #endif
181 outBuf->incrDrainPos(numWritten);
182 } else {
183 return false;
184 }
185 }
186
187 outBuf->compact();
188
189 return true;
190 }
191
192 int
193 IOBuf::readChar(bool block) {
194 do {
195 int c = inBuf->readByte();
196 if (c >= 0) {
197 return c;
198 }
199 // See whether we need to compact the input buffer
200 if (inBuf->remaining() < inBuf->size() / 2) {
201 inBuf->compact();
202 }
203 // See whether socket is ready
204 fd_set fds;
205 FD_ZERO(&fds);
206 FD_SET(fd, &fds);
207 struct timeval timeout;
208 timeout.tv_sec = 0;
209 timeout.tv_usec = 0;
210 if (block || select(1 + fd, &fds, NULL, NULL, &timeout) > 0) {
211 if (block || FD_ISSET(fd, &fds)) {
212 #ifdef DEBUGGING
213 int b = (block ? 1 : 0);
214 fprintf(stderr, "calling recv: block = %d\n", b);
215 #endif
216 // Read data from socket
217 int numRead = recv(fd, inBuf->fillPos(), inBuf->remaining(), 0);
218 if (numRead < 0) {
219 #ifdef DEBUGGING
220 fprintf(stderr, "recv failed\n");
221 #endif
222 return -1;
223 }
224 inBuf->incrFillPos(numRead);
225 }
226 }
227 } while (block);
228
229 return inBuf->readByte();
230 }
231
232 char*
233 IOBuf::getLine() {
234 #ifdef DEBUGGING
235 fprintf(stderr, "Returning (first 10 chars) \"%.10s\"\n", curLine.begin());
236 #endif
237 return curLine.begin();
238 }
239
240 bool
241 IOBuf::flush() {
242 return flushImpl(false);
243 }
244
245 bool
246 IOBuf::writeString(const char* str) {
247 int len = strlen(str);
248
249 if (len > outBuf->size()) {
250 return false;
251 }
252
253 if (len > outBuf->remaining()) {
254 if (!flushImpl(true)) {
255 return false;
256 }
257 }
258
259 // NOTE we do not copy the null terminator of the string.
260
261 strncpy(outBuf->fillPos(), str, len);
262 outBuf->incrFillPos(len);
263 return true;
264 }
265
266 bool
267 IOBuf::writeInt(int val) {
268 char buf[128];
269 sprintf(buf, "%d", val);
270 return writeString(buf);
271 }
272
273 bool
274 IOBuf::writeUnsignedInt(unsigned int val) {
275 char buf[128];
276 sprintf(buf, "%u", val);
277 return writeString(buf);
278 }
279
280 bool
281 IOBuf::writeBoolAsInt(bool val) {
282 if (val) {
283 return writeString("1");
284 } else {
285 return writeString("0");
286 }
287 }
288
289 bool
290 IOBuf::writeAddress(void* val) {
291 char buf[128];
292 sprintf(buf, INTPTR_FORMAT, val);
293 return writeString(buf);
294 }
295
296 bool
297 IOBuf::writeSpace() {
298 return writeString(" ");
299 }
300
301 bool
302 IOBuf::writeEOL() {
303 return writeString("\n\r");
304 }
305
306 bool
307 IOBuf::writeBinChar(char c) {
308 return writeBinBuf((char*) &c, sizeof(c));
309 }
310
311 bool
312 IOBuf::writeBinUnsignedShort(unsigned short i) {
313 i = htons(i);
314 return writeBinBuf((char*) &i, sizeof(i));
315 }
316
317 bool
318 IOBuf::writeBinUnsignedInt(unsigned int i) {
319 i = htonl(i);
320 return writeBinBuf((char*) &i, sizeof(i));
321 }
322
323 bool
324 IOBuf::writeBinBuf(char* buf, int size) {
325 while (size > 0) {
326 int spaceRemaining = outBuf->remaining();
327 if (spaceRemaining == 0) {
328 if (!flushImpl(true)) {
329 return false;
330 }
331 spaceRemaining = outBuf->remaining();
332 }
333 int toCopy = (size > spaceRemaining) ? spaceRemaining : size;
334 memcpy(outBuf->fillPos(), buf, toCopy);
335 outBuf->incrFillPos(toCopy);
336 buf += toCopy;
337 size -= toCopy;
338 if (size > 0) {
339 if (!flushImpl(true)) {
340 return false;
341 }
342 }
343 }
344 return true;
345 }
346
347 #ifdef WIN32
348 IOBuf::FillState
349 IOBuf::fillFromFileHandle(HANDLE fh, DWORD* numBytesRead) {
350 int totalToRead;
351 char moreToCome;
352
353 outBuf->compact();
354
355 DWORD numRead;
356 if (!ReadFile(fh, &totalToRead, sizeof(int), &numRead, NULL)) {
357 return FAILED;
358 }
359 if (numRead != sizeof(int)) {
360 return FAILED;
361 }
362 if (!ReadFile(fh, &moreToCome, 1, &numRead, NULL)) {
363 return FAILED;
364 }
365 if (numRead != 1) {
366 return FAILED;
367 }
368 if (outBuf->remaining() < totalToRead) {
369 return FAILED;
370 }
371
372 int tmp = totalToRead;
373
374 while (totalToRead > 0) {
375 if (!ReadFile(fh, outBuf->fillPos(), totalToRead, &numRead, NULL)) {
376 return FAILED;
377 }
378 outBuf->incrFillPos((int) numRead);
379 totalToRead -= numRead;
380 }
381
382 *numBytesRead = tmp;
383 return ((moreToCome == 0) ? DONE : MORE_DATA_PENDING);
384 }
385 #endif
386
387 bool
388 IOBuf::isBinEscapeChar(char c) {
389 return (c == '|');
390 }
391
392 IOBuf::Action
393 IOBuf::processChar(char c) {
394 Action action = NO_ACTION;
395 switch (state) {
396 case TEXT_STATE: {
397 // Looking for text char, bin escape char, or EOL
398 if (isBinEscapeChar(c)) {
399 #ifdef DEBUGGING
400 fprintf(stderr, "[a: '%c'] ", inBuf[0]);
401 #endif
402 binPos = 0;
403 #ifdef DEBUGGING
404 fprintf(stderr, "[b: '%c'] ", inBuf[0]);
405 #endif
406 binLength = 0;
407 #ifdef DEBUGGING
408 fprintf(stderr, "[c: '%c'] ", inBuf[0]);
409 #endif
410 state = BIN_STATE;
411 #ifdef DEBUGGING
412 fprintf(stderr, "[d: '%c'] ", inBuf[0]);
413 #endif
414 #ifdef DEBUGGING
415 fprintf(stderr, "\nSwitching to BIN_STATE\n");
416 #endif
417 } else if (isEOL(c)) {
418 state = EOL_STATE;
419 action = GOT_LINE;
420 #ifdef DEBUGGING
421 fprintf(stderr, "\nSwitching to EOL_STATE (GOT_LINE)\n");
422 #endif
423 }
424 #ifdef DEBUGGING
425 else {
426 fprintf(stderr, "'%c' ", c);
427 fflush(stderr);
428 }
429 #endif
430 break;
431 }
432
433 case BIN_STATE: {
434 // Seeking to finish read of input
435 if (binPos < 4) {
436 int cur = c & 0xFF;
437 binLength <<= 8;
438 binLength |= cur;
439 ++binPos;
440 } else {
441 #ifdef DEBUGGING
442 fprintf(stderr, "Reading binary byte %d of %d\n",
443 binPos - 4, binLength);
444 #endif
445 ++binPos;
446 if (binPos == 4 + binLength) {
447 state = TEXT_STATE;
448 #ifdef DEBUGGING
449 fprintf(stderr, "Switching to TEXT_STATE\n");
450 #endif
451 }
452 }
453 break;
454 }
455
456 case EOL_STATE: {
457 // More EOL characters just cause us to re-enter this state
458 if (isEOL(c)) {
459 action = SKIP_EOL_CHAR;
460 } else if (isBinEscapeChar(c)) {
461 binPos = 0;
462 binLength = 0;
463 state = BIN_STATE;
464 } else {
465 state = TEXT_STATE;
466 #ifdef DEBUGGING
467 fprintf(stderr, "'%c' ", c);
468 fflush(stderr);
469 #endif
470 }
471 break;
472 }
473
474 } // switch
475
476 return action;
477 }
478
479
480 bool
481 IOBuf::isEOL(char c) {
482 #ifdef WIN32
483 return ((c == '\n') || (c == '\r'));
484 #elif defined(__sun)
485 return c == '\n';
486 #else
487 #error Please port isEOL() to your platform
488 return false;
489 #endif
490 }