static char* rep_str(char* instr) { char* beg = strchr(instr, '['); if (!beg) return instr; char* end = strchr(beg+1, ']'); for (size_t i = 0; i < sizeof(envvs)/sizeof(envvs[0]); i++){ if (end) *end = '\0'; if (strcmp(envvs[i], beg+1) != 0) continue; char* exp = arcan_expand_resource("", 1 << i); if (!exp) goto fail; if (!end){ *beg = '\0'; char* newstr = alloc_cat(instr, exp); free(instr); return newstr; } else{ *beg = '\0'; *end = '\0'; char* newstr = alloc_cat(instr, exp); free(instr); char* resstr = alloc_cat(newstr, end+1); free(newstr); return rep_str(resstr); } } fail: arcan_warning("expand failed, no match for supplied string (%s)\n", beg+1); return instr; }
static error forward_server_control_command( const std::string& _name, const std::string& _host, const std::string& _port_keyword, std::string& _output ) { if ( EMPTY_RESC_HOST == _host ) { return SUCCESS(); } int time_out = 0; error ret = get_server_property < int > ( CFG_SERVER_CONTROL_PLANE_TIMEOUT, time_out ); if ( !ret.ok() ) { return PASS( ret ); } int port = 0, num_hash_rounds = 0; std::string encryption_algorithm; buffer_crypt::array_t shared_secret; ret = get_server_properties( _port_keyword, port, num_hash_rounds, shared_secret, encryption_algorithm ); if ( !ret.ok() ) { return PASS( ret ); } // stringify the port std::stringstream port_sstr; port_sstr << port; // standard zmq rep-req communication pattern zmq::context_t zmq_ctx( 1 ); zmq::socket_t zmq_skt( zmq_ctx, ZMQ_REQ ); zmq_skt.setsockopt( ZMQ_RCVTIMEO, &time_out, sizeof( time_out ) ); zmq_skt.setsockopt( ZMQ_SNDTIMEO, &time_out, sizeof( time_out ) ); // this is the client so we connect rather than bind std::string conn_str( "tcp://" ); conn_str += _host; conn_str += ":"; conn_str += port_sstr.str(); try { zmq_skt.connect( conn_str.c_str() ); } catch ( zmq::error_t& e_ ) { std::string msg( "failed to connect to [" ); msg + conn_str + "]"; return ERROR( SYS_INVALID_INPUT_PARAM, msg ); } // build the command to forward control_plane_command cmd; cmd.command = _name; cmd.options[ SERVER_CONTROL_OPTION_KW ] = SERVER_CONTROL_HOSTS_OPT; cmd.options[ SERVER_CONTROL_HOST_KW ] = _host; // serialize using the generated avro class std::auto_ptr< avro::OutputStream > out = avro::memoryOutputStream(); avro::EncoderPtr e = avro::binaryEncoder(); e->init( *out ); avro::encode( *e, cmd ); boost::shared_ptr< std::vector< uint8_t > > data = avro::snapshot( *out ); buffer_crypt crypt( shared_secret.size(), // key size 0, // salt size ( we dont send a salt ) num_hash_rounds, // num hash rounds encryption_algorithm.c_str() ); buffer_crypt::array_t iv; buffer_crypt::array_t data_to_send; buffer_crypt::array_t data_to_encrypt( data->data(), data->data() + data->size() ); ret = crypt.encrypt( shared_secret, iv, data_to_encrypt, data_to_send ); if ( !ret.ok() ) { return PASS( ret ); } // copy binary encoding into a zmq message for transport zmq::message_t rep( data_to_send.size() ); memcpy( rep.data(), data_to_send.data(), data_to_send.size() ); zmq_skt.send( rep ); // wait for the server response zmq::message_t req; zmq_skt.recv( &req ); if ( 0 == req.size() ) { return ERROR( SYS_INVALID_INPUT_PARAM, "empty response string" ); } // decrypt the message before passing to avro buffer_crypt::array_t data_to_process; const uint8_t* data_ptr = static_cast< const uint8_t* >( req.data() ); buffer_crypt::array_t data_to_decrypt( data_ptr, data_ptr + req.size() ); ret = crypt.decrypt( shared_secret, iv, data_to_decrypt, data_to_process ); if ( !ret.ok() ) { irods::log( PASS( ret ) ); rodsLog( LOG_ERROR, "Failed to decrpyt [%s]", req.data() ); return PASS( ret ); } std::string rep_str( reinterpret_cast< char* >( data_to_process.data() ), data_to_process.size() ); if ( SERVER_CONTROL_SUCCESS != rep_str ) { // check if the result is really an error or a status if ( std::string::npos == rep_str.find( "[-]" ) ) { _output += rep_str; } else { return ERROR( CONTROL_PLANE_MESSAGE_ERROR, rep_str ); } } return SUCCESS(); } // forward_server_control_command