00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef _WINDOWS
00022 #include <windows.h>
00023 #include <winsock.h>
00024 #else
00025 #include <sys/types.h>
00026 #include <sys/socket.h>
00027 #include <unistd.h>
00028 #include <sys/time.h>
00029 #endif
00030
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <math.h>
00034 #include <stdio.h>
00035
00036 #include "binarytermreader.h"
00037 #include "javadistoglib.h"
00038 #include "binarytermtypes.h"
00039 #include "libicl.h"
00040 #include "libicl_private.h"
00041 #include "glib.h"
00042 #include "liboaa.h"
00043
00044 #ifdef _WINDOWS
00045
00046
00047
00048 enum { INITBUFFERSZ = 8388608 };
00049 enum { AMOUNTTOREAD = 8192 };
00050 #else
00051 static const int INITBUFFERSZ = 8388608;
00052 static const int AMOUNTTOREAD = 8192;
00053 #endif
00054
00055 struct BinaryTermReaderStruct
00056 {
00057 TermReader* superReader;
00058 GByteArray* currentBuffer;
00059 }
00060 ;
00061
00062 void binaryTermReader_cleanup(TermReader*);
00063 ICLTerm* binaryTermReader_getNext(TermReader*, double);
00064 ICLTerm* binaryTermReader_parseBuffer(BinaryTermReader* br);
00065 void binaryTermReader_fillData(BinaryTermReader* br, double timeout);
00066 void binaryTermReader_addToCurrentBuffer(BinaryTermReader* br, char* buf, ssize_t len);
00067 void binaryTermReader_cleanupTermList(GQueue*);
00068
00069 BinaryTermReader* binaryTermReader_create(TermReader* t, gint listenSocket)
00070 {
00071 BinaryTermReader* r = (BinaryTermReader*)malloc(sizeof(BinaryTermReader));
00072 r->superReader = t;
00073 r->currentBuffer = g_byte_array_new();
00074 termReader_setReaderSpecificData(t, r);
00075 termReader_setSocket(t, listenSocket);
00076 termReader_setType(t, BINARYTERMREADERTYPE);
00077 termReader_setGetNextCallback(t, binaryTermReader_getNext);
00078 termReader_setCleanupCallback(t, binaryTermReader_cleanup);
00079 termReader_setError(t, TERMREADER_OKAY);
00080 return r;
00081 }
00082
00083 void binaryTermReader_cleanup(TermReader* reader)
00084 {
00085 BinaryTermReader* br = (BinaryTermReader*)termReader_getReaderSpecificData(reader);
00086 if(br->currentBuffer != NULL) {
00087 free(br->currentBuffer);
00088 }
00089 if(br != NULL) {
00090 free(br);
00091 }
00092 }
00093
00094 ICLTerm* binaryTermReader_getNext(TermReader* reader, double timeout)
00095 {
00096 ICLTerm* nextEvent = NULL;
00097 gboolean done = FALSE;
00098 gboolean timedOut = FALSE;
00099 gboolean hadOldData = FALSE;
00100 gboolean forceFill = FALSE;
00101 BinaryTermReader* br = (BinaryTermReader*)termReader_getReaderSpecificData(reader);
00102 while(!done) {
00103 termReader_setError(reader, TERMREADER_OKAY);
00104 if((br->currentBuffer->len == 0) || forceFill) {
00105 binaryTermReader_fillData(br, timeout);
00106 if(termReader_getError(reader) == TERMREADER_TIMEOUT) {
00107 timedOut = TRUE;
00108 }
00109 }
00110 else {
00111 forceFill = FALSE;
00112 hadOldData = TRUE;
00113 }
00114 if((termReader_getError(reader) != TERMREADER_OKAY) &&
00115 !timedOut) {
00116 if(termReader_getError(reader) != TERMREADER_NOCONN) {
00117
00118
00119 fprintf(stderr,
00120 "binaryTermReader_getNext() [%s %i] bad read: %i\n",
00121 __FILE__, __LINE__, termReader_getError(reader));
00122 }
00123 return NULL;
00124 }
00125 if(br->currentBuffer->len > 0) {
00126 CHECK_LEAKS();
00127 nextEvent = binaryTermReader_parseBuffer(br);
00128 CHECK_LEAKS();
00129 if(nextEvent == NULL) {
00130
00131 if(timedOut) {
00132 nextEvent = icl_NewTermFromString("event(timeout)");
00133 return nextEvent;
00134 }
00135 else if(termReader_getError(reader) == TERMREADER_BINNOTENOUGHDATA) {
00136 forceFill = TRUE;
00137 hadOldData = FALSE;
00138 termReader_setError(reader, TERMREADER_OKAY);
00139
00140 continue;
00141 }
00142 else if(termReader_getError(reader) != TERMREADER_OKAY) {
00143 fprintf(stderr, "error in binarytermreader\n");
00144 return NULL;
00145 }
00146 else if(hadOldData) {
00147 forceFill = TRUE;
00148 hadOldData = FALSE;
00149 continue;
00150 }
00151 else {
00152 continue;
00153 }
00154 }
00155 else {
00156
00157
00158
00159
00160 return nextEvent;
00161 }
00162 }
00163 else if(timedOut) {
00164 nextEvent = icl_NewTermFromString("event(timeout)");
00165 return nextEvent;
00166 }
00167 else {
00168 continue;
00169 }
00170 }
00171 return NULL;
00172 }
00173
00174 void binaryTermReader_cleanupTermList(GQueue* termList)
00175 {
00176 ICLTerm* t;
00177 while(!g_queue_is_empty(termList)) {
00178 t = (ICLTerm*)g_queue_pop_tail(termList);
00179 icl_Free(t);
00180 }
00181 g_queue_free(termList);
00182 }
00183
00184 ICLTerm* binaryTermReader_parseBuffer(BinaryTermReader* br)
00185 {
00186 GQueue* termList = g_queue_new();
00187 gboolean done = FALSE;
00188 gint32 type;
00189 gint32 numArgs;
00190 gint32 dataLen;
00191 ICLTerm* newTerm;
00192 gint64 inIclInt = 0;
00193 double inIclFloat = 0;
00194 char* inString = NULL;
00195 char* inData = NULL;
00196 char* currPos = (char*)br->currentBuffer->data;
00197 size_t bufLen = br->currentBuffer->len;
00198 size_t offset = 0;
00199 size_t offsetIncr = 0;
00200 size_t strLen = 0;
00201 char starter = 0;
00202 ICLTerm* args;
00203 int i;
00204
00205
00206
00207 while(!done) {
00208 offsetIncr = javadistoglib_readJavaInt(currPos + offset, bufLen, &type);
00209 if(offsetIncr == 0) {
00210
00211 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00212 binaryTermReader_cleanupTermList(termList);
00213 return NULL;
00214 }
00215 offset += offsetIncr;
00216 bufLen -= offsetIncr;
00217 numArgs = 0;
00218 dataLen = 0;
00219 newTerm = NULL;
00220 switch(type) {
00221 case BTT_SENTINEL:
00222
00223 done = TRUE;
00224 newTerm = (ICLTerm*)g_queue_pop_tail(termList);
00225 if(!g_queue_is_empty(termList)) {
00226 fprintf(stderr, "binaryTermReader_parseBuffer() encountered sentinel but termList not empty\n");
00227 termReader_setError(br->superReader, TERMREADER_BINUNEXPECTEDSENTINEL);
00228 binaryTermReader_cleanupTermList(termList);
00229 return NULL;
00230 }
00231 else {
00232 GByteArray* oldBuf = br->currentBuffer;
00233 br->currentBuffer = g_byte_array_sized_new(br->currentBuffer->len - offset);
00234 g_byte_array_append(br->currentBuffer, oldBuf->data + offset, oldBuf->len - offset);
00235 g_byte_array_free(oldBuf, TRUE);
00236 binaryTermReader_cleanupTermList(termList);
00237 return newTerm;
00238 }
00239 case BTT_ICLINT:
00240
00241 offsetIncr = javadistoglib_readJavaLong(currPos + offset, bufLen, &inIclInt);
00242 if(offsetIncr == 0) {
00243
00244 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00245 binaryTermReader_cleanupTermList(termList);
00246 return NULL;
00247 }
00248 offset += offsetIncr;
00249 bufLen -= offsetIncr;
00250 newTerm = icl_NewInt(inIclInt);
00251 break;
00252 case BTT_ICLFLOAT:
00253
00254 offsetIncr = javadistoglib_readJavaDouble(currPos + offset, bufLen, &inIclFloat);
00255 if(offsetIncr == 0) {
00256
00257 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00258 binaryTermReader_cleanupTermList(termList);
00259 return NULL;
00260 }
00261 offset += offsetIncr;
00262 bufLen -= offsetIncr;
00263 newTerm = icl_NewFloat(inIclFloat);
00264 break;
00265 case BTT_ICLVAR:
00266
00267 offsetIncr = javadistoglib_readJavaInt(currPos + offset, bufLen, &dataLen);
00268 if(offsetIncr == 0) {
00269
00270 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00271 binaryTermReader_cleanupTermList(termList);
00272 return NULL;
00273 }
00274 offset += offsetIncr;
00275 bufLen -= offsetIncr;
00276 if(dataLen < 0) {
00277 fprintf(stderr, "binaryTermReader_parseBuffer() ICLVAR has datalen < 0\n");
00278 termReader_setError(br->superReader, TERMREADER_BINBADICLVAR);
00279 binaryTermReader_cleanupTermList(termList);
00280 return NULL;
00281 }
00282 if(dataLen == 0) {
00283 newTerm = icl_NewVar("_");
00284 }
00285 else {
00286 inString = (char*)malloc((dataLen + 1) * sizeof(char));
00287 offsetIncr = javadistoglib_readJavaChars(currPos + offset, bufLen, dataLen, dataLen + 1, inString);
00288 if(offsetIncr == 0) {
00289
00290 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00291 free(inString);
00292 binaryTermReader_cleanupTermList(termList);
00293 return NULL;
00294 }
00295 offset += offsetIncr;
00296 bufLen -= offsetIncr;
00297 newTerm = icl_NewVarNoCopy(inString);
00298 inString = NULL;
00299 }
00300 break;
00301 case BTT_ICLSTR:
00302
00303 offsetIncr = javadistoglib_readJavaInt(currPos + offset, bufLen, &dataLen);
00304 if(offsetIncr == 0) {
00305 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00306 binaryTermReader_cleanupTermList(termList);
00307 return NULL;
00308 }
00309 offset += offsetIncr;
00310 bufLen -= offsetIncr;
00311 if(dataLen <= 0) {
00312 fprintf(stderr, "binaryTermReader_parseBuffer() ICLSTR has datalen <= 0\n");
00313 termReader_setError(br->superReader, TERMREADER_BINBADICLSTR);
00314 binaryTermReader_cleanupTermList(termList);
00315 return NULL;
00316 }
00317 inString = (char*)malloc((dataLen + 1) * sizeof(char));
00318 offsetIncr = javadistoglib_readJavaChars(currPos + offset, bufLen, dataLen, dataLen + 1, inString);
00319 if(offsetIncr == 0) {
00320
00321 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00322 binaryTermReader_cleanupTermList(termList);
00323 free(inString);
00324 return NULL;
00325 }
00326 offset += offsetIncr;
00327 bufLen -= offsetIncr;
00328 icl_safeStRemoveQuotes(inString, dataLen, &strLen);
00329 icl_safeStUndoubleQuotes(inString, strLen, &strLen);
00330 newTerm = icl_NewStrNoCopy(inString);
00331 inString = NULL;
00332 break;
00333 case BTT_ICLDATAQ:
00334 offsetIncr = javadistoglib_readJavaInt(currPos + offset, bufLen, &dataLen);
00335 if(offsetIncr == 0) {
00336 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00337 binaryTermReader_cleanupTermList(termList);
00338 return NULL;
00339 }
00340 offset += offsetIncr;
00341 bufLen -= offsetIncr;
00342 if(dataLen <= 0) {
00343 fprintf(stderr, "binaryTermReader_parseBuffer() ICLDATAQ has datalen <= 0\n");
00344 }
00345 inData = (char*)malloc(dataLen * sizeof(char));
00346 offsetIncr = javadistoglib_readJavaBytes(currPos + offset, bufLen, dataLen, dataLen, inData);
00347 if(offsetIncr == 0) {
00348 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00349 binaryTermReader_cleanupTermList(termList);
00350 free(inData);
00351 return NULL;
00352 }
00353 offset += offsetIncr;
00354 newTerm = icl_NewDataQNoCopy(inData, dataLen);
00355 inData = NULL;
00356 break;
00357 case BTT_ICLSTRUCT:
00358
00359 offsetIncr = javadistoglib_readJavaInt(currPos + offset, bufLen, &numArgs);
00360 if(offsetIncr == 0) {
00361
00362 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00363 binaryTermReader_cleanupTermList(termList);
00364 return NULL;
00365 }
00366 offset += offsetIncr;
00367 bufLen -= offsetIncr;
00368 offsetIncr = javadistoglib_readJavaInt(currPos + offset, bufLen, &dataLen);
00369 offset += offsetIncr;
00370 bufLen -= offsetIncr;
00371 if(offsetIncr == 0) {
00372
00373 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00374 binaryTermReader_cleanupTermList(termList);
00375 return NULL;
00376 }
00377 if(dataLen <= 0) {
00378 fprintf(stderr, "binaryTermReader_parseBuffer() ICLSTRUCT has datalen <= 0\n");
00379 termReader_setError(br->superReader, TERMREADER_BINBADICLSTRUCT);
00380 binaryTermReader_cleanupTermList(termList);
00381 return NULL;
00382 }
00383 inString = (char*)malloc((dataLen + 1) * sizeof(char));
00384 offsetIncr = javadistoglib_readJavaChars(currPos + offset, bufLen, dataLen, dataLen + 1, inString);
00385 if(offsetIncr == 0) {
00386
00387 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00388 binaryTermReader_cleanupTermList(termList);
00389 free(inString);
00390 return NULL;
00391 }
00392 offset += offsetIncr;
00393 bufLen -= offsetIncr;
00394 args = icl_NewList(NULL);
00395 for(i = 0; i < numArgs; ++i) {
00396 if(g_queue_is_empty(termList)) {
00397 fprintf(stderr, "binaryTermReader_parseBuffer() ICLSTRUCT not enough args\n");
00398 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHARGS);
00399 binaryTermReader_cleanupTermList(termList);
00400 return NULL;
00401 }
00402 icl_AddToList(args, (ICLTerm*)g_queue_pop_tail(termList), TRUE);
00403 }
00404 newTerm = icl_NewStructFromList(inString, args);
00405 free(inString);
00406 inString = NULL;
00407 break;
00408 case BTT_ICLLIST:
00409
00410 offsetIncr = javadistoglib_readJavaInt(currPos + offset, bufLen, &numArgs);
00411 if(offsetIncr == 0) {
00412
00413 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00414 binaryTermReader_cleanupTermList(termList);
00415 return NULL;
00416 }
00417 offset += offsetIncr;
00418 bufLen -= offsetIncr;
00419 newTerm = icl_NewList(NULL);
00420 for(i = 0; i < numArgs; ++i) {
00421 if(g_queue_is_empty(termList)) {
00422 fprintf(stderr, "binaryTermReader_parseBuffer() ICLLIST not enough args\n");
00423 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHARGS);
00424 binaryTermReader_cleanupTermList(termList);
00425 return NULL;
00426 }
00427 icl_AddToList(newTerm, (ICLTerm*)g_queue_pop_tail(termList), TRUE);
00428 }
00429 break;
00430 case BTT_ICLGROUP:
00431
00432 offsetIncr = javadistoglib_readJavaInt(currPos + offset, bufLen, &numArgs);
00433 if(offsetIncr == 0) {
00434
00435 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00436 binaryTermReader_cleanupTermList(termList);
00437 return NULL;
00438 }
00439 offset += offsetIncr;
00440 bufLen -= offsetIncr;
00441 offsetIncr = javadistoglib_readJavaChar(currPos + offset, bufLen, &starter);
00442 if(offsetIncr == 0) {
00443
00444 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHDATA);
00445 binaryTermReader_cleanupTermList(termList);
00446 return NULL;
00447 }
00448 offset += offsetIncr;
00449 bufLen -= offsetIncr;
00450 newTerm = icl_NewGroup(starter, ",", NULL);
00451 for(i = 0; i < numArgs; ++i) {
00452 if(g_queue_is_empty(termList)) {
00453 fprintf(stderr, "binaryTermReader_parseBuffer() ICLGROUP not enough args\n");
00454 termReader_setError(br->superReader, TERMREADER_BINNOTENOUGHARGS);
00455 binaryTermReader_cleanupTermList(termList);
00456 return NULL;
00457 }
00458 icl_AddToList(newTerm, (ICLTerm*)g_queue_pop_tail(termList), TRUE);
00459 }
00460 break;
00461 default:
00462 {
00463 char* format;
00464 if(sizeof(offset) == 4) {
00465 format = "binaryTermReader_parseBuffer() encountered unexpected type: [%i] at offset %d\n";
00466 }
00467 else {
00468 format = "binaryTermReader_parseBuffer() encountered unexpected type: [%i] at offset %ld\n";
00469 }
00470 fprintf(stderr, format, type, offset - offsetIncr);
00471 }
00472 termReader_setError(br->superReader, TERMREADER_BINUNEXPECTEDTYPE);
00473 binaryTermReader_cleanupTermList(termList);
00474 return NULL;
00475 }
00476 g_queue_push_tail(termList, newTerm);
00477 }
00478 fprintf(stderr, "binaryTermReader_parseBuffer() unexpected exit from loop\n");
00479 termReader_setError(br->superReader, TERMREADER_BINUNREACHABLE);
00480 binaryTermReader_cleanupTermList(termList);
00481 return NULL;
00482 }
00483
00484 void binaryTermReader_fillData(BinaryTermReader* br, double timeout)
00485 {
00486 char buf[AMOUNTTOREAD + 1];
00487 struct timeval time;
00488 struct timeval* timep = NULL;
00489 int lastFdPlusOne;
00490 int selectRes = 0;
00491 ssize_t numBytes = 0;
00492 fd_set readfds;
00493
00494
00495 if(timeout > 0) {
00496 long i = (long)floor(timeout);
00497 time.tv_sec = i;
00498 time.tv_usec = (long)floor((timeout - i) * 1e6);
00499 timep = &time;
00500 }
00501
00502 lastFdPlusOne = termReader_getSocket(br->superReader) + 1;
00503 FD_ZERO(&readfds);
00504 FD_SET(termReader_getSocket(br->superReader), &readfds);
00505
00506 selectRes = select(lastFdPlusOne, &readfds, NULL, NULL, timep);
00507
00508 switch(selectRes) {
00509 case -1:
00510 perror("binaryTermReader_fillData bad select");
00511 termReader_setError(br->superReader, TERMREADER_SELECTERR);
00512 return;
00513 case 0:
00514
00515 termReader_setError(br->superReader, TERMREADER_TIMEOUT);
00516 return;
00517 default:
00518 #ifdef _WINDOWS
00519 numBytes = recv(termReader_getSocket(br->superReader), buf, AMOUNTTOREAD, 0);
00520 #else
00521 numBytes = read(termReader_getSocket(br->superReader), buf, AMOUNTTOREAD);
00522 #endif
00523
00524 switch(numBytes) {
00525 case -1:
00526 perror("binaryTermReader_fillData bad read");
00527 termReader_setError(br->superReader, TERMREADER_READERR);
00528 return;
00529 case 0:
00530
00531 termReader_setError(br->superReader, TERMREADER_NOCONN);
00532 return;
00533 }
00534 }
00535
00536 binaryTermReader_addToCurrentBuffer(br, buf, numBytes);
00537 termReader_setError(br->superReader, TERMREADER_OKAY);
00538
00539
00540
00541
00542
00543 }
00544
00545 void binaryTermReader_addToCurrentBuffer(BinaryTermReader* br, char* buf, ssize_t len)
00546 {
00547 g_byte_array_append(br->currentBuffer, (guint8*)buf, len);
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 }