FreeWRL/FreeX3D  3.0.0
EAI_C_Internals.c
1 
2 /****************************************************************************
3  This file is part of the FreeWRL/FreeX3D Distribution.
4 
5  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
6 
7  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
8  it under the terms of the GNU Lesser Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
19 ****************************************************************************/
20 
21 #include "EAI_C.h"
22 #include "config.h"
23 #include "system.h"
24 
25 //#define VERBOSE 1 //JAS
26 #define UNUSED(v) ((void) v)
27 
28 #define WAIT_FOR_RETVAL (command!=SENDEVENT)
29 
30 static pthread_mutex_t eailock = PTHREAD_MUTEX_INITIALIZER;
31 #define EAILOCK pthread_mutex_lock(&eailock);
32 #define EAIUNLOCK pthread_mutex_unlock(&eailock);
33 
34 int _X3D_FreeWRL_FD;
35 int _X3D_FreeWRL_Swig_FD = 0;
36 int _X3D_FreeWRL_listen_FD = 0;
37 int _X3D_queryno = 1;
38 
39 int receivedData= FALSE;
40 /* for waiting on a socket */
41 fd_set rfds;
42 struct timeval tv;
43 struct timeval tv2;
44 
45 void X3D_error(char *msg) {
46  perror(msg);
47  exit(0);
48 }
49 
50 double mytime;
51 
52 //char readbuffer[2048];
53 char *sendBuffer = NULL;
54 int sendBufferSize = 0;
55 
56 /* handle a callback - this should get a line like:
57  EV
58 1170697988.125835
59 31
60 0.877656
61 EV_EOT
62 */
63 
64 /* make a buffer large enough to hold our data */
65 void verifySendBufferSize (int len) {
66  if (len < (sendBufferSize-50)) return;
67 
68  /* make it large enough to contain string, plus some more, as we usually throw some stuff on the beginning. */
69  while (len>(sendBufferSize-200)) sendBufferSize+=1024;
70  sendBuffer = realloc(sendBuffer,sendBufferSize);
71 }
72 
73 /* count the number of numbers on a line - useful for MFNode return value mallocs */
74 int _X3D_countWords(char *ptr) {
75  int ct;
76 
77  ct = 0;
78 
79  while (*ptr >= ' ') {
80  SKIP_CONTROLCHARS
81  SKIP_IF_GT_SPACE
82  ct ++;
83  }
84  return ct;
85 }
86 #ifdef SWIG
87 void *freewrlSwigThread(void* nada) {
88 
89  const int on=1;
90  /* unused int flags; */
91  int len;
92 
93  struct sockaddr_in servaddr, cliaddr;
94 #ifdef WIN32
95  int iResult;
96  WSADATA wsaData;
97 
98  iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
99  if (iResult != 0) {
100  X3D_error("WSAStartup failed to load winsock2 ws2_32.dll\n");
101  /* return NULL; */
102  return ;
103  }
104 #endif
105 
106  if ((_X3D_FreeWRL_listen_FD= socket(AF_INET, SOCK_STREAM, 0)) < 0) {
107  X3D_error("ERROR opening swig socket");
108  /* return NULL; */
109  return ;
110 
111  }
112 
113  setsockopt(_X3D_FreeWRL_listen_FD, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
114 
115  bzero(&servaddr, sizeof(servaddr));
116  servaddr.sin_family = AF_INET;
117  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
118  servaddr.sin_port = htons(EAIBASESOCKET+ 500);
119 
120  if (bind((_X3D_FreeWRL_listen_FD), (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
121  X3D_error("ERROR in bind");
122  }
123 
124  if (listen(_X3D_FreeWRL_listen_FD, 1024) < 0) {
125  X3D_error("ERROR in listen");
126  /* return NULL; */
127  return ;
128  }
129 
130  len = sizeof(cliaddr);
131 
132 #ifdef WIN32
133  _X3D_FreeWRL_Swig_FD = accept((_X3D_FreeWRL_listen_FD), (struct sockaddr*) &cliaddr, &len);
134 #else
135  _X3D_FreeWRL_Swig_FD = accept((_X3D_FreeWRL_listen_FD), (struct sockaddr*) &cliaddr, (socklen_t *) &len);
136 #endif
137  /* return NULL; */
138  return ;
139 }
140 #endif //SWIG
141 #include <list.h>
142 static s_list_t *evlist = NULL;
143 static s_list_t *relist = NULL;
144 
145 pthread_mutex_t mut_relist = PTHREAD_MUTEX_INITIALIZER;
146 pthread_mutex_t mut_evlist = PTHREAD_MUTEX_INITIALIZER;
147 pthread_mutex_t mut_re = PTHREAD_MUTEX_INITIALIZER;
148 
149 pthread_cond_t condition_relist_nonempty = PTHREAD_COND_INITIALIZER;
150 pthread_cond_t condition_evlist_nonempty = PTHREAD_COND_INITIALIZER;
151 pthread_cond_t condition_re_done = PTHREAD_COND_INITIALIZER;
152 
153 
154 s_list_t* _enqueue_readbuffer(s_list_t *list, char *readbuffer){
155  s_list_t* item;
156  char *cbline = strdup(readbuffer);
157  item = ml_new(cbline);
158  list = ml_append(list, item);
159  return list;
160 }
161 void _enqueue_readbuffer_re(char *readbuffer)
162 {
163  pthread_mutex_lock (&mut_relist);
164  relist = _enqueue_readbuffer(relist,readbuffer);
165  pthread_cond_signal(&condition_relist_nonempty);
166  pthread_mutex_unlock (&mut_relist);
167 }
168 void _enqueue_readbuffer_ev(char *readbuffer)
169 {
170  pthread_mutex_lock (&mut_evlist);
171  evlist = _enqueue_readbuffer(evlist,readbuffer);
172  pthread_cond_signal(&condition_evlist_nonempty);
173  pthread_mutex_unlock (&mut_evlist);
174 }
175 char* dequeue_readbuffer(s_list_t **plist)
176 {
177  s_list_t *list = *plist;
178  if(list){
179  char *readbuffer = ml_elem(list);
180  *plist = ml_delete_self(list, list);
181  return readbuffer;
182  }else
183  return NULL;
184 }
185 int waiting_for_RE = 0;
186 char *dequeue_readbuffer_wait_re()
187 {
188  char *readbuffer;
189  pthread_mutex_lock (&mut_re); //hold up ev work
190  waiting_for_RE = 1; //set flag for holding up ev
191 
192  pthread_mutex_lock (&mut_relist);
193  if(relist == NULL)
194  pthread_cond_wait(&condition_relist_nonempty, &mut_relist);
195  readbuffer = dequeue_readbuffer(&relist);
196  pthread_mutex_unlock (&mut_relist);
197 
198  waiting_for_RE = 0;
199  pthread_cond_signal(&condition_re_done); //signal ev OK
200  pthread_mutex_unlock (&mut_re); //release ev work
201  return readbuffer;
202 }
203 char* dequeue_readbuffer_ev(int wait)
204 {
205  char *readbuffer;
206  pthread_mutex_lock (&mut_evlist);
207  if(evlist == NULL){
208  if(!wait){
209  pthread_mutex_unlock (&mut_evlist);
210  return NULL;
211  }
212  pthread_cond_wait(&condition_evlist_nonempty, &mut_evlist);
213  }
214  readbuffer = dequeue_readbuffer(&evlist);
215  pthread_mutex_unlock (&mut_evlist);
216  return readbuffer;
217 }
218 /* Dave says:
219  "If you get an EV while still waiting for any REs you should not
220  handle the EV until the RE queue is empty and you are not expecting
221  any REs."
222  In sendToFreewrl we send, then immediately set waiting_for_RE if/while
223  we are waiting, and here we skip/return if that's the case.
224 */
225 void dequeue_callback_ev(int wait)
226 {
227  char* cbline;
228  if(!wait)
229  {
230  if(waiting_for_RE) return;
231  cbline = dequeue_readbuffer_ev(wait);
232  if(cbline){
233  _handleFreeWRLcallback (cbline) ;
234  free(cbline);
235  }
236  }else if(wait) {
237  cbline = dequeue_readbuffer_ev(wait);
238  if(cbline){
239  pthread_mutex_lock (&mut_re);
240  if(waiting_for_RE)
241  pthread_cond_wait(&condition_re_done, &mut_re);
242  pthread_mutex_unlock (&mut_re);
243  _handleFreeWRLcallback (cbline) ;
244  free(cbline);
245  }
246  }
247 }
248 /* you'd start this thread if you have no main.c to call dequeue_callback_ev() from,
249  such as SAI in javascript.
250 */
251 void *freewrlEVcallbackThread(void* nada) {
252  while(1){
253  dequeue_callback_ev(1);
254  }
255  return nada;
256 }
257 
258 /* read in the reply - if it is an RE; it is the reply to an event; if it is an
259  EV it is an async event */
260 void *freewrlReadThread(void* nada) {
261  int retval;
262  char readbuffer[2048];
263  //initialize_queue_mutexes();
264  while (1==1) {
265 
266 
267  tv.tv_sec = 0;
268  tv.tv_usec = 100;
269  FD_ZERO(&rfds);
270  FD_SET(_X3D_FreeWRL_FD, &rfds);
271 
272  /* wait for the socket. We HAVE to select on "sock+1" - RTFM */
273  /* WIN32 ignors the first select parameter, just there for berkley compatibility */
274  // retval = select(_X3D_FreeWRL_FD+1, &rfds, NULL, NULL, &tv); //times out
275  retval = select(_X3D_FreeWRL_FD+1, &rfds, NULL, NULL, NULL); //blocking
276 
277 #ifdef VERBOSE
278  if(retval)printf("+");
279  else printf("-");
280 #endif
281 
282  if (retval) {
283 #ifdef WIN32
284  retval = recv(_X3D_FreeWRL_FD, readbuffer, 2048, 0);
285  if (retval == SOCKET_ERROR) {
286 #else
287  retval = read(_X3D_FreeWRL_FD,readbuffer,2048);
288  if (retval <= 0) {
289 #endif
290  printf("ERROR reading fromsocket\n");
291  exit(1);
292  }
293  readbuffer[retval] = '\0';
294 
295  /* if this is normal data - signal that it is received */
296  if (strncmp ("RE",readbuffer,2) == 0) {
297  if(0)
298  receivedData = TRUE;
299  if(1)
300  _enqueue_readbuffer_re(readbuffer);
301  } else if (strncmp ("EV",readbuffer,2) == 0) {
302  if(0)
303  _handleFreeWRLcallback(readbuffer);
304  if(1)
305  _enqueue_readbuffer_ev(readbuffer);
306  } else if (strncmp ("QUIT",readbuffer,4) == 0) {
307  exit(0);
308  } else {
309  printf ("readThread - unknown prefix - %s\n",readbuffer);
310  }
311 
312  }
313 
314  }
315  return nada;
316 }
317 
318 /* threading - we thread only to read from a different thread. This
319 allows events and so on to go quickly - no return value required. */
320 char readbuffer[2048];
321 
322 static char *sendToFreeWRL(char *callerbuffer, int size, int waitForResponse) {
323  int retval;
324  int readquery;
325  char *ptr;
326 
327  #ifdef VERBOSE
328  printf ("sendToFreeWRL - sending :%s:\n",callerbuffer);
329  #endif
330 
331 #ifdef WIN32
332  ptr = NULL;
333  receivedData = FALSE;
334  retval = send(_X3D_FreeWRL_FD, callerbuffer, size, 0);
335  if (retval == SOCKET_ERROR )
336 #else
337  ptr = NULL;
338  retval = write(_X3D_FreeWRL_FD, callerbuffer, size);
339  #ifdef VERBOSE
340  printf ("sendToFreeWRL, sent callbuffer %s of size %d, retval %d\n",callerbuffer,size,retval);
341  #endif
342 
343  if (retval < 0)
344 #endif
345  X3D_error("ERROR writing to socket");
346 
347  if (waitForResponse) {
348 
349  //receivedData = FALSE;
350  if(0)
351  while (!receivedData) {
352  sched_yield();
353  }
354  if(1){
355  char *rb;
356  //sched_yield();
357  rb = dequeue_readbuffer_wait_re();
358  strcpy(readbuffer,rb);
359  free(rb);
360  }
361 
362 
363  /* have the response here now. */
364 
365  #ifdef VERBOSE
366  printf("Client got: %s\n",readbuffer);
367  #endif
368 
369  /* should return something like: RE
370 1165347857.925786
371 1
372 0.000000
373 RE_EOT
374 */
375  /* see if it is a reply, or an event return */
376 
377 
378  ptr = readbuffer;
379  while ((*ptr != '\0') && (*ptr <= ' ')) ptr++;
380 
381  #ifdef VERBOSE
382  printf ("found a reply\n");
383  #endif
384 
385  SKIP_IF_GT_SPACE
386  SKIP_CONTROLCHARS
387  if (sscanf(ptr,"%lf",&mytime) != 1) {
388  printf ("huh, expected the time, got %s\n",ptr);
389  exit(1);
390  }
391  #ifdef VERBOSE
392  printf ("time of command is %lf\n",mytime);
393  #endif
394 
395  SKIP_IF_GT_SPACE
396  SKIP_CONTROLCHARS
397 
398  #ifdef VERBOSE
399  printf ("this should be the query number: %s\n",ptr);
400  #endif
401 
402  if (sscanf(ptr,"%d",&readquery) != 1) {
403  printf ("huh, expected the time, got %s\n",ptr);
404  exit(1);
405  }
406  #ifdef VERBOSE
407  printf ("query returned is %d\n",readquery);
408  #endif
409 
410  if (_X3D_queryno != readquery) {
411  printf ("server: warning, _X3D_queryno %d != received %d\n",_X3D_queryno,readquery);
412  usleep(5000);
413  sched_yield();
414  }
415 
416  SKIP_IF_GT_SPACE
417  SKIP_CONTROLCHARS
418 
419 
420  strncpy(callerbuffer,readbuffer,retval);
421 
422  }
423  _X3D_queryno ++;
424  #ifdef VERBOSE
425  printf ("sendToFreeWRL, returning %p\n",ptr);
426  #endif
427 
428 
429  return ptr;
430 }
431 
432 void _X3D_sendEvent (char command, char *string,int line) {
433  char *myptr;
434  UNUSED (myptr); // mitigate compiler warnings
435  EAILOCK
436  verifySendBufferSize (strlen(string));
437  //JAS printf ("_X3D_sendEvent, sending string %s, called from line %d\n",string,line);
438 
439  sprintf (sendBuffer, "%d %c %s\n",_X3D_queryno,command,string);
440  myptr = sendToFreeWRL(sendBuffer, strlen(sendBuffer),WAIT_FOR_RETVAL);
441  EAIUNLOCK
442  //JAS printf ("_X3D_sendEvent, sent, returning...\n");
443 }
444 
445 char *_X3D_makeShortCommand (char command) {
446  char *myptr;
447 
448  EAILOCK
449  verifySendBufferSize (100);
450  sprintf (sendBuffer, "%d %c\n",_X3D_queryno,command);
451  myptr = sendToFreeWRL(sendBuffer, strlen(sendBuffer),WAIT_FOR_RETVAL);
452  EAIUNLOCK
453  #ifdef VERBOSE
454  printf ("makeShortCommand, buffer now %s\n",myptr);
455  #endif
456  return myptr;
457 }
458 
459 char *_X3D_make1VoidCommand (char command, int adr) {
460  char *myptr;
461 
462  EAILOCK
463  verifySendBufferSize (100);
464  sprintf (sendBuffer, "%d %c %d\n",_X3D_queryno,command,adr);
465  myptr = sendToFreeWRL(sendBuffer, strlen(sendBuffer),WAIT_FOR_RETVAL);
466  EAIUNLOCK
467  #ifdef VERBOSE
468  printf ("make1VoidCommand, buffer now %s\n",myptr);
469  #endif
470  return myptr;
471 }
472 
473 char *_X3D_make1StringCommand (char command, char *name) {
474  char *myptr;
475 
476  #ifdef VERBOSE
477  printf ("start _X3D_make1StringCommand, command %c char %s\n",command,name);
478  #endif
479 
480  EAILOCK
481  verifySendBufferSize (strlen(name));
482  sprintf (sendBuffer, "%d %c %s\n",_X3D_queryno,command,name);
483  myptr = sendToFreeWRL(sendBuffer, strlen(sendBuffer),WAIT_FOR_RETVAL);
484  EAIUNLOCK
485 
486  #ifdef VERBOSE
487  printf ("make1StringCommand, buffer now %s\n",myptr);
488  #endif
489 
490  return myptr;
491 }
492 
493 
494 char *_X3D_make2StringCommand (char command, char *str1, char *str2) {
495  char *myptr;
496  char sendBuffer[2048];
497 
498  EAILOCK
499  verifySendBufferSize ( strlen(str1) + strlen(str2));
500  sprintf (sendBuffer, "%d %c %s%s\n",_X3D_queryno,command,str1,str2);
501  myptr = sendToFreeWRL(sendBuffer, strlen(sendBuffer),WAIT_FOR_RETVAL);
502  EAIUNLOCK
503 
504  #ifdef VERBOSE
505  printf ("make2StringCommand, buffer now %s\n",myptr);
506  #endif
507  return myptr;
508 }
509 
510 
511 char *_X3D_Browser_SendEventType(int adr,char *name, char *evtype) {
512  char *myptr;
513 
514  EAILOCK
515  verifySendBufferSize (100);
516  sprintf (sendBuffer, "%d %c %d %s %s\n",_X3D_queryno, GETFIELDTYPE, adr, name, evtype);
517 
518  myptr = sendToFreeWRL(sendBuffer, strlen(sendBuffer),TRUE);
519  EAIUNLOCK
520  #ifdef VERBOSE
521  printf ("_X3D_Browser_SendEventType, buffer now %s\n",myptr);
522  #endif
523  return myptr;
524 }
525 
526 char * _RegisterListener (X3DEventOut *node, int adin) {
527  char *myptr;
528 
529 
530  verifySendBufferSize (100);
531  #ifdef VERBOSE
532  printf ("in RegisterListener, we have query %d advise index %d nodeptr %d offset %d datatype %d datasize %d field %s\n",
533  _X3D_queryno,
534  adin, node->nodeptr, node->offset, node->datatype, node->datasize, node->field);
535  #endif
536 
537 /*
538  EAIoutSender.send ("" + queryno + "G " + nodeptr + " " + offset + " " + datatype +
539  " " + datasize + "\n");
540 */
541  EAILOCK
542  sprintf (sendBuffer, "%u %c %d %d %c %d\n",
543  _X3D_queryno,
544  REGLISTENER,
545  node->nodeptr,
546  node->offset,
547  mapFieldTypeToEAItype(node->datatype),
548  node->datasize);
549 
550  myptr = sendToFreeWRL(sendBuffer, strlen(sendBuffer),TRUE);
551  EAIUNLOCK
552  #ifdef VERBOSE
553  printf ("_X3D_Browser_SendEventType, buffer now %s\n",myptr);
554  #endif
555  return myptr;
556 }
557 
Definition: list.h:37