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 }
/* 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 )); }
/** * 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); }
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); }
/** * 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; }
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 ); }
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); }