00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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;
00051 else
00052 return -1;
00053 } else if (nread == 0)
00054 break;
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
00104
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
00118
00119
00120
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
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 }
00140 }
00141 }
00142 vmd_msleep(10);
00143 }
00144
00145
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,
00179 serversock
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
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
00211 return TRUE;
00212 }
00213
00214 vmd_sleep(1);
00215 }
00216
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
00265 vmd_msleep(1);
00266 return TRUE;
00267 }
00268