source: trunk/packages/vizservers/pymolproxy/pymolproxy.c @ 1161

Last change on this file since 1161 was 1161, checked in by gah, 16 years ago

added stats counters

File size: 38.0 KB
Line 
1
2/*
3 * ----------------------------------------------------------------------
4 * proxypymol.c
5 *
6 *      This module creates the Tcl interface to the pymol server.  It acts as
7 *      a go-between establishing communication between a molvisviewer widget
8 *      and the pymol server. The communication protocol from the molvisviewer
9 *      widget is the Tcl language.  Commands are then relayed to the pymol
10 *      server.  Responses from the pymol server are translated into Tcl
11 *      commands * and send to the molvisviewer widget. For example, resulting
12 *      image rendered offscreen is returned as BMP-formatted image data.
13 *
14 *  Copyright (c) 2004-2006  Purdue Research Foundation
15 *
16 *  See the file "license.terms" for information on usage and
17 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 * ======================================================================
19 */
20
21#include <stdio.h>
22#include <time.h>
23#include <assert.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <string.h>
27#include <signal.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/wait.h>
31#include <sys/select.h>
32#include <poll.h>
33#include <sys/time.h>
34#include <sys/times.h>
35#include <fcntl.h>
36#include <netinet/in.h>
37#include <getopt.h>
38#include <errno.h>
39#include <sys/ioctl.h>
40#include <net/if.h>
41#include <tcl.h>
42
43#undef INLINE
44#ifdef __GNUC__
45#  define INLINE __inline__
46#else
47#  define INLINE
48#endif
49
50#define FALSE 0
51#define TRUE  1
52
53#define IO_TIMEOUT (30000)
54#define STATSFILE       "/var/tmp/visservers/data.xml"
55#define KEEPSTATS       1
56#define CVT2SECS(x)  ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6)
57
58typedef struct {
59    pid_t child;                /* Child process. */
60    size_t nFrames;             /* # of frames sent to client. */
61    size_t nBytes;              /* # of bytes for all frames. */
62    size_t nCommands;           /* # of commands executed */
63    double cmdTime;             /* Elasped time spend executing commands. */
64    struct timeval start;       /* Start of elapsed time. */
65} Stats;
66
67static Stats stats;
68
69static FILE *flog;
70static int debug = 1;
71
72
73typedef struct {
74    char *data;
75    int   used;
76    int   allocated;
77} DyBuffer;
78
79typedef struct {
80    int p_stdin;
81    int p_stdout;
82    int p_stderr;
83    int c_stdin;
84    int c_stdout;
85    DyBuffer image;
86    int need_update;
87    int can_update;
88    int immediate_update;
89    int sync;
90    int labels;
91    int frame;
92    int rock_offset;
93    int cacheid;
94    int invalidate_cache;
95    int error;
96    int status;
97} PymolProxy;
98
99static void
100trace TCL_VARARGS_DEF(char *, arg1)
101{
102    if (debug) {
103        char *format;
104        va_list args;
105
106        format = TCL_VARARGS_START(char *, arg1, args);
107        vfprintf(flog, format, args);
108        fprintf(flog, "\n");
109        fflush(flog);
110    }
111}
112
113#ifdef KEEPSTATS
114
115static int
116WriteStats(const char *who, int code)
117{
118    double start, finish;
119    pid_t pid;
120    char buf[BUFSIZ];
121    Tcl_DString ds;
122
123    {
124        struct timeval tv;
125
126        /* Get ending time.  */
127        gettimeofday(&tv, NULL);
128        finish = CVT2SECS(tv);
129        tv = stats.start;
130        start = CVT2SECS(tv);
131    }
132    /*
133     * Session information:
134     *   1. Start date of session in seconds.
135     *   2. Process ID
136     *   3. Number of frames returned.
137     *   4. Number of bytes total returned (in frames).
138     *   5. Total elapsed time of all commands.
139     *   6. Total elapsed time of session.
140     *   7. Exit code of pymol server.
141     *   8. User time. 
142     *   9. System time.
143     *  10. Maximum resident size.
144     */
145    pid = getpid();
146    Tcl_DStringInit(&ds);
147
148    sprintf(buf, "<session server=\"%s\" ", who);
149    Tcl_DStringAppend(&ds, buf, -1);
150
151    strcpy(buf, ctime(&stats.start.tv_sec));
152
153    buf[strlen(buf) - 1] = '\0';
154    Tcl_DStringAppend(&ds, "date=\"", -1);
155    Tcl_DStringAppend(&ds, buf, -1);
156    Tcl_DStringAppend(&ds, "\" ", -1);
157
158    sprintf(buf, "date_secs=\"%ld\" ", stats.start.tv_sec);
159    Tcl_DStringAppend(&ds, buf, -1);
160
161    sprintf(buf, "pid=\"%d\" ", pid);
162    Tcl_DStringAppend(&ds, buf, -1);
163    sprintf(buf, "num_frames=\"%lu\" ", (unsigned long int)stats.nFrames);
164    Tcl_DStringAppend(&ds, buf, -1);
165    sprintf(buf, "frame_bytes=\"%lu\" ", (unsigned long int)stats.nBytes);
166    Tcl_DStringAppend(&ds, buf, -1);
167    sprintf(buf, "num_commands=\"%lu\" ", (unsigned long int)stats.nCommands);
168    Tcl_DStringAppend(&ds, buf, -1);
169    sprintf(buf, "cmd_time=\"%g\" ", stats.cmdTime);
170    Tcl_DStringAppend(&ds, buf, -1);
171    sprintf(buf, "session_time=\"%g\" ", finish - start);
172    Tcl_DStringAppend(&ds, buf, -1);
173    sprintf(buf, "status=\"%d\" ", code);
174    Tcl_DStringAppend(&ds, buf, -1);
175    {
176        long clocksPerSec = sysconf(_SC_CLK_TCK);
177        double clockRes = 1.0 / clocksPerSec;
178        struct tms tms;
179
180        memset(&tms, 0, sizeof(tms));
181        if (times(&tms) < 0) {
182            fprintf(flog, "can't get times: %s\n", strerror(errno));
183        }
184        sprintf(buf, "utime=\"%g\" ", tms.tms_utime * clockRes);
185        Tcl_DStringAppend(&ds, buf, -1);
186        sprintf(buf, "stime=\"%g\" ", tms.tms_stime * clockRes);
187        Tcl_DStringAppend(&ds, buf, -1);
188        sprintf(buf, "cutime=\"%g\" ", tms.tms_cutime * clockRes);
189        Tcl_DStringAppend(&ds, buf, -1);
190        sprintf(buf, "cstime=\"%g\" ", tms.tms_cstime * clockRes);
191        Tcl_DStringAppend(&ds, buf, -1);
192    }
193    Tcl_DStringAppend(&ds, "/>\n", -1);
194
195    {
196        int f;
197        ssize_t length;
198        int result;
199
200        length = Tcl_DStringLength(&ds);
201        f = open(STATSFILE, O_APPEND | O_CREAT | O_WRONLY, 0600);
202        result = FALSE;
203        if (f < 0) {
204            goto error;
205        }
206        if (write(f, Tcl_DStringValue(&ds), length) != length) {
207            goto error;
208        }
209        result = TRUE;
210 error:
211        if (f >= 0) {
212            close(f);
213        }
214        Tcl_DStringFree(&ds);
215        return result;
216    }
217}
218#endif
219
220static void
221DoExit(int code)
222{
223    char fileName[200];
224#ifdef KEEPSTATS
225    WriteStats("pymolproxy", code);
226#endif
227    sprintf(fileName, "/tmp/pymol%d.pdb", getpid());
228    unlink(fileName);
229    exit(code);
230}
231
232static int
233ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)
234{
235    struct timeval tv;
236    double start, finish;
237    int result;
238
239    gettimeofday(&tv, NULL);
240    start = CVT2SECS(tv);
241
242    result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr));
243    trace("Executed (%s)", Tcl_DStringValue(dsPtr));
244    Tcl_DStringSetLength(dsPtr, 0);
245
246    gettimeofday(&tv, NULL);
247    finish = CVT2SECS(tv);
248
249    stats.cmdTime += finish - start;
250    stats.nCommands++;
251    return result;
252}
253
254
255INLINE static void
256dyBufferInit(DyBuffer *buffer)
257{
258    buffer->data = NULL;
259    buffer->used = 0;
260    buffer->allocated = 0;
261}
262
263INLINE static void
264dyBufferFree(DyBuffer *buffer)
265{
266    assert(buffer != NULL);
267    free(buffer->data);
268    dyBufferInit(buffer);
269}
270
271void
272dyBufferSetLength(DyBuffer *buffer, int length)
273{
274    assert(buffer != NULL);
275    if (length == 0) {
276        dyBufferFree(buffer);
277    } else if (length > buffer->used) {
278        char *newdata;
279       
280        newdata = realloc(buffer->data, length);
281        if (newdata != NULL) {
282            buffer->data = newdata;
283            buffer->used = length;
284            buffer->allocated = length;
285        }
286    } else {
287        buffer->used = length;
288    }
289}
290
291static void
292dyBufferAppend(DyBuffer *buffer, const char *data, int length)
293{
294    int offset;
295
296    assert(buffer != NULL);
297    offset = buffer->used;
298    dyBufferSetLength(buffer, offset + length);
299    memcpy(buffer->data + offset, data, length);
300}
301
302static int
303bwrite(int sock, char *buffer, int size)
304{
305    int result;
306    int total = 0;
307    int left = size;
308
309    trace("bwrite: want to write %d bytes\n", size);
310    while(1) {
311        result = write(sock,buffer+total,left);
312
313        if (result <= 0)
314            break;
315
316        total += result;
317        left -= result;
318
319        if (total == size)
320            break;
321    }
322    trace("bwrite: wrote %d bytes\n", total);
323    return(total);
324}
325
326static int
327bread(int sock, char *buffer, int size)
328{
329    int result, total, left;
330
331    for( total = 0, left = size; left > 0; left -= result) {
332        result = read(sock,buffer+total,left);
333       
334        if (result > 0) {
335            total += result;
336            continue;
337        }
338       
339        if ((result < 0) && (errno != EAGAIN) && (errno != EINTR)) {
340            trace("pymolproxy: Error reading sock(%d), %d/%s\n",
341                  sock, errno,strerror(errno));
342            break;
343        }
344       
345        result = 0;
346    }
347    return total;
348}
349
350#ifdef notdef
351
352static int
353bflush(int sock, char *buffer, int size, int bytes)
354{
355    int bsize;
356
357    while(bytes) {
358        if (bytes > size)
359            bsize = size;
360        else
361            bsize = bytes;
362       
363        bsize = bread(sock,buffer,bsize);
364       
365        bytes -= bsize;     
366    }
367}
368
369#undef timersub
370static void
371timersub(struct timeval *a, struct timeval *b, struct timeval *result)
372{
373    result->tv_sec = a->tv_sec - b->tv_sec;
374    result->tv_usec = a->tv_usec - b->tv_usec;
375
376    while(result->tv_usec < 0) {
377        result->tv_sec -= 1;
378        result->tv_usec += 1000000;
379    }
380}
381
382#endif
383
384static void
385timersub_ms(struct timeval *a, struct timeval *b, int *result)
386{
387    struct timeval tmp;
388
389    tmp.tv_sec = a->tv_sec - b->tv_sec;
390    tmp.tv_usec = a->tv_usec - b->tv_usec;
391
392    while(tmp.tv_usec < 0) {
393        tmp.tv_sec -= 1;
394        tmp.tv_usec += 1000000;
395    }
396
397    *result = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000);
398}
399
400#undef timeradd
401static void
402timeradd (struct timeval *a, struct timeval *b, struct timeval *result)
403{
404    result->tv_sec = a->tv_sec + b->tv_sec;
405    result->tv_usec = a->tv_usec + b->tv_usec;
406
407    while (result->tv_usec >= 1000000) {
408        result->tv_sec += 1;
409        result->tv_usec -= 1000000;
410    }
411}
412
413static void
414timerset_ms(struct timeval *result, int timeout)
415{
416    result->tv_sec = timeout / 1000;
417    result->tv_usec = (timeout % 1000) * 1000;
418}
419
420static int
421getline(int sock, char *buffer, int size, long timeout)
422{
423    int pos = 0, status, timeo;
424    struct timeval now, end, tmo;
425    struct pollfd ufd;
426
427    gettimeofday(&now,NULL);
428    timerset_ms(&tmo, timeout);
429    timeradd(&now,&tmo,&end);
430
431    ufd.fd = sock;
432    ufd.events = POLLIN;
433
434    size--;
435
436    while(pos < size) {
437        if (timeout > 0) {
438            gettimeofday(&now,NULL);
439            timersub_ms(&now,&end,&timeo);
440        }
441        else
442            timeo = -1;
443
444        status = poll(&ufd, 1, timeo);
445
446        if (status > 0)
447            status = read(sock,&buffer[pos],1);
448
449        if ( (status < 0) && ( (errno == EINTR) || (errno == EAGAIN) ) )
450            continue; /* try again, if interrupted/blocking */
451
452        if (status <= 0)
453            break;
454                       
455        if (buffer[pos] == '\n') {
456            pos++;
457            break;
458        }
459        pos++;
460    }
461
462    buffer[pos]=0;
463
464    return(pos);
465}
466
467static int
468waitForString(PymolProxy *pymol, char *string, char *buffer, int length)
469{
470    int sock;
471
472    assert(buffer != NULL);
473    if (pymol->status != TCL_OK)
474        return pymol->status;
475
476    sock = pymol->p_stdout;
477    trace("want to match (%s)\n", string);
478    while(1) {
479        if (getline(sock,buffer,length,IO_TIMEOUT) == 0) {
480            pymol->error = 2;
481            pymol->status = TCL_ERROR;
482            break;
483        }
484        trace("stdout-u>read(%s)", buffer);
485        if (strncmp(buffer, string, strlen(string)) == 0) {
486            trace("stdout-e> %s",buffer);
487            pymol->error = 0;
488            pymol->status = TCL_OK;
489            break;
490        }
491    }
492
493    return pymol->status;
494}
495
496INLINE static int
497clear_error(PymolProxy *pymol)
498{
499    pymol->error = 0;
500    pymol->status = TCL_OK;
501    return pymol->status;
502}
503
504static int
505send_expect(PymolProxy *pymol, char *expect, char *cmd)
506{
507    if (pymol->error) {
508        return(TCL_ERROR);
509    }
510    trace("to-pymol>(%s)", cmd);
511    write(pymol->p_stdin, cmd, strlen(cmd));
512    if (waitForString(pymol, expect, cmd, 800)) {
513        trace("pymolproxy: Timeout reading data [%s]\n",cmd);
514        pymol->error = 1;
515        pymol->status = TCL_ERROR;
516        return pymol->status;
517    }
518    return( pymol->status );
519}
520
521static int
522sendf(PymolProxy *pymol, char *format, ...)
523{
524    va_list ap;
525    char buffer[800];
526
527    if (pymol->error)
528        return(TCL_ERROR);
529
530    va_start(ap, format);
531    vsnprintf(buffer, 800, format, ap);
532    va_end(ap);
533    trace("to-pymol>(%s)", buffer);
534    write(pymol->p_stdin, buffer, strlen(buffer));
535
536    if (waitForString(pymol, "PyMOL>", buffer, 800)) {
537        trace("pymolproxy: Timeout reading data [%s]\n",buffer);
538        pymol->error = 1;
539        pymol->status = TCL_ERROR;
540        return pymol->status;
541    }
542
543    return( pymol->status );
544}
545
546static int
547BallNStickCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
548{
549    int ghost = 0, defer = 0, push = 0, arg;
550    const char *model = "all";
551    PymolProxy *pymol = (PymolProxy *) cdata;
552
553    clear_error(pymol);
554
555    for(arg = 1; arg < argc; arg++) {
556        if ( strcmp(argv[arg],"-defer") == 0 )
557            defer = 1;
558        else if (strcmp(argv[arg],"-push") == 0)
559            push = 1;
560        else if (strcmp(argv[arg],"-ghost") == 0)
561            ghost = 1;
562        else if (strcmp(argv[arg],"-normal") == 0)
563            ghost = 0;
564        else if (strcmp(argv[arg],"-model") == 0) {
565            if (++arg < argc)
566                model = argv[arg];
567        }
568        else
569            model = argv[arg];
570    }
571
572    pymol->invalidate_cache = 1;
573    pymol->need_update = !defer || push;
574    pymol->immediate_update |= push;
575
576    sendf(pymol, "hide everything,%s\n",model);
577    sendf(pymol, "set stick_color,white,%s\n",model);
578       
579    if (ghost)
580        sendf(pymol, "set stick_radius,0.1,%s\n",model);
581    else
582        sendf(pymol, "set stick_radius,0.14,%s\n",model);
583
584    sendf(pymol, "set sphere_scale=0.25,%s\n", model);
585
586    if (ghost) {
587        sendf(pymol, "set sphere_transparency,0.75,%s\n", model);
588        sendf(pymol, "set stick_transparency,0.75,%s\n", model);
589    }
590    else {
591        sendf(pymol, "set sphere_transparency,0,%s\n", model);
592        sendf(pymol, "set stick_transparency,0,%s\n", model);
593    }
594
595    sendf(pymol, "show sticks,%s\n",model);
596    sendf(pymol, "show spheres,%s\n",model);
597
598    if (pymol->labels)
599        sendf(pymol, "show labels,%s\n", model);
600
601    return( pymol->status );
602}
603
604static int
605SpheresCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
606{
607    int defer = 0, ghost = 0, push = 0, arg;
608    const char *model = "all";
609    PymolProxy *pymol = (PymolProxy *) cdata;
610
611    clear_error(pymol);
612
613    for(arg = 1; arg < argc; arg++) {
614        if ( strcmp(argv[arg],"-defer") == 0 )
615            defer = 1;
616        else if (strcmp(argv[arg],"-push") == 0)
617            push = 1;
618        else if (strcmp(argv[arg],"-ghost") == 0)
619            ghost = 1;
620        else if (strcmp(argv[arg],"-normal") == 0)
621            ghost = 0;
622        else if (strcmp(argv[arg],"-model") == 0) {
623            if (++arg < argc)
624                model = argv[arg];
625        }
626        else
627            model = argv[arg];
628    }
629
630    pymol->invalidate_cache = 1;
631    pymol->need_update = !defer || push;
632    pymol->immediate_update |= push;
633
634    sendf(pymol, "hide everything, %s\n", model);
635    sendf(pymol, "set sphere_scale,0.41,%s\n", model);
636    //sendf(pymol, "set sphere_quality,2,%s\n", model);
637    sendf(pymol, "set ambient,.2,%s\n", model);
638
639    if (ghost)
640        sendf(pymol, "set sphere_transparency,.75,%s\n", model);
641    else
642        sendf(pymol, "set sphere_transparency,0,%s\n", model);
643
644    sendf(pymol, "show spheres,%s\n", model);
645
646    if (pymol->labels)
647        sendf(pymol, "show labels,%s\n", model);
648
649    return pymol->status;
650}
651
652static int
653LinesCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
654{
655    int ghost = 0, defer = 0, push = 0, arg;
656    const char *model = "all";
657    PymolProxy *pymol = (PymolProxy *) cdata;
658
659    clear_error(pymol);
660
661    for(arg = 1; arg < argc; arg++) {
662        if ( strcmp(argv[arg],"-defer") == 0 )
663            defer = 1;
664        else if (strcmp(argv[arg],"-push") == 0)
665            push = 1;
666        else if (strcmp(argv[arg],"-ghost") == 0)
667            ghost = 1;
668        else if (strcmp(argv[arg],"-normal") == 0)
669            ghost = 0;
670        else if (strcmp(argv[arg],"-model") == 0) {
671            if (++arg < argc)
672                model = argv[arg];
673        }
674        else
675            model = argv[arg];
676    }
677
678    pymol->invalidate_cache = 1;
679    pymol->need_update = !defer || push;
680    pymol->immediate_update |= push;
681
682    sendf(pymol, "hide everything,%s\n",model);
683
684    if (ghost)
685        sendf(pymol, "set line_width,.25,%s\n",model);
686    else
687        sendf(pymol, "set line_width,1,%s\n",model);
688
689    sendf(pymol, "show lines,%s\n",model);
690
691    if (pymol->labels)
692        sendf(pymol, "show labels,%s\n",model);
693
694    return pymol->status;
695}
696
697static int
698DisableCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
699{
700    PymolProxy *pymol = (PymolProxy *) cdata;
701    const char *model = "all";
702    int arg, defer = 0, push = 0;
703
704    clear_error(pymol);
705
706    for(arg = 1; arg < argc; arg++) {
707
708        if (strcmp(argv[arg], "-defer") == 0 )
709            defer = 1;
710        else if (strcmp(argv[arg], "-push") == 0 )
711            push = 1;
712        else
713            model = argv[arg];
714       
715    }
716
717    pymol->need_update = !defer || push;
718    pymol->immediate_update |= push;
719    pymol->invalidate_cache = 1;
720
721    sendf( pymol, "disable %s\n", model);
722
723    return pymol->status;
724}
725
726static int
727EnableCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
728{
729    PymolProxy *pymol = (PymolProxy *) cdata;
730    const char *model = "all";
731    int arg, defer = 0, push = 0;
732
733    clear_error(pymol);
734
735    for(arg = 1; arg < argc; arg++) {
736               
737        if (strcmp(argv[arg],"-defer") == 0)
738            defer = 1;
739        else if (strcmp(argv[arg], "-push") == 0 )
740            push = 1;
741        else
742            model = argv[arg];
743
744    }
745
746    pymol->need_update = !defer || push;
747    pymol->immediate_update |= push;
748    pymol->invalidate_cache = 1;
749
750    sendf( pymol, "enable %s\n", model);
751
752    return pymol->status;
753}
754
755static int
756VMouseCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
757{
758    PymolProxy *pymol = (PymolProxy *) cdata;
759    int arg, defer = 0, push = 0, varg = 1;
760    int arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0, arg5 = 0;
761
762    clear_error(pymol);
763
764    for(arg = 1; arg < argc; arg++) {
765        if (strcmp(argv[arg], "-defer") == 0)
766            defer = 1;
767        else if (strcmp(argv[arg], "-push") == 0)
768            push = 1;
769        else if (varg == 1) {
770            arg1 = atoi(argv[arg]);
771            varg++;
772        }
773        else if (varg == 2) {
774            arg2 = atoi(argv[arg]);
775            varg++;
776        }
777        else if (varg == 3) {
778            arg3 = atoi(argv[arg]);
779            varg++;
780        }
781        else if (varg == 4) {
782            arg4 = atoi(argv[arg]);
783            varg++;
784        }
785        else if (varg == 5) {
786            arg5 = atoi(argv[arg]);
787            varg++;
788        }
789    }
790
791    pymol->need_update = !defer || push;
792    pymol->immediate_update |= push;
793    pymol->invalidate_cache = 1;
794
795    sendf(pymol, "vmouse %d,%d,%d,%d,%d\n", arg1,arg2,arg3,arg4,arg5);
796
797    return pymol->status;
798}
799
800static int
801RawCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
802{
803    PymolProxy *pymol = (PymolProxy *) cdata;
804    DyBuffer buffer;
805    int arg, defer = 0, push = 0;
806    const char *cmd;
807    clear_error(pymol);
808
809    dyBufferInit(&buffer);
810
811    cmd = NULL;
812    for(arg = 1; arg < argc; arg++) {
813        if (strcmp(argv[arg], "-defer") == 0)
814            defer = 1;
815        else if (strcmp(argv[arg], "-push") == 0)
816            push = 1;
817        else {
818            cmd = argv[arg];
819        }
820    }
821
822    pymol->need_update = !defer || push;
823    pymol->immediate_update |= push;
824    pymol->invalidate_cache = 1;
825
826    sendf(pymol,"%s\n", cmd);
827    dyBufferFree(&buffer);
828
829    return pymol->status;
830}
831
832static int
833LabelCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
834{
835    PymolProxy *pymol = (PymolProxy *) cdata;
836    int state = 1;
837    int arg, push = 0, defer = 0;
838
839    clear_error(pymol);
840
841    for(arg = 1; arg < argc; arg++) {
842        if ( strcmp(argv[arg],"-defer") == 0 )
843            defer = 1;
844        else if (strcmp(argv[arg],"-push") == 0 )
845            push = 1;
846        else if (strcmp(argv[arg],"on") == 0 )
847            state = 1;
848        else if (strcmp(argv[arg],"off") == 0 )
849            state = 0;
850        else if (strcmp(argv[arg],"toggle") == 0 )
851            state =  !pymol->labels;
852    }
853
854    pymol->need_update = !defer || push;
855    pymol->immediate_update |= push;
856    pymol->invalidate_cache = 1;
857
858    if (state) {
859        sendf(pymol, "set label_color,white,all\n");
860        sendf(pymol, "set label_size,14,all\n");
861        sendf(pymol, "label all,\"%%s%%s\" %% (ID,name)\n");
862    }
863    else
864        sendf(pymol, "label all\n");
865
866    pymol->labels = state;
867
868    return pymol->status;
869}
870
871static int
872FrameCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
873{
874    PymolProxy *pymol = (PymolProxy *) cdata;
875    int frame = 0;
876    int arg, push = 0, defer = 0;
877
878    clear_error(pymol);
879
880    for(arg = 1; arg < argc; arg++) {
881        if ( strcmp(argv[arg],"-defer") == 0 )
882            defer = 1;
883        else if (strcmp(argv[arg],"-push") == 0 )
884            push = 1;
885        else
886            frame = atoi(argv[arg]);
887    }
888               
889    pymol->need_update = !defer || push;
890    pymol->immediate_update |= push;
891
892    pymol->frame = frame;
893
894    sendf(pymol,"frame %d\n", frame);
895       
896    return pymol->status;
897}
898
899static int
900ResetCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
901{
902    PymolProxy *pymol = (PymolProxy *) cdata;
903    int arg, push = 0, defer = 0;
904
905    clear_error(pymol);
906
907    for(arg = 1; arg < argc; arg++) {
908        if ( strcmp(argv[arg],"-defer") == 0 )
909            defer = 1;
910        else if (strcmp(argv[arg],"-push") == 0 )
911            push = 1;
912    }
913               
914    pymol->need_update = !defer || push;
915    pymol->immediate_update |= push;
916    pymol->invalidate_cache = 1;
917       
918    sendf(pymol, "reset\n");
919    sendf(pymol, "zoom buffer=2\n");
920
921    return pymol->status;
922}
923
924static int
925RockCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
926{
927    PymolProxy *pymol = (PymolProxy *) cdata;
928    float y = 0.0;
929    int arg, push = 0, defer = 0;
930
931    clear_error(pymol);
932
933    for(arg = 1; arg < argc; arg++) {
934        if ( strcmp(argv[arg],"-defer") == 0 )
935            defer = 1;
936        else if (strcmp(argv[arg],"-push") == 0 )
937            push = 1;
938        else
939            y = atof( argv[arg] );
940    }
941               
942    pymol->need_update = !defer || push;
943    pymol->immediate_update |= push;
944
945    sendf(pymol,"turn y, %f\n", y - pymol->rock_offset);
946
947    pymol->rock_offset = y;
948
949    return pymol->status;
950}
951
952static int
953ViewportCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
954{
955    PymolProxy *pymol = (PymolProxy *) cdata;
956    int width = 640, height = 480;
957    int defer = 0, push = 0, arg, varg = 1;
958
959    clear_error(pymol);
960
961    for(arg = 1; arg < argc; arg++) {
962        if ( strcmp(argv[arg],"-defer") == 0 )
963            defer = 1;
964        else if ( strcmp(argv[arg], "-push") == 0 )
965            push = 1;
966        else if (varg == 1) {
967            width = atoi(argv[arg]);
968            height = width;
969            varg++;
970        }
971        else if (varg == 2) {
972            height = atoi(argv[arg]);
973            varg++;
974        }
975    }
976
977    pymol->need_update = !defer || push;
978    pymol->immediate_update |= push;
979    pymol->invalidate_cache = 1;
980
981    sendf(pymol, "viewport %d,%d\n", width, height);
982
983    //usleep(205000); // .2s delay for pymol to update its geometry *HACK ALERT*
984       
985    return pymol->status;
986}
987
988static int
989LoadPDB2Cmd(ClientData cdata, Tcl_Interp *interp, int argc,
990              const char *argv[])
991{
992    const char *pdbdata, *name;
993    PymolProxy *pymol = (PymolProxy *) cdata;
994    int state = 1;
995    int arg, defer = 0, push = 0, varg = 1;
996   
997    if (pymol == NULL)
998        return(TCL_ERROR);
999    clear_error(pymol);
1000    pdbdata = name = NULL;      /* Suppress compiler warning. */
1001    for(arg = 1; arg < argc; arg++) {
1002        if ( strcmp(argv[arg],"-defer") == 0 )
1003            defer = 1;
1004        else if (strcmp(argv[arg],"-push") == 0)
1005            push = 1;
1006        else if (varg == 1) {
1007            pdbdata = argv[arg];
1008            varg++;
1009        } else if (varg == 2) {
1010            name = argv[arg];
1011            varg++;
1012        } else if (varg == 3) {
1013            state = atoi( argv[arg] );
1014            varg++;
1015        }
1016    }
1017   
1018    pymol->need_update = !defer || push;
1019    pymol->immediate_update |= push;
1020
1021    {
1022        char fileName[200];
1023        FILE *f;
1024        size_t nBytes, nWritten;
1025
1026        sprintf(fileName, "/tmp/pymol%d.pdb", getpid());
1027        f = fopen(fileName, "w");
1028        trace("pymolproxy: open file %s as %x\n", fileName, f);
1029        if (f == NULL) {
1030            trace("pymolproxy: failed to open %s %d\n", fileName, errno);
1031            perror("pymolproxy");
1032        }
1033        nBytes = strlen(pdbdata);
1034        nWritten = fwrite(pdbdata, sizeof(char), nBytes, f);
1035        if (nBytes != nWritten) {
1036            trace("pymolproxy: short write %d wanted %d bytes\n", nWritten,
1037                  nBytes);
1038            perror("pymolproxy");
1039        }
1040        fclose(f);
1041        sendf(pymol, "load %s, %s, %d\n", fileName, name, state);
1042    }
1043    sendf(pymol, "zoom buffer=2\n");
1044    return(pymol->status);
1045}
1046
1047static int
1048LoadPDBCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
1049{
1050    const char *pdbdata, *name;
1051    PymolProxy *pymol = (PymolProxy *) cdata;
1052    int state = 1;
1053    int arg, defer = 0, push = 0, varg = 1;
1054
1055    clear_error(pymol);
1056
1057    pdbdata = name = NULL;      /* Suppress compiler warning. */
1058    for(arg = 1; arg < argc; arg++) {
1059        if ( strcmp(argv[arg],"-defer") == 0 )
1060            defer = 1;
1061        else if (strcmp(argv[arg],"-push") == 0)
1062            push = 1;
1063        else if (varg == 1) {
1064            pdbdata = argv[arg];
1065            varg++;
1066        }
1067        else if (varg == 2) {
1068            name = argv[arg];
1069            varg++;
1070        }
1071        else if (varg == 3) {
1072            state = atoi( argv[arg] );
1073            varg++;
1074        }
1075    }
1076
1077    pymol->need_update = !defer || push;
1078    pymol->immediate_update |= push;
1079
1080    {
1081        int count;
1082        const char *p;
1083        char *q, *newdata;
1084
1085        count = 0;
1086        for (p = pdbdata; *p != '\0'; p++) {
1087            if (*p == '\n') {
1088                count++;
1089            }
1090            count++;
1091        }
1092       
1093        q = newdata = malloc(count + 100);
1094        strcpy(newdata, "cmd.read_pdbstr(\"\"\"\\\n");
1095        q = newdata + strlen(newdata);
1096        for (p = pdbdata; *p != '\0'; p++, q++) {
1097            if (*p == '\n') {
1098                *q++ = '\\';
1099            }
1100            *q = *p;
1101        }
1102        sprintf(q, "\\\n\"\"\",\"%s\",%d)\n", name, state);
1103        {
1104            char expect[800];
1105
1106            sprintf(expect, "PyMOL>\"\"\",\"%s\",%d)\n", name, state);
1107            send_expect(pymol, expect, newdata);
1108        }
1109        free(newdata);
1110    }
1111    sendf(pymol, "zoom buffer=2\n");
1112
1113    return pymol->status;
1114}
1115
1116
1117static int
1118RotateCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
1119{
1120    double turnx = 0.0;
1121    double turny = 0.0;
1122    double turnz = 0.0;
1123    PymolProxy *pymol = (PymolProxy *) cdata;
1124    int defer = 0, push = 0, arg, varg = 1;
1125
1126    clear_error(pymol);
1127
1128    for(arg = 1; arg < argc; arg++) {
1129        if (strcmp(argv[arg],"-defer") == 0) {
1130            defer = 1;
1131        } else if (strcmp(argv[arg],"-push") == 0) {
1132            push = 1;
1133        } else  if (varg == 1) {
1134            turnx = atof(argv[arg]);
1135            varg++;
1136        } else if (varg == 2) {
1137            turny = atof(argv[arg]);
1138            varg++;
1139        } else if (varg == 3) {
1140            turnz = atof(argv[arg]);
1141            varg++;
1142        }
1143    }
1144    pymol->need_update = !defer || push;
1145    pymol->immediate_update  |= push;
1146    pymol->invalidate_cache = 1;
1147
1148    if (turnx != 0.0)
1149        sendf(pymol,"turn x, %f\n", turnx);
1150       
1151    if (turny != 0.0)
1152        sendf(pymol,"turn y, %f\n", turny);
1153       
1154    if (turnz != 0.0)
1155        sendf(pymol,"turn z, %f\n", turnz);
1156
1157    return pymol->status;
1158}
1159
1160static int
1161ZoomCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
1162{
1163    double factor = 0.0;
1164    double zmove = 0.0;
1165    PymolProxy *pymol = (PymolProxy *) cdata;
1166    int defer = 0, push = 0, arg, varg = 1;
1167
1168    clear_error(pymol);
1169
1170    for(arg = 1; arg < argc; arg++) {
1171        if (strcmp(argv[arg],"-defer") == 0)
1172            defer = 1;
1173        else if (strcmp(argv[arg],"-push") == 0)
1174            push = 1;
1175        else if (varg == 1) {
1176            factor = atof(argv[arg]);
1177            varg++;
1178        }
1179    }
1180    zmove = factor * -75;
1181 
1182    pymol->need_update = !defer || push;
1183    pymol->immediate_update  |= push;
1184    pymol->invalidate_cache = 1;
1185
1186    if (zmove != 0.0)
1187        sendf(pymol,"move z, %f\n", factor);
1188
1189    return pymol->status;
1190}
1191
1192static int
1193PNGCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
1194{
1195    char buffer[800];
1196    unsigned int nBytes=0;
1197    float samples = 0.0;
1198    PymolProxy *pymol = (PymolProxy *) cdata;
1199
1200    clear_error(pymol);
1201
1202    if (pymol->invalidate_cache)
1203        pymol->cacheid++;
1204
1205    pymol->need_update = 0;
1206    pymol->immediate_update = 0;
1207    pymol->invalidate_cache = 0;
1208
1209    sendf(pymol,"png -\n");
1210
1211    waitForString(pymol, "image follows: ", buffer, 800);
1212
1213    sscanf(buffer, "image follows: %d %f\n", &nBytes, &samples);
1214 
1215    write(3, &samples, sizeof(samples));
1216 
1217    dyBufferSetLength(&pymol->image, nBytes);
1218
1219    bread(pymol->p_stdout, pymol->image.data, pymol->image.used);
1220
1221    waitForString(pymol, " ScenePNG", buffer,800);
1222
1223    if ((nBytes > 0) && (pymol->image.used == nBytes)) {
1224        sprintf(buffer, "nv>image %d %d %d %d\n",
1225                nBytes, pymol->cacheid, pymol->frame, pymol->rock_offset);
1226        trace("to-molvis> %s", buffer);
1227        write(pymol->c_stdin, buffer, strlen(buffer));
1228        bwrite(pymol->c_stdin, pymol->image.data, nBytes);
1229        stats.nFrames++;
1230        stats.nBytes += nBytes;
1231    }
1232    return pymol->status;
1233}
1234
1235static int
1236BMPCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
1237{
1238    char buffer[800];
1239    unsigned int nBytes=0;
1240    float samples = 0.0;
1241    PymolProxy *pymol = (PymolProxy *) cdata;
1242
1243    clear_error(pymol);
1244
1245    if (pymol->invalidate_cache)
1246        pymol->cacheid++;
1247
1248    pymol->need_update = 0;
1249    pymol->immediate_update = 0;
1250    pymol->invalidate_cache = 0;
1251
1252    sendf(pymol,"bmp -\n");
1253
1254    waitForString(pymol, "image follows: ", buffer, 800);
1255
1256    sscanf(buffer, "image follows: %d %f\n", &nBytes, &samples);
1257    write(3,&samples,sizeof(samples));
1258
1259    dyBufferSetLength(&pymol->image, nBytes);
1260
1261    bread(pymol->p_stdout, pymol->image.data, pymol->image.used);
1262
1263    if ((nBytes > 0) && (pymol->image.used == nBytes)) {
1264        sprintf(buffer, "nv>image %d %d %d %d\n",
1265                nBytes, pymol->cacheid, pymol->frame, pymol->rock_offset);
1266        write(pymol->c_stdin, buffer, strlen(buffer));
1267        trace("to-molvis buffer=%s\n", buffer);
1268        bwrite(pymol->c_stdin, pymol->image.data, nBytes);
1269        stats.nFrames++;
1270        stats.nBytes += nBytes;
1271    }
1272    return pymol->status;
1273}
1274       
1275static int
1276ProxyInit(int c_in, int c_out, char *const *argv)
1277{
1278    int flags, status, result = 0;
1279    int pairIn[2];
1280    int pairOut[2];
1281    int pairErr[2];
1282    Tcl_Interp *interp;
1283    Tcl_DString cmdbuffer;
1284    DyBuffer dybuffer, dybuffer2;
1285    struct pollfd ufd[3];
1286    int pid;
1287    PymolProxy pymol;
1288    struct timeval now, end;
1289    int timeout;
1290
1291    /* Create three pipes for communication with the external application. One
1292     * each for the applications's: stdin, stdout, and stderr  */
1293
1294    if (pipe(pairIn) == -1)
1295        return(-1);
1296
1297    if (pipe(pairOut) == -1) {
1298        close(pairIn[0]);
1299        close(pairIn[1]);
1300        return(-1);
1301    }
1302
1303    if (pipe(pairErr) == -1) {
1304        close(pairIn[0]);
1305        close(pairIn[1]);
1306        close(pairOut[0]);
1307        close(pairOut[1]);
1308        return(-1);
1309    }
1310
1311    /* Fork the new process.  Connect i/o to the new socket.  */
1312
1313    pid = fork();
1314       
1315    if (pid < 0) {
1316        fprintf(stderr, "can't fork process: %s\n", strerror(errno));
1317        return(-3);
1318    }
1319    if (pid == 0) {
1320        int fd;
1321
1322        /* Child process */
1323       
1324        /*
1325         * Create a new process group, so we can later kill this process and
1326         * all its children without affecting the process that created this
1327         * one.
1328         */
1329        setpgid(pid, 0);
1330       
1331        /* Redirect stdin, stdout, and stderr to pipes before execing */
1332        dup2(pairIn[0] ,0);  // stdin
1333        dup2(pairOut[1],1);  // stdout
1334        dup2(pairErr[1],2);  // stderr
1335       
1336        for(fd = 3; fd < FD_SETSIZE; fd++)  /* close all other descriptors  */
1337            close(fd);
1338       
1339        execvp(argv[0], argv);
1340        trace("pymolproxy: Failed to start pyMol %s\n", argv[0]);
1341        exit(-1);
1342    }
1343    stats.child = pid;
1344
1345    /* close opposite end of pipe, these now belong to the child process        */
1346    close(pairIn[0]);
1347    close(pairOut[1]);
1348    close(pairErr[1]);
1349
1350    signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE (ie if nanoscale terminates)
1351
1352    pymol.p_stdin = pairIn[1];
1353    pymol.p_stdout = pairOut[0];
1354    pymol.p_stderr = pairErr[0];
1355    pymol.c_stdin  = c_in;
1356    pymol.c_stdout = c_out;
1357    pymol.labels = 0;
1358    pymol.need_update = 0;
1359    pymol.can_update = 1;
1360    pymol.immediate_update = 0;
1361    pymol.sync = 0;
1362    pymol.frame = 1;
1363    pymol.rock_offset = 0;
1364    pymol.cacheid = 0;
1365    pymol.invalidate_cache = 0;
1366
1367    ufd[0].fd = pymol.c_stdout;
1368    ufd[0].events = POLLIN | POLLHUP; /* ensure catching EOF */
1369    ufd[1].fd = pymol.p_stdout;
1370    ufd[1].events = POLLIN | POLLHUP;
1371    ufd[2].fd = pymol.p_stderr;
1372    ufd[2].events = POLLIN | POLLHUP;
1373
1374    flags = fcntl(pymol.p_stdout, F_GETFL);
1375    fcntl(pymol.p_stdout, F_SETFL, flags|O_NONBLOCK);
1376
1377    interp = Tcl_CreateInterp();
1378    Tcl_MakeSafe(interp);
1379
1380    Tcl_DStringInit(&cmdbuffer);
1381    dyBufferInit(&pymol.image);
1382    dyBufferInit(&dybuffer);
1383    dyBufferInit(&dybuffer2);
1384
1385    Tcl_CreateCommand(interp, "bmp",     BMPCmd,        &pymol, NULL);
1386    Tcl_CreateCommand(interp, "png",     PNGCmd,        &pymol, NULL);
1387    Tcl_CreateCommand(interp, "screen",  ViewportCmd,   &pymol, NULL);
1388    Tcl_CreateCommand(interp, "viewport",ViewportCmd,   &pymol, NULL);
1389    Tcl_CreateCommand(interp, "rotate",  RotateCmd,     &pymol, NULL);
1390    Tcl_CreateCommand(interp, "zoom",    ZoomCmd,       &pymol, NULL);
1391    Tcl_CreateCommand(interp, "loadpdb.old", LoadPDBCmd,    &pymol, NULL);
1392    Tcl_CreateCommand(interp, "loadpdb", LoadPDB2Cmd,  &pymol, NULL);
1393    Tcl_CreateCommand(interp, "ballnstick",BallNStickCmd, &pymol, NULL);
1394    Tcl_CreateCommand(interp, "spheres", SpheresCmd,    &pymol, NULL);
1395    Tcl_CreateCommand(interp, "lines",   LinesCmd,      &pymol, NULL);
1396    Tcl_CreateCommand(interp, "raw",     RawCmd,        &pymol, NULL);
1397    Tcl_CreateCommand(interp, "label",   LabelCmd,      &pymol, NULL);
1398    Tcl_CreateCommand(interp, "reset",   ResetCmd,      &pymol, NULL);
1399    Tcl_CreateCommand(interp, "rock",    RockCmd,       &pymol, NULL);
1400    Tcl_CreateCommand(interp, "frame",   FrameCmd,      &pymol, NULL);
1401    Tcl_CreateCommand(interp, "vmouse",  VMouseCmd,     &pymol, NULL);
1402    Tcl_CreateCommand(interp, "disable", DisableCmd,    &pymol, NULL);
1403    Tcl_CreateCommand(interp, "enable",  EnableCmd,     &pymol, NULL);
1404
1405    // Main Proxy Loop
1406    //  accept tcl commands from socket
1407    //  translate them into pyMol commands, and issue them to child proccess
1408    //  send images back
1409
1410    gettimeofday(&end, NULL);
1411    stats.start = end;
1412    while(1) {
1413        char ch;
1414       
1415        gettimeofday(&now,NULL);
1416       
1417        if ( (!pymol.need_update) )
1418            timeout = -1;
1419        else if ((now.tv_sec > end.tv_sec) || ( (now.tv_sec == end.tv_sec) && (now.tv_usec >= end.tv_usec)) )
1420            timeout = 0;
1421        else {
1422            timeout = (end.tv_sec - now.tv_sec) * 1000;
1423           
1424            if (end.tv_usec > now.tv_usec)
1425                timeout += (end.tv_usec - now.tv_usec) / 1000;
1426            else
1427                timeout += (((1000000 + end.tv_usec) - now.tv_usec) / 1000) - 1000;
1428           
1429        }
1430       
1431        if (!pymol.immediate_update)
1432            status = poll(ufd, 3, timeout);
1433        else
1434            status = 0;
1435       
1436        if ( status < 0 ) {
1437            trace("pymolproxy: POLL ERROR: status = %d, errno = %d, %s \n", status,errno,strerror(errno));
1438        } else if (status > 0) {
1439            gettimeofday(&now,NULL);
1440           
1441            if (ufd[0].revents) { /* Client Stdout Connection: command input */
1442                if (read(ufd[0].fd,&ch,1) <= 0) {
1443                    if (errno != EINTR) {
1444                        trace("pymolproxy: lost client connection (%d).\n", errno);
1445                        break;
1446                    }
1447                } else {
1448                    Tcl_DStringAppend(&cmdbuffer, &ch, 1);
1449                   
1450                    if (ch == '\n' && Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer))) {
1451                        int result;
1452
1453                        result = ExecuteCommand(interp, &cmdbuffer);
1454                        if (timeout == 0) status = 0; // send update
1455                    }
1456                }
1457            }
1458
1459            if (ufd[1].revents ) { /* pyMol Stdout Connection: pymol (unexpected) output */
1460                if (read(ufd[1].fd, &ch, 1) <= 0) {
1461                    if (errno != EINTR) {
1462                        trace("pymolproxy: lost connection (stdout) to pymol server\n");
1463                        break;
1464                    }
1465                } else {
1466                    dyBufferAppend(&dybuffer, &ch, 1);
1467                   
1468                    if (ch == '\n') {
1469                        ch = 0;
1470                        dyBufferAppend(&dybuffer, &ch, 1);
1471                        trace("STDOUT>%s",dybuffer.data);
1472                        dyBufferSetLength(&dybuffer,0);
1473                    }
1474                }
1475            }
1476           
1477            if (ufd[2].revents) { /* pyMol Stderr Connection: pymol standard error output */
1478                if (read(ufd[2].fd, &ch, 1) <= 0) {
1479                    if (errno != EINTR) {
1480                        trace("pymolproxy: lost connection (stderr) to pymol server\n");
1481                        break;
1482                    }
1483                } else {
1484                    dyBufferAppend(&dybuffer2, &ch, 1);
1485                   
1486                    if (ch == '\n') {
1487                        ch = 0;
1488                        dyBufferAppend(&dybuffer2, &ch, 1);
1489                        trace("stderr>%s", dybuffer2.data);
1490                        dyBufferSetLength(&dybuffer2,0);
1491                    }
1492                }
1493            }
1494        }
1495       
1496        if (status == 0) {
1497            gettimeofday(&now,NULL);
1498           
1499            if (pymol.need_update && pymol.can_update)
1500                Tcl_Eval(interp, "bmp -\n");
1501           
1502            end.tv_sec = now.tv_sec;
1503            end.tv_usec = now.tv_usec + 150000;
1504           
1505            if (end.tv_usec >= 1000000) {
1506                end.tv_sec++;
1507                end.tv_usec -= 1000000;
1508            }
1509           
1510        }
1511       
1512    }
1513   
1514    status = waitpid(pid, &result, WNOHANG);
1515    if (status == -1) {
1516        trace("pymolproxy: error waiting on pymol server to exit (%d)\n", errno);
1517    } else if (status == 0) {
1518        trace("pymolproxy: attempting to SIGTERM pymol server\n");
1519        kill(-pid, SIGTERM); // kill process group
1520        alarm(5);
1521        status = waitpid(pid, &result, 0);
1522        alarm(0);
1523
1524        while ((status == -1) && (errno == EINTR)) {
1525            trace("pymolproxy: Attempting to SIGKILL process.\n");
1526            kill(-pid, SIGKILL); // kill process group
1527            alarm(10);
1528            status = waitpid(pid, &result, 0);
1529            alarm(0);
1530        }
1531    }
1532   
1533    trace("pymolproxy: pymol server process ended (%d)\n", result);
1534   
1535    dyBufferFree(&pymol.image);
1536   
1537    Tcl_DeleteInterp(interp);
1538    DoExit(result);
1539    return 0;
1540}
1541
1542#ifdef STANDALONE
1543
1544int
1545main(int argc, char *argv[])
1546{
1547    flog = stderr;
1548    if (debug) {
1549        char fileName[200];
1550        sprintf(fileName, "/tmp/pymolproxy%d.log", getpid());
1551        flog = fopen(fileName, "w");
1552    }   
1553    ProxyInit(fileno(stdout), fileno(stdin), argv + 1);
1554    return 0;
1555}
1556
1557#endif
1558
Note: See TracBrowser for help on using the repository browser.