int tcp_socket_channel_init( comm_channel_t *channel, socket_type_t type, char *addr, int port ) { tcp_connection_t *tc = tcp_get_connection( channel ); if( !tc ) { return( -1 ); } switch( type ) { case SOCK_SERVER: return server_socket_init( tc, port ); case SOCK_CLIENT: channel->transmit = client_socket_transmit; channel->receive = client_socket_receive; return client_socket_init( tc, addr, port ); default: fprintf( stderr, "ERROR in %s %d: unknown socket type\n", __FILE__, __LINE__ ); } return( -1 ); }
/** * This function is used as a the start function for the slave renderer thread. * It pulls a request from the central queue of requests and dispatches it to * the slave renderer. It then blocks and waits for the response with no timeout. * As it only sends one request at a time (there are as many slave_thread threads as there * are rendering threads on the slaves) nothing gets queued on the slave and should get * rendererd immediately. Thus overall, requests should be nicely load balanced between * all the rendering threads available both locally and in the slaves. */ void *slave_thread(void * arg) { renderd_config * sConfig = (renderd_config *) arg; int pfd = FD_INVALID; int retry; size_t ret_size; struct protocol * resp; struct protocol * req_slave; req_slave = (struct protocol *)malloc(sizeof(struct protocol)); resp = (struct protocol *)malloc(sizeof(struct protocol)); bzero(req_slave, sizeof(struct protocol)); bzero(resp, sizeof(struct protocol)); while (1) { if (pfd == FD_INVALID) { pfd = client_socket_init(sConfig); if (pfd == FD_INVALID) { if (sConfig->ipport > 0) { syslog(LOG_ERR, "Failed to connect to render slave %s:%i, trying again in 30 seconds", sConfig->iphostname, sConfig->ipport); } else { syslog( LOG_ERR, "Failed to connect to render slave %s, trying again in 30 seconds", sConfig->socketname); } sleep(30); continue; } } enum protoCmd ret; struct item *item = fetch_request(); if (item) { struct protocol *req = &item->req; req_slave->ver = PROTO_VER; req_slave->cmd = cmdRender; strcpy(req_slave->xmlname, req->xmlname); req_slave->x = req->x; req_slave->y = req->y; req_slave->z = req->z; /*Dispatch request to slave renderd*/ retry = 2; syslog(LOG_INFO, "Dispatching request to slave thread on fd %i", pfd); do { ret_size = send(pfd, req_slave, sizeof(struct protocol), 0); if (ret_size == sizeof(struct protocol)) { //correctly sent command to slave break; } if (errno != EPIPE) { syslog(LOG_ERR, "Failed to send cmd to render slave, shutting down thread"); free(resp); free(req_slave); close(pfd); return NULL; } syslog(LOG_WARNING, "Failed to send cmd to render slave, retrying"); close(pfd); pfd = client_socket_init(sConfig); if (pfd == FD_INVALID) { syslog(LOG_ERR, "Failed to re-connect to render slave, dropping request"); ret = cmdNotDone; send_response(item, ret); break; } } while (retry--); if (pfd == FD_INVALID || ret_size != sizeof(struct protocol)) { continue; } ret_size = 0; retry = 10; while ((ret_size < sizeof(struct protocol)) && (retry > 0)) { ret_size = recv(pfd, resp + ret_size, (sizeof(struct protocol) - ret_size), 0); if ((errno == EPIPE) || ret_size == 0) { close(pfd); pfd = FD_INVALID; ret_size = 0; syslog(LOG_ERR, "Pipe to render slave closed"); break; } retry--; } if (ret_size < sizeof(struct protocol)) { if (sConfig->ipport > 0) { syslog( LOG_ERR, "Invalid reply from render slave %s:%i, trying again in 30 seconds", sConfig->iphostname, sConfig->ipport); } else { syslog( LOG_ERR, "Invalid reply render slave %s, trying again in 30 seconds", sConfig->socketname); } ret = cmdNotDone; send_response(item, ret); sleep(30); } else { ret = resp->cmd; send_response(item, ret); if (resp->cmd != cmdDone) { if (sConfig->ipport > 0) { syslog( LOG_ERR, "Request from render slave %s:%i did not complete correctly", sConfig->iphostname, sConfig->ipport); } else { syslog( LOG_ERR, "Request from render slave %s did not complete correctly", sConfig->socketname); } //Sleep for a while to make sure we don't overload the renderer //This only happens if it didn't correctly block on the rendering //request sleep(30); } } } else { sleep(1); // TODO: Use an event to indicate there are new requests } } free(resp); free(req_slave); return NULL; }