Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

VMDCollab.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: VMDCollab.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.11 $      $Date: 2019/01/17 21:21:02 $
00015  *
00016  ***************************************************************************/
00017 
00018 #include "VMDCollab.h"
00019 #include "WKFThreads.h"
00020 #include "vmdsock.h"
00021 #include "Inform.h"
00022 #include "utilities.h"
00023 #include "TextEvent.h"
00024 
00025 #if defined(VMDTKCON)
00026 #include "vmdconsole.h"
00027 #endif
00028 
00029 #include <limits.h>
00030 #include <errno.h>
00031 
00032 // collab messages will be the following number of bytes
00033 static const int VMDCOLLAB_MSGSIZE = 256;
00034 
00035 
00036 #if ( INT_MAX == 2147483647 )
00037 typedef int     int32;
00038 #else
00039 typedef short   int32;
00040 #endif
00041 
00042 static int32 imd_readn(void *s, char *ptr, int32 n) {
00043   int32 nleft;
00044   int32 nread;
00045  
00046   nleft = n;
00047   while (nleft > 0) {
00048     if ((nread = vmdsock_read(s, ptr, nleft)) < 0) {
00049       if (errno == EINTR)
00050         nread = 0;         /* and call read() again */
00051       else
00052         return -1;
00053     } else if (nread == 0)
00054       break;               /* EOF */
00055     nleft -= nread;
00056     ptr += nread;
00057   }
00058   return n-nleft;
00059 }
00060 
00061 
00062 static int32 imd_writen(void *s, const char *ptr, int32 n) {
00063   int32 nleft;
00064   int32 nwritten;
00065 
00066   nleft = n;
00067   while (nleft > 0) {
00068     if ((nwritten = vmdsock_write(s, ptr, nleft)) <= 0) {
00069       if (errno == EINTR)
00070         nwritten = 0;
00071       else
00072         return -1;
00073     }
00074     nleft -= nwritten;
00075     ptr += nwritten; }
00076   return n;
00077 }
00078 
00079 VMDCollab::VMDCollab(VMDApp *app) : UIObject(app) {
00080   clientsock = NULL;
00081   serversock = NULL;
00082   eval_in_progress = FALSE;
00083 #if defined(VMDTKCON)
00084   cmdbufstr = new Inform("",VMDCON_ALWAYS);
00085 #else
00086   cmdbufstr = new Inform("");
00087 #endif
00088   for (int i=0; i<Command::TOTAL; i++) command_wanted(i);
00089 }
00090 
00091 
00092 VMDCollab::~VMDCollab() {
00093   stopserver();
00094   delete cmdbufstr;
00095 }
00096 
00097 
00098 // this is a static method that will be created in a new child thread
00099 void *VMDCollab::serverproc(void *serversock) {
00100   ResizeArray<void *>clients;
00101   char buf[VMDCOLLAB_MSGSIZE];
00102   int i, j;
00103   
00104   while (1) {
00105     // if we have no clients, hang until someone connects
00106     // otherwise, just check for pending connections
00107     if (vmdsock_selread(serversock, 0) > 0) {
00108       msgInfo << "serversock became readable" << sendmsg;
00109       void *clientsock = vmdsock_accept(serversock);
00110       if (clientsock) {
00111         msgInfo << "VMDCollab accepting connection" << sendmsg;
00112         clients.append(clientsock);
00113       }
00114     } else if (vmdsock_selwrite(serversock, 0)) {
00115       msgInfo << "serversock became writable; exiting..." << sendmsg;
00116       break;
00117     }
00118 
00119     // Loop through one socket at a time.  If incoming data is found,
00120     // drain it before moving on, on the assumption that we only want
00121     // commands from one VMD at a time to be propagated to the other
00122     // clients.
00123     for (i=0; i<clients.num(); i++) {
00124       void *client = clients[i];
00125       while (vmdsock_selread(client, 0) > 0) {
00126         memset(buf, 0, VMDCOLLAB_MSGSIZE);
00127         if (imd_readn(client, buf, VMDCOLLAB_MSGSIZE) != VMDCOLLAB_MSGSIZE) {
00128           msgInfo << "client sent incomplete message, shutting it down"
00129                   << sendmsg;
00130           vmdsock_shutdown(client);
00131           vmdsock_destroy(client);
00132           clients.remove(clients.find(client));
00133           break;
00134         }
00135         // send to all other clients
00136         for (j=0; j<clients.num(); j++) {
00137           void *dest = clients[j];
00138           if (dest != client) {
00139             imd_writen(clients[j], buf, VMDCOLLAB_MSGSIZE);
00140           }
00141         } // loop over clients other than sender
00142       } // while client is readable
00143     } // loop over clients
00144     vmd_msleep(10);
00145   }
00146 
00147   // if here, then the serversock got shut down, indicating that it's
00148   // time to die.
00149   msgInfo << "VMDCollab shutting down server" << sendmsg;
00150   for (i=0; i<clients.num(); i++) {
00151     void *client = clients[i];
00152     strcpy(buf, "exit");
00153     imd_writen(client, buf, VMDCOLLAB_MSGSIZE);
00154     vmdsock_shutdown(client);
00155     vmdsock_destroy(client);
00156   }
00157   vmdsock_destroy(serversock);
00158   return NULL;
00159 }
00160 
00161 
00162 int VMDCollab::startserver(int port) {
00163   if (serversock) {
00164     msgErr << "Already running a server on port " <<  port << sendmsg;
00165     return FALSE;
00166   }
00167   serversock = vmdsock_create();
00168   if (!serversock) {
00169     msgErr << "Could not create socket." << sendmsg;
00170     return FALSE;
00171   }
00172   if (vmdsock_bind(serversock, port)) {
00173     msgErr << "Could not bind vmdcollab server to port " << port 
00174            << sendmsg;
00175     vmdsock_destroy(serversock);
00176     return FALSE;
00177   }
00178   vmdsock_listen(serversock);
00179 
00180   wkf_thread_t serverthread;
00181   if (wkf_thread_create(&serverthread,
00182                         serverproc,    // my thread routine
00183                         serversock     // context for thread
00184   )) {
00185     msgErr << "VMDCollab: unable to create server thread" << sendmsg;
00186   } else {
00187     msgInfo << "Starting VMDCollab bounce server." << sendmsg;
00188   }
00189 
00190   return TRUE;
00191 }
00192 
00193 
00194 void VMDCollab::stopserver() {
00195   if (!serversock) return;
00196   vmdsock_shutdown(serversock);
00197   // don't destroy; let the server thread do that
00198   serversock = NULL;
00199 }
00200 
00201 
00202 int VMDCollab::connect(const char *host, int port) {
00203   if (clientsock) {
00204     msgErr << "Already connected to another vmdcollab server" << sendmsg;
00205     return FALSE;
00206   }
00207   if (!(clientsock = vmdsock_create())) {
00208     msgErr << "Could not create socket." << sendmsg;
00209     return FALSE;
00210   }
00211   int numTries = 3;
00212   for (int i=0; i<numTries; i++) {
00213     if (vmdsock_connect(clientsock, host, port)) {
00214       msgErr << "Could not connect to vmdcollab server at " << host << ":" << port << sendmsg;
00215       msgErr << "Error: " << strerror(errno) << sendmsg;
00216     } else {
00217       // success
00218       return TRUE;
00219     }
00220     // sleep for a second; maybe the server just hasn't started yet
00221     vmd_sleep(1);
00222   }
00223   // failed
00224   msgErr << "VMDCollab giving up after " << numTries << " seconds." << sendmsg;
00225   vmdsock_destroy(clientsock);
00226   clientsock = NULL;
00227   return FALSE;
00228 }
00229 
00230 
00231 void VMDCollab::disconnect() {
00232   if (!clientsock) return;
00233   vmdsock_shutdown(clientsock);
00234   vmdsock_destroy(clientsock);
00235   clientsock = NULL;
00236 }
00237 
00238 
00239 int VMDCollab::check_event() {
00240   if (!clientsock) return FALSE;
00241   eval_in_progress = TRUE;
00242   char buf[VMDCOLLAB_MSGSIZE];
00243   while (vmdsock_selread(clientsock, 0) > 0) {
00244     if (imd_readn(clientsock, buf, VMDCOLLAB_MSGSIZE) != VMDCOLLAB_MSGSIZE) {
00245       vmdsock_shutdown(clientsock);
00246       vmdsock_destroy(clientsock);
00247       clientsock = NULL;
00248       break;
00249     }
00250     runcommand(new TclEvalEvent(buf));
00251   }
00252   eval_in_progress = FALSE;
00253   return TRUE;
00254 }
00255 
00256 
00257 int VMDCollab::act_on_command(int, Command *cmd) {
00258   if (!clientsock) return FALSE;
00259   if (eval_in_progress) return FALSE;
00260   if (!cmd->has_text(cmdbufstr)) return TRUE;
00261 
00262   const char *txtcmd = cmdbufstr->text();
00263   int len = strlen(txtcmd);
00264   if (len >= VMDCOLLAB_MSGSIZE) {
00265     msgWarn << "VMDCollab: command too long: " << txtcmd << sendmsg;
00266     return FALSE;
00267   }
00268 
00269   char buf[VMDCOLLAB_MSGSIZE];
00270   strcpy(buf, txtcmd);
00271   cmdbufstr->reset();
00272 
00273   imd_writen(clientsock, buf, VMDCOLLAB_MSGSIZE);
00274   // give the server thread a chance to propagate events before continuing
00275   vmd_msleep(1);
00276   return TRUE;
00277 }
00278 

Generated on Fri Nov 8 02:45:44 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002