source: nanoscale/trunk/tclparser.c @ 6632

Last change on this file since 6632 was 6575, checked in by ldelgass, 8 years ago

check for max servers in tcl parser

  • Property svn:eol-style set to native
File size: 6.5 KB
Line 
1/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/* ======================================================================
3 *  Copyright (c) 2004-2016  HUBzero Foundation, LLC
4 * ----------------------------------------------------------------------
5 *  See the file "license.terms" for information on usage and
6 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
7 * ======================================================================
8 */
9#include <stdlib.h>
10#include <string.h>
11#include <tcl.h>
12
13#include "server.h"
14
15static int *s_numServers;
16static RenderServer **s_serverTable;
17
18static int
19ParseSwitches(Tcl_Interp *interp, RenderServer *serverPtr, int *objcPtr,
20              Tcl_Obj ***objvPtr)
21{
22    int i, objc;
23    Tcl_Obj **objv;
24
25    objc = *objcPtr;
26    objv = *objvPtr;
27    for (i = 3; i < objc; i += 2) {
28        const char *string;
29        char c;
30
31        string = Tcl_GetString(objv[i]);
32        if (string[0] != '-') {
33            break;
34        }
35        c = string[1];
36        if ((c == 'i') && (strcmp(string, "-input") == 0)) {
37            int f;
38
39            if (Tcl_GetIntFromObj(interp, objv[i+1], &f) != TCL_OK) {
40                return TCL_ERROR;
41            }
42            serverPtr->inputFd = f;
43        } else if ((c == 'o') && (strcmp(string, "-output") == 0)) {
44            int f;
45
46            if (Tcl_GetIntFromObj(interp, objv[i+1], &f) != TCL_OK) {
47                return TCL_ERROR;
48            }
49            serverPtr->outputFd = f;
50        } else if ((c == 'l') && (strcmp(string, "-logstdout") == 0)) {
51            int state;
52
53            if (Tcl_GetBooleanFromObj(interp, objv[i+1], &state) != TCL_OK) {
54                return TCL_ERROR;
55            }
56            serverPtr->logStdout = state;
57        } else if ((c == 'l') && (strcmp(string, "-logstderr") == 0)) {
58            int state;
59
60            if (Tcl_GetBooleanFromObj(interp, objv[i+1], &state) != TCL_OK) {
61                return TCL_ERROR;
62            }
63            serverPtr->logStderr = state;
64        } else if ((c == 'c') && (strcmp(string, "-combinelogs") == 0)) {
65            int state;
66
67            if (Tcl_GetBooleanFromObj(interp, objv[i+1], &state) != TCL_OK) {
68                return TCL_ERROR;
69            }
70            serverPtr->combineLogs = state;
71        } else {
72            Tcl_AppendResult(interp, "unknown switch \"", string, "\"",
73                             (char *)NULL);
74            return TCL_ERROR;
75        }
76    }
77    *objcPtr = objc - (i - 3);
78    *objvPtr = objv + (i - 3);
79    return TCL_OK;
80}
81
82/*
83 * RegisterServerCmd --
84 *
85 *      Registers a render server to be run when a client connects
86 *      on the designated port. The form of the commands is
87 *
88 *          register_server <name> <port> <cmd> <environ>
89 *
90 *      where
91 *
92 *          name        Token for the render server.
93 *          port        Port to listen to accept connections.
94 *          cmd         Command to be run to start the render server.
95 *          environ     Name-value pairs of representing environment
96 *                      variables.
97 *
98 *      Note that "cmd" and "environ" are variable and backslash
99 *      substituted.  A listener socket automatically is established on
100 *      the given port to accept client requests.
101 *
102 *      Example:
103 *
104 *          register_server myServer 12345 ?switches? {
105 *               /path/to/myserver arg arg
106 *          } {
107 *               LD_LIBRARY_PATH $libdir/myServer
108 *          }
109 *
110 */
111static int
112RegisterServerCmd(ClientData clientData, Tcl_Interp *interp, int objc,
113                  Tcl_Obj *const *objv)
114{
115    Tcl_Obj *objPtr;
116    const char *serverName;
117    int numCmdArgs, numEnvArgs;
118    char *const *cmdArgs;
119    char *const *envArgs;
120    RenderServer *serverPtr;
121
122    if (objc < 4) {
123        Tcl_AppendResult(interp, "wrong # args: should be \"",
124                         Tcl_GetString(objv[0]),
125                         " serverName port ?flags? cmd ?environ?",
126                         (char *)NULL);
127        return TCL_ERROR;
128    }
129    serverName = Tcl_GetString(objv[1]);
130    if (*s_numServers+1 >= MAX_SERVERS) {
131        Tcl_AppendResult(interp, "Too many servers in configuration", (char *)NULL);
132        return TCL_ERROR;
133    }
134    serverPtr = NewServer(serverName);
135    if (serverPtr == NULL) {
136        Tcl_AppendResult(interp, "Can't allocate a server entry", (char *)NULL);
137        return TCL_ERROR;
138    }
139    if (Tcl_GetIntFromObj(interp, objv[2], &serverPtr->port) != TCL_OK) {
140        Tcl_AppendResult(interp, "Can't parse port number", (char *)NULL);
141        goto error;
142    }
143
144    INFO("Registering \"%s\" server on port %d", serverPtr->name, serverPtr->port);
145    (*s_numServers)++;
146    s_serverTable[*s_numServers-1] = serverPtr;
147
148    if (ParseSwitches(interp, serverPtr, &objc, (Tcl_Obj ***)&objv) != TCL_OK) {
149        goto error;
150    }
151    objPtr = Tcl_SubstObj(interp, objv[3],
152                          TCL_SUBST_VARIABLES | TCL_SUBST_BACKSLASHES);
153    if (Tcl_SplitList(interp, Tcl_GetString(objPtr), &numCmdArgs,
154        (const char ***)&cmdArgs) != TCL_OK) {
155        goto error;
156    }
157    serverPtr->cmdArgs = cmdArgs;
158    serverPtr->numCmdArgs = numCmdArgs;
159
160    numEnvArgs = 0;
161    envArgs = NULL;
162    if (objc == 5) {
163        objPtr = Tcl_SubstObj(interp, objv[4],
164                              TCL_SUBST_VARIABLES | TCL_SUBST_BACKSLASHES);
165        if (Tcl_SplitList(interp, Tcl_GetString(objPtr), &numEnvArgs,
166                (const char ***)&envArgs) != TCL_OK) {
167            goto error;
168        }
169        if (numEnvArgs & 0x1) {
170            Tcl_AppendResult(interp, "odd # elements in environment list",
171                             (char *)NULL);
172            goto error;
173        }
174    }
175    serverPtr->envArgs = envArgs;
176    serverPtr->numEnvArgs = numEnvArgs;
177
178    return TCL_OK;
179 error:
180    free(serverPtr);
181    return TCL_ERROR;
182}
183
184char *MergeArgs(int numCmdArgs, char *const *cmdArgs)
185{
186    return Tcl_Merge(numCmdArgs, (const char *const *)cmdArgs);
187}
188
189void FreeArgs(char *cmd)
190{
191    Tcl_Free(cmd);
192}
193
194int
195ParseServersFile(const char *fileName, int *numServers, RenderServer **serverTable)
196{
197    Tcl_Interp *interp;
198
199    s_numServers = numServers;
200    s_serverTable = serverTable;
201
202    interp = Tcl_CreateInterp();
203    Tcl_MakeSafe(interp);
204    Tcl_CreateObjCommand(interp, "register_server", RegisterServerCmd, NULL,
205                         NULL);
206    if (Tcl_EvalFile(interp, fileName) != TCL_OK) {
207        ERROR("Can't add server: %s", Tcl_GetString(Tcl_GetObjResult(interp)));
208        return FALSE;
209    }
210
211    Tcl_DeleteInterp(interp);
212    return TRUE;
213}
Note: See TracBrowser for help on using the repository browser.