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

VMDCollab.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2011 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.8 $      $Date: 2010/12/16 04:08:45 $
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 static int32 imd_writen(void *s, const char *ptr, int32 n) {
00062   int32 nleft;
00063   int32 nwritten;
00064 
00065   nleft = n;
00066   while (nleft > 0) {
00067     if ((nwritten = vmdsock_write(s, ptr, nleft)) <= 0) {
00068       if (errno == EINTR)
00069         nwritten = 0;
00070       else
00071         return -1;
00072     }
00073     nleft -= nwritten;
00074     ptr += nwritten; }
00075   return n;
00076 }
00077 
00078 VMDCollab::VMDCollab(VMDApp *app)
00079 : 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 VMDCollab::~VMDCollab() {
00092   stopserver();
00093   delete cmdbufstr;
00094 }
00095 
00096 void *VMDCollab::serverproc(void *serversock) {
00097 
00098   ResizeArray<void *>clients;
00099   char buf[VMDCOLLAB_MSGSIZE];
00100   int i, j;
00101   
00102   while (1) {
00103     // if we have no clients, hang until someone connects
00104     // otherwise, just check for pending connections
00105     if (vmdsock_selread(serversock, 0) > 0) {
00106       msgInfo << "serversock became readable" << sendmsg;
00107       void *clientsock = vmdsock_accept(serversock);
00108       if (clientsock) {
00109         msgInfo << "VMDCollab accepting connection" << sendmsg;
00110         clients.append(clientsock);
00111       }
00112     } else if (vmdsock_selwrite(serversock, 0)) {
00113       msgInfo << "serversock became writable; exiting..." << sendmsg;
00114       break;
00115     }
00116 
00117     // Loop through one socket at a time.  If incoming data is found,
00118     // drain it before moving on, on the assumption that we only want
00119     // commands from one VMD at a time to be propagated to the other
00120     // clients.
00121     for (i=0; i<clients.num(); i++) {
00122       void *client = clients[i];
00123       while (vmdsock_selread(client, 0) > 0) {
00124         memset(buf, 0, VMDCOLLAB_MSGSIZE);
00125         if (imd_readn(client, buf, VMDCOLLAB_MSGSIZE) != VMDCOLLAB_MSGSIZE) {
00126           msgInfo << "client sent incomplete message, shutting it down"
00127                   << sendmsg;
00128           vmdsock_shutdown(client);
00129           vmdsock_destroy(client);
00130           clients.remove(clients.find(client));
00131           break;
00132         }
00133         // send to all other clients
00134         for (j=0; j<clients.num(); j++) {
00135           void *dest = clients[j];
00136           if (dest != client) {
00137             imd_writen(clients[j], buf, VMDCOLLAB_MSGSIZE);
00138           }
00139         } // loop over clients other than sender
00140       } // while client is readable
00141     } // loop over clients
00142     vmd_msleep(10);
00143   }
00144   // if here, then the serversock got shut down, indicating that it's
00145   // time to die.
00146   msgInfo << "VMDCollab shutting down server" << sendmsg;
00147   for (i=0; i<clients.num(); i++) {
00148     void *client = clients[i];
00149     strcpy(buf, "exit");
00150     imd_writen(client, buf, VMDCOLLAB_MSGSIZE);
00151     vmdsock_shutdown(client);
00152     vmdsock_destroy(client);
00153   }
00154   vmdsock_destroy(serversock);
00155   return NULL;
00156 }
00157 
00158 int VMDCollab::startserver(int port) {
00159   if (serversock) {
00160     msgErr << "Already running a server on port " <<  port << sendmsg;
00161     return FALSE;
00162   }
00163   void *serversock = vmdsock_create();
00164   if (!serversock) {
00165     msgErr << "Could not create socket." << sendmsg;
00166     return FALSE;
00167   }
00168   if (vmdsock_bind(serversock, port)) {
00169     msgErr << "Could not bind vmdcollab server to port " << port 
00170            << sendmsg;
00171     vmdsock_destroy(serversock);
00172     return FALSE;
00173   }
00174   vmdsock_listen(serversock);
00175 
00176   wkf_thread_t serverthread;
00177   if (wkf_thread_create(&serverthread,
00178                         serverproc,    // my thread routine
00179                         serversock     // context for thread
00180   )) {
00181     msgErr << "VMDCollab: unable to create server thread" << sendmsg;
00182   } else {
00183     msgInfo << "Starting VMDCollab bounce server." << sendmsg;
00184   }
00185   return TRUE;
00186 }
00187 
00188 void VMDCollab::stopserver() {
00189   if (!serversock) return;
00190   vmdsock_shutdown(serversock);
00191   // don't destroy; let the server thread do that
00192   serversock = NULL;
00193 }
00194 
00195 int VMDCollab::connect(const char *host, int port) {
00196   if (clientsock) {
00197     msgErr << "Already connected to another vmdcollab server" << sendmsg;
00198     return FALSE;
00199   }
00200   if (!(clientsock = vmdsock_create())) {
00201     msgErr << "Could not create socket." << sendmsg;
00202     return FALSE;
00203   }
00204   int numTries = 3;
00205   for (int i=0; i<numTries; i++) {
00206     if (vmdsock_connect(clientsock, host, port)) {
00207       msgErr << "Could not connect to vmdcollab server at " << host << ":" << port << sendmsg;
00208       msgErr << "Error: " << strerror(errno) << sendmsg;
00209     } else {
00210       // success
00211       return TRUE;
00212     }
00213     // sleep for a second; maybe the server just hasn't started yet
00214     vmd_sleep(1);
00215   }
00216   // failed
00217   msgErr << "VMDCollab giving up after " << numTries << " seconds." << sendmsg;
00218   vmdsock_destroy(clientsock);
00219   clientsock = NULL;
00220   return FALSE;
00221 }
00222 
00223 void VMDCollab::disconnect() {
00224   if (!clientsock) return;
00225   vmdsock_shutdown(clientsock);
00226   vmdsock_destroy(clientsock);
00227   clientsock = NULL;
00228 }
00229 
00230 int VMDCollab::check_event() {
00231   if (!clientsock) return FALSE;
00232   eval_in_progress = TRUE;
00233   char buf[VMDCOLLAB_MSGSIZE];
00234   while (vmdsock_selread(clientsock, 0) > 0) {
00235     if (imd_readn(clientsock, buf, VMDCOLLAB_MSGSIZE) != VMDCOLLAB_MSGSIZE) {
00236       vmdsock_shutdown(clientsock);
00237       vmdsock_destroy(clientsock);
00238       clientsock = NULL;
00239       break;
00240     }
00241     runcommand(new TclEvalEvent(buf));
00242   }
00243   eval_in_progress = FALSE;
00244   return TRUE;
00245 }
00246 
00247 int VMDCollab::act_on_command(int, Command *cmd) {
00248   if (!clientsock) return FALSE;
00249   if (eval_in_progress) return FALSE;
00250   if (!cmd->has_text(cmdbufstr)) return TRUE;
00251 
00252   const char *txtcmd = cmdbufstr->text();
00253   int len = strlen(txtcmd);
00254   if (len >= VMDCOLLAB_MSGSIZE) {
00255     msgWarn << "VMDCollab: command too long: " << txtcmd << sendmsg;
00256     return FALSE;
00257   }
00258 
00259   char buf[VMDCOLLAB_MSGSIZE];
00260   strcpy(buf, txtcmd);
00261   cmdbufstr->reset();
00262 
00263   imd_writen(clientsock, buf, VMDCOLLAB_MSGSIZE);
00264   // give the server thread a chance to propagate events before continuing
00265   vmd_msleep(1);
00266   return TRUE;
00267 }
00268 

Generated on Wed May 23 01:50:31 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002