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
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
00099 void *VMDCollab::serverproc(void *serversock) {
00100 ResizeArray<void *>clients;
00101 char buf[VMDCOLLAB_MSGSIZE];
00102 int i, j;
00103
00104 while (1) {
00105
00106
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
00120
00121
00122
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
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 }
00142 }
00143 }
00144 vmd_msleep(10);
00145 }
00146
00147
00148
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,
00183 serversock
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
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
00218 return TRUE;
00219 }
00220
00221 vmd_sleep(1);
00222 }
00223
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
00275 vmd_msleep(1);
00276 return TRUE;
00277 }
00278