binarytermsender.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006  SRI International
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00017  *
00018  * SRI International: 333 Ravenswood Ave, Menlo Park, CA 94025
00019  */
00020 
00021 #include <string.h>
00022 #include "binarytermsender.h"
00023 #include "binarytermtypes.h"
00024 #include "glibtojava.h"
00025 #include "libicl_private.h"
00026 
00027 #ifdef _WINDOWS
00028 #include <windows.h>
00029 #include <winsock.h>
00030 #else
00031 #include <sys/types.h>
00032 #include <sys/socket.h>
00033 #include <unistd.h>     /* close        */
00034 #endif
00035 
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038 
00039 struct BinaryTermSenderStruct
00040 {
00041   TermSender* superSender;
00042 }
00043 ;
00044 
00045 typedef struct TermRecordStruct
00046 {
00047   ICLTerm* term;
00048   int numTimesVisited;
00049 }
00050 TermRecord;
00051 
00052 static TermRecord* binaryTermSender_newTermRecord(ICLTerm* term)
00053 {
00054   TermRecord* t = (TermRecord*)malloc(sizeof(TermRecord));
00055   t->numTimesVisited = 0;
00056   t->term = term;
00057   return t;
00058 }
00059 
00060 void binaryTermSender_sendTerm(TermSender* ts, ICLTerm* toSend);
00061 void binaryTermSender_cleanup(TermSender* ts);
00062 
00063 BinaryTermSender* binaryTermSender_create(TermSender* t, gint sendSocket)
00064 {
00065   BinaryTermSender* s = (BinaryTermSender*)malloc(sizeof(BinaryTermSender));
00066   s->superSender = t;
00067   termSender_setSendTermCallback(t, binaryTermSender_sendTerm);
00068   termSender_setCleanupCallback(t, binaryTermSender_cleanup);
00069   termSender_setType(t, BINARYTERMSENDERTYPE);
00070   termSender_setSocket(t, sendSocket);
00071   termSender_setSenderSpecificData(t, s);
00072   return s;
00073 }
00074 
00078 void binaryTermSender_sendTerm(TermSender* ts, ICLTerm* inputTerm)
00079 {
00087   GByteArray* sendBuf = g_byte_array_new();
00088   GQueue* termRecordList = g_queue_new();
00089   TermRecord* currentRecord;
00090   ssize_t sent;
00091 
00092   /*
00093    * Send data in a postfix order.  So, if we had a term like,
00094    * ev_solve(one, [two, three(four, [five])])
00095    * we end up sending something that looks like (after wrapping it
00096    * with term):
00097    * atom length 4 data is 'five'
00098    * list length 1
00099    * atom length 4 data is 'four'
00100    * struct functor with length 5 and named 'three' with two args
00101    * atom length 3 data is 'two'
00102    * list length 2
00103    * atom length 3 data is 'one'
00104    * struct functor with length 8 and named 'ev_solve' with two args
00105    * struct functor with length 4 and named 'term' with 1 arg
00106    */
00107   g_queue_push_tail(termRecordList, binaryTermSender_newTermRecord(inputTerm));
00108   while(!g_queue_is_empty(termRecordList)) {
00109     currentRecord = (TermRecord*)g_queue_pop_tail(termRecordList);
00110     ++currentRecord->numTimesVisited;
00111     if(currentRecord->numTimesVisited == 2) {
00112       if(icl_IsStruct(currentRecord->term)) {
00113         gchar* functor = icl_Functor(currentRecord->term);
00114         sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLSTRUCT);
00115         sendBuf = glibtojava_writeJavaInt(sendBuf, icl_NumTerms(currentRecord->term));
00116         sendBuf = glibtojava_writeJavaInt(sendBuf, strlen(functor));
00117         sendBuf = glibtojava_writeJavaChars(sendBuf, strlen(functor), functor);
00118         free(currentRecord);
00119       }
00120       else if(icl_IsList(currentRecord->term)) {
00121         sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLLIST);
00122         sendBuf = glibtojava_writeJavaInt(sendBuf, icl_NumTerms(currentRecord->term));
00123         free(currentRecord);
00124       }
00125       else if(icl_IsGroup(currentRecord->term)) {
00126         gchar starter;
00127         gchar* sep;
00128         icl_GetGroupChars(currentRecord->term, &starter, &sep);
00129         sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLGROUP);
00130         sendBuf = glibtojava_writeJavaInt(sendBuf, icl_NumTerms(currentRecord->term));
00131         sendBuf = glibtojava_writeJavaChar(sendBuf, starter);
00132         free(currentRecord);
00133       }
00134       else {
00135         fprintf(stderr, "binaryTermSender_sendTerm() Unexpected type visited twice\n");
00136         termSender_setError(ts, TERMSENDER_BINUNKNOWNTYPETWICE);
00137         return;
00138       }
00139       continue;
00140     }
00141     else {
00142       if(icl_IsInt(currentRecord->term)) {
00143         sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLINT);
00144         sendBuf = glibtojava_writeJavaLong(sendBuf, icl_Int(currentRecord->term));
00145         free(currentRecord);
00146       }
00147       else if(icl_IsFloat(currentRecord->term)) {
00148         sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLFLOAT);
00149         sendBuf = glibtojava_writeJavaDouble(sendBuf, icl_Float(currentRecord->term));
00150         free(currentRecord);
00151       }
00152       else if(icl_IsVar(currentRecord->term)) {
00153         gchar* name = icl_Str(currentRecord->term);
00154         sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLVAR);
00155         sendBuf = glibtojava_writeJavaInt(sendBuf, strlen(name));
00156         sendBuf = glibtojava_writeJavaChars(sendBuf, strlen(name), name);
00157         free(currentRecord);
00158       }
00159       else if(icl_IsStr(currentRecord->term)) {
00160         gchar* name = icl_Str(currentRecord->term);
00161         sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLSTR);
00162         sendBuf = glibtojava_writeJavaInt(sendBuf, strlen(name));
00163         sendBuf = glibtojava_writeJavaChars(sendBuf, strlen(name), name);
00164         free(currentRecord);
00165       }
00166       else if(icl_IsDataQ(currentRecord->term)) {
00167         gchar* data = icl_DataQ(currentRecord->term);
00168         sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLDATAQ);
00169         sendBuf = glibtojava_writeJavaInt(sendBuf, currentRecord->term->len);
00170         sendBuf = glibtojava_writeJavaBytes(sendBuf, currentRecord->term->len, (guint8*)data);
00171         //printf("sendBuf (%p) added iclDataQ of length %i, and is now of size %i\n", sendBuf->data, currentRecord->term->len, sendBuf->len);
00172         free(currentRecord);
00173       }
00174       else if(icl_IsStruct(currentRecord->term) ||
00175               icl_IsList(currentRecord->term) ||
00176               icl_IsGroup(currentRecord->term)) {
00177         ICLListType* args = icl_List(currentRecord->term);
00178         g_queue_push_tail(termRecordList, currentRecord);
00179         while(args != NULL) {
00180           if(icl_IsValid(icl_ListElement(args))) {
00181             g_queue_push_tail(termRecordList, binaryTermSender_newTermRecord(icl_ListElement(args)));
00182           }
00183           else {
00184             fprintf(stderr, "binaryTermSender_sendTerm() invalid element to add to queue\n");
00185             termSender_setError(ts, TERMSENDER_BININVALIDELEMENT);
00186             return;
00187           }
00188           args = icl_ListNextElement(args);
00189         }
00190       }
00191       else {
00192         fprintf(stderr, "binaryTermSender_sendTerm() Unexpected type visited once\n");
00193         termSender_setError(ts, TERMSENDER_BINUNKNOWNTYPEONCE);
00194         return;
00195       }
00196     }
00197   }
00198   /*
00199    * Add the 'term' struct which has one argument, which is the single term that came before
00200    */
00201   {
00202     gchar* functor = "term";
00203     sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_ICLSTRUCT);
00204     sendBuf = glibtojava_writeJavaInt(sendBuf, 1);
00205     sendBuf = glibtojava_writeJavaInt(sendBuf, 4);
00206     sendBuf = glibtojava_writeJavaChars(sendBuf, 4, functor);
00207   }
00208   
00209   sendBuf = glibtojava_writeJavaInt(sendBuf, BTT_SENTINEL);
00210 
00211 #ifdef _WINDOWS
00212   if(send(termSender_getSocket(ts), sendBuf->data, sendBuf->len, 0) == SOCKET_ERROR) {
00213     termSender_setError(ts, TERMSENDER_BADSEND);
00214     return;
00215   }
00216 #else
00217   sent = write(termSender_getSocket(ts), sendBuf->data, sendBuf->len);
00218   if((sent < 0) ||
00219      ((sent > 0) && ((size_t)sent != sendBuf->len)))
00220   {
00221     termSender_setError(ts, TERMSENDER_BADSEND);
00222     return;
00223   }
00224   fsync(termSender_getSocket(ts));
00225 #endif
00226 
00227   g_queue_free(termRecordList);
00228   g_byte_array_free(sendBuf, TRUE);
00229 }
00230 
00231 void binaryTermSender_cleanup(TermSender* ts)
00232 {
00233   if(termSender_getSenderSpecificData(ts) != NULL) {
00234     free(termSender_getSenderSpecificData(ts));
00235     termSender_setSenderSpecificData(ts, NULL);
00236   }
00237 }

Generated on Wed May 23 17:20:10 2007 using doxygen 1.5.2