Exemple #1
0
static void
vncspuNetLoggerInit(void)
{
#ifdef NETLOGGER
	if (vnc_spu.netlogger_url) {
		char *c;

		crDebug("VNC SPU: NetLogger URL: %s", vnc_spu.netlogger_url);
#if 0
		if (vnc_spu.netlogger_url) {
			/* XXX add unlink() wrapper to Cr util package */
			unlink(vnc_spu.netlogger_url);
		}
#endif
		NL_logger_module("vncspu", /* module name */
										 vnc_spu.netlogger_url,
										 NL_LVL_DEBUG, /* logging level */
										 NL_TYPE_APP, /* target type */
										 "" /* terminator */
										 );
		NL_info("vncspu", "spu.program.begin", "");

		vnc_spu.hostname = crAlloc(101);
		crGetHostname(vnc_spu.hostname, 100);
		/* truncate at first dot */
		if ((c = crStrchr(vnc_spu.hostname, '.')))
			*c = 0;
	}
	else {
		crDebug("VNC SPU: NetLogger disabled");
	}
#endif
}
Exemple #2
0
/* Called by OpenGL faker library to identify itself to the mothership */
void crMothershipIdentifyOpenGL( CRConnection *conn, char *response, const char *app_id )
{
	char hostname[1024];
	if ( crGetHostname( hostname, sizeof(hostname) ) )
	{
		crError( "Couldn't get my own hostname?" );
	}
	/* This returns the client's SPU chain, if nothing goes wrong */
	INSIST( crMothershipSendString( conn, response, "opengldll %s %s", app_id, hostname ));
}
Exemple #3
0
/**
 * Helper function for below.
 */
static void
crMothershipIdentifySelf(const char *type, CRConnection *conn, char *response)
{
	char hostname[1024];
	if ( crGetHostname( hostname, sizeof(hostname) ) )
	{
		crError( "Couldn't get my own hostname?" );
	}
	crMothershipIdentify(type, hostname, conn, response);
}
Exemple #4
0
void crServerSetVBoxConfiguration()
{
    CRMuralInfo *defaultMural;
    char response[8096];

    char **spuchain;
    int num_spus;
    int *spu_ids;
    char **spu_names;
    char *spu_dir = NULL;
    int i;
    /* Quadrics defaults */
    int my_rank = 0;
    int low_context = CR_QUADRICS_DEFAULT_LOW_CONTEXT;
    int high_context = CR_QUADRICS_DEFAULT_HIGH_CONTEXT;
    unsigned char key[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    char hostname[1024];
    char **clientchain, **clientlist;
    GLint dims[4];
    const char * env;

    defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0);
    CRASSERT(defaultMural);

    setDefaults();

    /*
     * Get my hostname
     */
    if (crGetHostname(hostname, sizeof(hostname)))
    {
        crError("CRServer: Couldn't get my own hostname?");
    }

    strcpy(response, "1 0 render");
    crDebug("CRServer: my SPU chain: %s", response);

    /* response will describe the SPU chain.
     * Example "2 5 wet 6 render"
     */
    spuchain = crStrSplit(response, " ");
    num_spus = crStrToInt(spuchain[0]);
    spu_ids = (int *) crAlloc(num_spus * sizeof(*spu_ids));
    spu_names = (char **) crAlloc((num_spus + 1) * sizeof(*spu_names));
    for (i = 0; i < num_spus; i++)
    {
        spu_ids[i] = crStrToInt(spuchain[2 * i + 1]);
        spu_names[i] = crStrdup(spuchain[2 * i + 2]);
        crDebug("SPU %d/%d: (%d) \"%s\"", i + 1, num_spus, spu_ids[i],
                        spu_names[i]);
    }
    spu_names[i] = NULL;

    //spu_dir = crStrdup(response);
    crNetSetRank(0);
    crNetSetContextRange(32, 35);
    crNetSetNodeRange("iam0", "iamvis20");
    crNetSetKey(key,sizeof(key));
    crNetSetKey(key,sizeof(key));
    cr_server.tcpip_port = 7000;

        /*cr_server.optimizeBucket = crStrToInt(response);
        cr_server.localTileSpec = crStrToInt(response);
        cr_server.useL2 = crStrToInt(response);
        cr_server.ignore_papi = crStrToInt(response);
        if (crMothershipGetServerParam(conn, response, "overlap_blending"))
        {
            if (!crStrcmp(response, "blend"))
                cr_server.overlapBlending = 1;
            else if (!crStrcmp(response, "knockout"))
                cr_server.overlapBlending = 2;
        }
        if (crMothershipGetServerParam(conn, response, "overlap_levels"))
        cr_server.only_swap_once = crStrToInt(response);
        cr_server.debug_barriers = crStrToInt(response);
        cr_server.sharedDisplayLists = crStrToInt(response);
        cr_server.sharedTextureObjects = crStrToInt(response);
        cr_server.sharedPrograms = crStrToInt(response);
        cr_server.sharedWindows = crStrToInt(response);
        cr_server.uniqueWindows = crStrToInt(response);
        cr_server.useDMX = crStrToInt(response);
        if (crMothershipGetServerParam(conn, response, "vertprog_projection_param"))
        if (crMothershipGetServerParam(conn, response, "stereo_view"))
        if (crMothershipGetServerParam(conn, response, "view_matrix"))
        if (crMothershipGetServerParam(conn, response, "right_view_matrix"))
        if (crMothershipGetServerParam(conn, response, "projection_matrix"))
        if (crMothershipGetServerParam(conn, response, "right_projection_matrix"))*/

    crDebug("CRServer: my port number is %d", cr_server.tcpip_port);

    /*
     * Load the SPUs
     */
    cr_server.head_spu =
        crSPULoadChain(num_spus, spu_ids, spu_names, spu_dir, &cr_server);

    env = crGetenv( "CR_SERVER_DEFAULT_RENDER_TYPE" );
    if (env != NULL)
    {
        GLubyte redir = (env[0] - 0x30);
        if (redir <= CR_SERVER_REDIR_MAXVAL)
        {
            int rc = crServerSetOffscreenRenderingMode(redir);
            if (!RT_SUCCESS(rc))
                crWarning("offscreen rendering unsupported, no offscreen rendering will be used..");
        }
        else
            crWarning("invalid redir option %c", redir);
    }
#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS) || defined(GLX)
    else
    {
        int rc = crServerSetOffscreenRenderingMode(CR_SERVER_REDIR_FBO_BLT);
        if (!RT_SUCCESS(rc))
            crWarning("offscreen rendering unsupported, no offscreen rendering will be used..");

    }
#endif
    cr_server.bOffscreenRenderingDefault = cr_server.bForceOffscreenRendering;

    /* Need to do this as early as possible */

    cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_POSITION_CR, 0, GL_INT, 2, &dims[0]);
    cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, 0, GL_INT, 2, &dims[2]);
    
    defaultMural->gX = dims[0];
    defaultMural->gY = dims[1];
    defaultMural->width = dims[2];
    defaultMural->height = dims[3];

    crFree(spu_ids);
    crFreeStrings(spu_names);
    crFreeStrings(spuchain);
    if (spu_dir)
        crFree(spu_dir);

    cr_server.mtu = 1024 * 30;

    /*
     * Get a list of all the clients talking to me.
     */
    if (cr_server.vncMode) {
        /* we're inside a vnc viewer */
        /*if (!crMothershipSendString( conn, response, "getvncclient %s", hostname ))
            crError( "Bad Mothership response: %s", response );*/
    }
    else {
        //crMothershipGetClients(conn, response);
        strcpy(response, "1 tcpip 1");
    }

    crDebug("CRServer: my clients: %s", response);

    /*
     * 'response' will now contain a number indicating the number of clients
     * of this server, followed by a comma-separated list of protocol/SPU ID
     * pairs.
     * Example: "3 tcpip 1,gm 2,via 10"
     */
    clientchain = crStrSplitn(response, " ", 1);
    cr_server.numClients = crStrToInt(clientchain[0]);
    if (cr_server.numClients == 0)
    {
        crError("I have no clients!  What's a poor server to do?");
    }
    clientlist = crStrSplit(clientchain[1], ",");

    /*
     * Connect to initial set of clients.
     * Call crNetAcceptClient() for each client.
     * Also, look for a client that's _not_ using the file: protocol.
     */
    for (i = 0; i < cr_server.numClients; i++)
    {
        CRClient *newClient = (CRClient *) crCalloc(sizeof(CRClient));
#ifdef VBOX
        sscanf(clientlist[i], "%1023s %d", cr_server.protocol, &(newClient->spu_id));
#else
        sscanf(clientlist[i], "%s %d", cr_server.protocol, &(newClient->spu_id));
#endif
        newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
                                            cr_server.tcpip_port,
                                            cr_server.mtu, 0);
        newClient->currentCtxInfo = &cr_server.MainContextInfo;
        crServerAddToRunQueue(newClient);

        cr_server.clients[i] = newClient;
    }

    /* set default client and mural */
    if (cr_server.numClients > 0) {
         cr_server.curClient = cr_server.clients[0];
         cr_server.curClient->currentMural = defaultMural;
         cr_server.client_spu_id =cr_server.clients[0]->spu_id;
    }

    crFreeStrings(clientchain);
    crFreeStrings(clientlist);

    /* Ask the mothership for the tile info */
    //crServerGetTileInfoFromMothership(conn, defaultMural);

    if (cr_server.vncMode) {
        /* In vnc mode, we reset the mothership configuration so that it can be
         * used by subsequent OpenGL apps without having to spawn a new mothership
         * on a new port.
         */
        crDebug("CRServer: Resetting mothership to initial state");
        //crMothershipReset(conn);
    }

    //crMothershipDisconnect(conn);
}
Exemple #5
0
/**
 * Establish a connection with a server.
 * \param server  the server to connect to, in the form
 *                "protocol://servername:port" where the port specifier
 *                is optional and if the protocol is missing it is assumed
 *                to be "tcpip".
 * \param default_port  the port to connect to, if port not specified in the
 *                      server URL string.
 * \param mtu  desired maximum transmission unit size (in bytes)
 * \param broker  either 1 or 0 to indicate if connection is brokered through
 *                the mothership
 */
CRConnection * crNetConnectToServer( const char *server, unsigned short default_port, int mtu, int broker
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
                , struct VBOXUHGSMI *pHgsmi
#endif
)
{
    char hostname[4096], protocol[4096];
    unsigned short port;
    CRConnection *conn;

    crDebug( "In crNetConnectToServer( \"%s\", port=%d, mtu=%d, broker=%d )",
                     server, default_port, mtu, broker );

    CRASSERT( cr_net.initialized );

    if (mtu < CR_MINIMUM_MTU)
    {
        crError( "You tried to connect to server \"%s\" with an mtu of %d, "
                         "but the minimum MTU is %d", server, mtu, CR_MINIMUM_MTU );
    }

    /* Tear the URL apart into relevant portions. */
    if ( !crParseURL( server, protocol, hostname, &port, default_port ) ) {
         crError( "Malformed URL: \"%s\"", server );
    }

    /* If the host name is "localhost" replace it with the _real_ name
     * of the localhost.  If we don't do this, there seems to be
     * confusion in the mothership as to whether or not "localhost" and
     * "foo.bar.com" are the same machine.
     */
    if (crStrcmp(hostname, "localhost") == 0) {
        int rv = crGetHostname(hostname, 4096);
        CRASSERT(rv == 0);
        (void) rv;
    }

    /* XXX why is this here???  I think it could be moved into the
     * crTeacConnection() function with no problem. I.e. change the
     * connection's port, teac_rank and tcscomm_rank there.  (BrianP)
     */
    if ( !crStrcmp( protocol, "quadrics" ) ||
         !crStrcmp( protocol, "quadrics-tcscomm" ) ) {
      /* For Quadrics protocols, treat "port" as "rank" */
      if ( port > CR_QUADRICS_HIGHEST_RANK ) {
        crWarning( "Invalid crserver rank, %d, defaulting to %d\n",
               port, CR_QUADRICS_LOWEST_RANK );
        port = CR_QUADRICS_LOWEST_RANK;
      }
    }
    crDebug( "Connecting to %s on port %d, with protocol %s",
                     hostname, port, protocol );

#ifdef SDP_SUPPORT
    /* This makes me ill, but we need to "fix" the hostname for sdp. MCH */
    if (!crStrcmp(protocol, "sdp")) {
        char* temp;
        temp = strtok(hostname, ".");
        crStrcat(temp, crGetSDPHostnameSuffix());
        crStrcpy(hostname, temp);
        crDebug("SDP rename hostname: %s", hostname);    
    }
#endif

    conn = (CRConnection *) crCalloc( sizeof(*conn) );
    if (!conn)
        return NULL;

    /* init the non-zero fields */
    conn->type               = CR_NO_CONNECTION; /* we don't know yet */
    conn->recv_credits       = CR_INITIAL_RECV_CREDITS;
    conn->hostname           = crStrdup( hostname );
    conn->port               = port;
    conn->mtu                = mtu;
    conn->buffer_size        = mtu;
    conn->broker             = broker;
    conn->endianness         = crDetermineEndianness();
    /* XXX why are these here??? Move them into the crTeacConnection()
     * and crTcscommConnection() functions.
     */
    conn->teac_id            = -1;
    conn->teac_rank          = port;
    conn->tcscomm_id         = -1;
    conn->tcscomm_rank       = port;

    crInitMessageList(&conn->messageList);

    /* now, just dispatch to the appropriate protocol's initialization functions. */
    InitConnection(conn, protocol, mtu
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
                , pHgsmi
#endif
            );

    if (!crNetConnect( conn ))
    {
        crDebug("crNetConnectToServer() failed, freeing the connection");
        #ifdef CHROMIUM_THREADSAFE
            crFreeMutex( &conn->messageList.lock );
        #endif
        conn->Disconnect(conn);
        crFree( conn );
        return NULL;
    }

    crDebug( "Done connecting to %s (swapping=%d)", server, conn->swap );
    return conn;
}
Exemple #6
0
static void
crSDPAccept( CRConnection *conn, const char *hostname, unsigned short port )
{
	int err;
	socklen_t		addr_length;
	struct sockaddr_in	servaddr;
	struct sockaddr		addr;
	struct hostent		*host;
	struct in_addr		sin_addr;

	if (port != last_port)
	{
	     /* with the new OOB stuff, we can have multiple ports being 
	      * accepted on, so we need to redo the server socket every time.
	      */
		cr_sdp.server_sock = socket( AF_INET_SDP, SOCK_STREAM, 0 );
		if ( cr_sdp.server_sock == -1 )
		{
			err = crSDPErrno( );
			crError( "Couldn't create socket: %s", crSDPErrorString( err ) );
		}
		spankSocket( cr_sdp.server_sock );

		servaddr.sin_family = AF_INET;
		servaddr.sin_addr.s_addr = INADDR_ANY;
		servaddr.sin_port = htons( port );

		if ( bind( cr_sdp.server_sock, (struct sockaddr *) &servaddr, sizeof(servaddr) ) )
		{
			err = crSDPErrno( );
			crError( "Couldn't bind to socket (port=%d): %s", port, crSDPErrorString( err ) );
		}
		last_port = port;
		if ( listen( cr_sdp.server_sock, 100 /* max pending connections */ ) )
		{
			err = crSDPErrno( );
			crError( "Couldn't listen on socket: %s", crSDPErrorString( err ) );
		}
	}
	
	if (conn->broker)
	{
		CRConnection *mother;
		char response[8096];
		char my_hostname[256];
		char *temp;
		mother = __copy_of_crMothershipConnect( );
    
		if (!hostname)
		{
			if ( crGetHostname( my_hostname, sizeof( my_hostname ) ) )
			{
				crError( "Couldn't determine my own hostname in crSDPAccept!" );
			}
		}
		else
			crStrcpy(my_hostname, hostname);
    
		/* Hack hostname, YUCK!!! */
		temp = strtok(my_hostname, ".");
		crStrcat(temp, crGetSDPHostnameSuffix());
		(void) temp;
		if (!__copy_of_crMothershipSendString( mother, response, "acceptrequest sdp %s %d %d", temp, conn->port, conn->endianness ) )
		{
			crError( "Mothership didn't like my accept request" );
		}
    
		__copy_of_crMothershipDisconnect( mother );
    
		sscanf( response, "%u", &(conn->id) );
	}
	
	addr_length =	sizeof( addr );
	conn->sdp_socket = accept( cr_sdp.server_sock, (struct sockaddr *) &addr, &addr_length );
	if (conn->sdp_socket == -1)
	{
		err = crSDPErrno( );
		crError( "Couldn't accept client: %s", crSDPErrorString( err ) );
	}
	
	sin_addr = ((struct sockaddr_in *) &addr)->sin_addr;
	host = gethostbyaddr( (char *) &sin_addr, sizeof( sin_addr), AF_INET_SDP );
	if (host == NULL )
	{
		char *temp = inet_ntoa( sin_addr );
		conn->hostname = crStrdup( temp );
	}
	else
	{
		char *temp;
		conn->hostname = crStrdup( host->h_name );
    
		temp = conn->hostname;
		while (*temp && *temp != '.' )
			temp++;
		*temp = '\0';
	}
	
#ifdef RECV_BAIL_OUT 
	err = sizeof(unsigned int);
	if ( getsockopt( conn->sdp_socket, SOL_SOCKET, SO_RCVBUF,
									 (char *) &conn->krecv_buf_size, &err ) )
	{
		conn->krecv_buf_size = 0;	
	}
#endif
	crDebug( "Accepted connection from \"%s\".", conn->hostname );
}
Exemple #7
0
void
crServerGatherConfiguration(char *mothership)
{
	CRMuralInfo *defaultMural;
	CRConnection *conn;
	char response[8096];

	char **spuchain;
	int num_spus;
	int *spu_ids;
	char **spu_names;
	char *spu_dir = NULL;
	int i;
	/* Quadrics defaults */
	int my_rank = 0;
	int low_context = CR_QUADRICS_DEFAULT_LOW_CONTEXT;
	int high_context = CR_QUADRICS_DEFAULT_HIGH_CONTEXT;
	char *low_node = "none";
	char *high_node = "none";
	unsigned char key[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
	char hostname[1024];
	char **clientchain, **clientlist;

	defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0);
	CRASSERT(defaultMural);

	setDefaults();

	if (mothership)
	{
		crSetenv("CRMOTHERSHIP", mothership);
	}

	conn = crMothershipConnect();
	if (!conn)
	{
		crError("Couldn't connect to the mothership, I have no idea what to do!");
	}

	/*
	 * Get my hostname
	 */
	if (crGetHostname(hostname, sizeof(hostname)))
	{
		crError("CRServer: Couldn't get my own hostname?");
	}

	/* Identify ourselves to the mothership */
	if (cr_server.vncMode) {
		/* we're running inside a vnc viewer */
		if (!crMothershipSendString( conn, response, "vncserver %s", hostname ))
			crError( "Bad Mothership response: %s", response );
	}
	else {
		crMothershipIdentifyServer(conn, response);
	}

	crDebug("CRServer: my SPU chain: %s", response);

	/* response will describe the SPU chain.
	 * Example "2 5 wet 6 render"
	 */
	spuchain = crStrSplit(response, " ");
	num_spus = crStrToInt(spuchain[0]);
	spu_ids = (int *) crAlloc(num_spus * sizeof(*spu_ids));
	spu_names = (char **) crAlloc((num_spus + 1) * sizeof(*spu_names));
	for (i = 0; i < num_spus; i++)
	{
		spu_ids[i] = crStrToInt(spuchain[2 * i + 1]);
		spu_names[i] = crStrdup(spuchain[2 * i + 2]);
		crDebug("SPU %d/%d: (%d) \"%s\"", i + 1, num_spus, spu_ids[i],
						spu_names[i]);
	}
	spu_names[i] = NULL;

	/*
	 * Gather configuration options.
	 * NOTE:  when you add new options, be sure to update the
	 * mothership/tools/crtypes.py file's NetworkNode class's notion of
	 * config options.
	 * XXX Use the SPU option parser code here someday.
	 */
	if (crMothershipGetServerParam( conn, response, "spu_dir" ) && crStrlen(response) > 0)
	{
		spu_dir = crStrdup(response);
	}

	/* Quadrics networking stuff */
	if (crMothershipGetRank(conn, response))
	{
		my_rank = crStrToInt(response);
	}
	crNetSetRank(my_rank);

	if (crMothershipGetParam(conn, "low_context", response))
	{
		low_context = crStrToInt(response);
	}
	if (crMothershipGetParam(conn, "high_context", response))
	{
		high_context = crStrToInt(response);
	}
	crNetSetContextRange(low_context, high_context);

	if (crMothershipGetParam(conn, "low_node", response))
	{
		low_node = crStrdup(response);
	}
	if (crMothershipGetParam(conn, "high_node", response))
	{
		high_node = crStrdup(response);
	}
	crNetSetNodeRange(low_node, high_node);
	if (low_node)
		crFree(low_node);
	if (high_node)
		crFree(high_node);
	if (crMothershipGetParam(conn, "comm_key", response))
	{
	  unsigned int a;
	  char **words, *found;
	  
	  /* remove the silly []'s */
	  while ((found = crStrchr(response, '[')) != NULL)
	    *found = ' ';
	  while ((found = crStrchr(response, ']')) != NULL)
	    *found = ' ';
	  
	  words = crStrSplit(response, ",");
	  
	  a = 0;
	  while (words[a] != NULL && a < sizeof(key)) {
			key[a]= crStrToInt(words[a]);
			a++;
		}
	  
	  crFreeStrings(words);
	}
	crNetSetKey(key,sizeof(key));

	if (crMothershipGetServerParam(conn, response, "port"))
	{
		cr_server.tcpip_port = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "optimize_bucket"))
	{
		cr_server.optimizeBucket = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "local_tile_spec"))
	{
		cr_server.localTileSpec = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "lightning2"))
	{
		cr_server.useL2 = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "ignore_papi"))
	{
		cr_server.ignore_papi = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "overlap_blending"))
	{
		if (!crStrcmp(response, "blend"))
			cr_server.overlapBlending = 1;
		else if (!crStrcmp(response, "knockout"))
			cr_server.overlapBlending = 2;
	}
	if (crMothershipGetServerParam(conn, response, "overlap_levels"))
	{
		int a;
		char **levels, *found;

		/* remove the []'s */
		while ((found = crStrchr(response, '[')))
			*found = ' ';
		while ((found = crStrchr(response, ']')))
			*found = ' ';

		levels = crStrSplit(response, ",");

		a = 0;
		while (levels[a] != NULL)
		{
			crDebug("%d: %s", a, levels[a]);
			cr_server.num_overlap_intens++;
			a++;
		}

		cr_server.overlap_intens = (float *)crAlloc(cr_server.num_overlap_intens*sizeof(float));
		for (a=0; a<cr_server.num_overlap_intens; a++)
			cr_server.overlap_intens[a] = crStrToFloat(levels[a]);

		crFreeStrings(levels);
	}
	if (crMothershipGetServerParam(conn, response, "only_swap_once"))
	{
		cr_server.only_swap_once = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "debug_barriers"))
	{
		cr_server.debug_barriers = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "shared_display_lists"))
	{
		cr_server.sharedDisplayLists = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "shared_texture_objects"))
	{
		cr_server.sharedTextureObjects = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "shared_programs"))
	{
		cr_server.sharedPrograms = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "shared_windows"))
	{
		cr_server.sharedWindows = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "unique_window_ids"))
	{
		cr_server.uniqueWindows = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "use_dmx"))
	{
		cr_server.useDMX = crStrToInt(response);
	}
	if (crMothershipGetServerParam(conn, response, "vertprog_projection_param"))
	{
		if (crIsDigit(response[0])) {
			cr_server.vpProjectionMatrixParameter = crStrToInt(response);
		}
		else {
			cr_server.vpProjectionMatrixVariable = crStrdup(response);
		}
	}
	if (crMothershipGetServerParam(conn, response, "stereo_view"))
	{
		if (crStrcmp(response, "left") == 0)
			cr_server.stereoView = 0x1;
		else if (crStrcmp(response, "right") == 0)
			cr_server.stereoView = 0x2;
		else if (crStrcmp(response, "both") == 0)
			cr_server.stereoView = 0x3;
		else
			cr_server.stereoView = 0x3;
	}
	if (crMothershipGetServerParam(conn, response, "view_matrix"))
	{
		crMatrixInitFromString(&cr_server.viewMatrix[0], response);
		cr_server.viewOverride = GL_TRUE;
	}
	if (crMothershipGetServerParam(conn, response, "right_view_matrix"))
	{
		crMatrixInitFromString(&cr_server.viewMatrix[1], response);
		cr_server.viewOverride = GL_TRUE;
	}

	if (crMothershipGetServerParam(conn, response, "projection_matrix"))
	{
		crMatrixInitFromString(&cr_server.projectionMatrix[0], response);
		cr_server.projectionOverride = GL_TRUE;
	}
	if (crMothershipGetServerParam(conn, response, "right_projection_matrix"))
	{
		crMatrixInitFromString(&cr_server.projectionMatrix[1], response);
		cr_server.projectionOverride = GL_TRUE;
	}

	if (crMothershipGetServerParam(conn, response, "exit_if_no_clients"))
	{
		cr_server.exitIfNoClients = crStrToInt(response);
	}


	crDebug("CRServer: my port number is %d", cr_server.tcpip_port);

	/*
	 * Load the SPUs
	 */
	cr_server.head_spu =
		crSPULoadChain(num_spus, spu_ids, spu_names, spu_dir, &cr_server);

	/* Need to do this as early as possible */

	/* XXX DMX get window size instead? */
	cr_server.head_spu->dispatch_table.GetIntegerv(GL_VIEWPORT,
															 (GLint *) defaultMural->underlyingDisplay);

	crFree(spu_ids);
	crFreeStrings(spu_names);
	crFreeStrings(spuchain);
	if (spu_dir)
		crFree(spu_dir);

	cr_server.mtu = crMothershipGetMTU( conn );

	/*
	 * Get a list of all the clients talking to me.
	 */
	if (cr_server.vncMode) {
		/* we're inside a vnc viewer */
		if (!crMothershipSendString( conn, response, "getvncclient %s", hostname ))
			crError( "Bad Mothership response: %s", response );
	}
	else {
		crMothershipGetClients(conn, response);
	}

	crDebug("CRServer: my clients: %s", response);

	/*
	 * 'response' will now contain a number indicating the number of clients
	 * of this server, followed by a comma-separated list of protocol/SPU ID
	 * pairs.
	 * Example: "3 tcpip 1,gm 2,via 10"
	 */
	clientchain = crStrSplitn(response, " ", 1);
	cr_server.numClients = crStrToInt(clientchain[0]);
	if (cr_server.numClients == 0)
	{
		crError("I have no clients!  What's a poor server to do?");
	}
	clientlist = crStrSplit(clientchain[1], ",");

	/*
	 * Connect to initial set of clients.
	 * Call crNetAcceptClient() for each client.
	 * Also, look for a client that's _not_ using the file: protocol.
	 */
	for (i = 0; i < cr_server.numClients; i++)
	{
		CRClient *newClient = (CRClient *) crCalloc(sizeof(CRClient));
		sscanf(clientlist[i], "%s %d", cr_server.protocol, &(newClient->spu_id));
		newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
																				cr_server.tcpip_port,
																				cr_server.mtu, 1);
		newClient->currentCtx = cr_server.DummyContext;
		crServerAddToRunQueue(newClient);

		cr_server.clients[i] = newClient;
	}

	/* set default client and mural */
	if (cr_server.numClients > 0) {
		 cr_server.curClient = cr_server.clients[0];
		 cr_server.curClient->currentMural = defaultMural;
		 cr_server.client_spu_id =cr_server.clients[0]->spu_id;
	}

	crFreeStrings(clientchain);
	crFreeStrings(clientlist);

	/* Ask the mothership for the tile info */
	crServerGetTileInfoFromMothership(conn, defaultMural);

	if (cr_server.vncMode) {
		/* In vnc mode, we reset the mothership configuration so that it can be
		 * used by subsequent OpenGL apps without having to spawn a new mothership
		 * on a new port.
		 */
		crDebug("CRServer: Resetting mothership to initial state");
		crMothershipReset(conn);
	}

	crMothershipDisconnect(conn);
}