#include #include #include #include #include "trick/MSSocket.hh" #include "trick/Master.hh" #include "trick/tc_proto.h" #include "trick/exec_proto.h" #include "trick/command_line_protos.h" Trick::MSSocket::MSSocket() : tc_dev() { tc_dev.disabled = TC_COMM_FALSE ; tc_dev.error_handler = NULL ; tc_dev.blockio_type = TC_COMM_TIMED_BLOCKIO ; tc_dev.blockio_type = TC_COMM_BLOCKIO ; tc_dev.port = 0 ; // tc_multiconnect needs this so that it will send broadcast msg ! // default is a non-zero sync wait limit; helpful when slave reading initial data from master sync_wait_limit = 5.0 ; } int Trick::MSSocket::set_sync_wait_limit(double in_limit) { /** @par Detailed Design */ sync_wait_limit = in_limit ; if ( in_limit > 0.0 ) { /** @li if the incoming limit time is greater than zero, set the socket to TC_COMM_TIMED_BLOCKIO with the time limit of in_limit */ tc_blockio(&tc_dev, TC_COMM_TIMED_BLOCKIO); tc_set_blockio_timeout_limit(&tc_dev, sync_wait_limit); } else { /** @li if the incoming limit time is less than or equal to zero, set the socket to TC_COMM_BLOCKIO (infinite block) */ tc_blockio(&tc_dev, TC_COMM_BLOCKIO); } return(0) ; } std::string Trick::MSSocket::add_sim_args( std::string slave_type ) { char master_host[80]; std::stringstream temp_stream ; /** @par Detailed Design */ /** @li create a unique identifier based on the _. */ gethostname(master_host, (size_t) 80); /** @li if master is running with dmtcp slave or vice versa, use "_dmtcp_multiconnect_tag" for sync_port_tag. on restart, dmtcp will retain original slave pid, which will not match restarted master pid. sync_port_tag must match for master and slave(s) to connect/reconnect via tc_multiconnect() */ if (slave_type == "dmtcp") temp_stream << master_host << "_dmtcp_multiconnect_tag" ; else temp_stream << master_host << "_" << getpid() ; sync_port_tag = temp_stream.str() ; /** @li return the unique identifier with the "-p" argument that is specific to master/slave communications. */ return("-p " + temp_stream.str()) ; } int Trick::MSSocket::process_sim_args() { int ii ; int argc ; char ** argv ; argc = command_line_args_get_argc() ; argv = command_line_args_get_argv() ; /** @par Detailed Design */ /** @li search for the "-p" argument. If found get the master identifier as the next argument */ for (ii = 2; ii < argc; ii++) { if (!strncmp("-p", argv[ii], (size_t) 2)) { if (argc >= ii + 1) { sync_port_tag = argv[ii+1] ; return(1) ; } } } return(0) ; } int Trick::MSSocket::accept() { int ret ; /** @par Detailed Design */ /** @li Call tc_multiconnect to connect this master. Use "master" as the my_tag argument */ ret = tc_multiconnect(&tc_dev, (char *)"master", (char *)sync_port_tag.c_str(), NULL); return(ret) ; } int Trick::MSSocket::connect() { int ret ; /** @par Detailed Design */ /** @li Call tc_multiconnect to connect this slave. Use "slave" as the my_tag argument */ ret = tc_multiconnect(&tc_dev, (char *)"slave", (char *)sync_port_tag.c_str(), NULL); return(ret) ; } int Trick::MSSocket::disconnect() { int ret; /** @par Detailed Design */ /** @li Call tc_disconnect to disconnect this device. */ ret = tc_disconnect( &tc_dev ); tc_dev.disabled = TC_COMM_FALSE ; tc_dev.error_handler = NULL ; tc_dev.blockio_type = TC_COMM_TIMED_BLOCKIO ; tc_dev.blockio_type = TC_COMM_BLOCKIO ; tc_dev.port = 0 ; return(ret); } long long Trick::MSSocket::read_time() { long long in_time = 0 ; int ret ; /** @par Detailed Design */ /** @li Call tc_read to get the time */ ret = tc_read(&tc_dev , (char *)&in_time, sizeof(long long)); /** @li If the read call returned the correct number of bytes return the read in time */ if ( ret == sizeof(long long)) { return(in_time) ; } /** @li Else return the special "error" time */ return (MS_ERROR_TIME) ; } MS_SIM_COMMAND Trick::MSSocket::read_command() { MS_SIM_COMMAND command ; int ret ; /** @par Detailed Design */ /** @li Call tc_read to get the command */ ret = tc_read(&tc_dev , (char *)&command, sizeof(MS_SIM_COMMAND)); /** @li If the read call returned the correct number of bytes return the read in command */ if ( ret == sizeof(MS_SIM_COMMAND)) { return(command) ; } /** @li Else return ErrorCmd */ return(MS_ErrorCmd) ; } int Trick::MSSocket::read_port() { int in_port = 0 ; int ret ; /** @par Detailed Design */ /** @li Call tc_read to get the port number */ ret = tc_read(&tc_dev , (char *)&in_port, sizeof(int)); /** @li If the read call returned the correct number of bytes return the read in port */ if ( ret == sizeof(int)) { return(in_port) ; } /** @li Else return the special "error" port */ return (MS_ERROR_PORT) ; } char Trick::MSSocket::read_name(char * read_data, size_t size) { int ret ; /** @par Detailed Design */ /** @li Call tc_read to get the name (character array) */ ret = tc_read(&tc_dev , (char *)read_data, (int)size); /** @li If the read call returned the correct number of bytes return 1st character read */ if ( ret == int(size)) { return(read_data[0]) ; } /** @li Else return the special "error" name character */ return (MS_ERROR_NAME) ; } int Trick::MSSocket::write_time(long long in_time) { int ret ; /** @par Detailed Design */ /** @li Call tc_write to write the time */ ret = tc_write(&tc_dev , (char *)&in_time, sizeof(long long)); /** @li Return the number of bytes written */ return(ret) ; } int Trick::MSSocket::write_command(MS_SIM_COMMAND command) { int ret ; /** @par Detailed Design */ /** @li Call tc_write to write the command */ ret = tc_write(&tc_dev , (char *)&command, sizeof(unsigned int)); /** @li Return the number of bytes written */ return(ret) ; } int Trick::MSSocket::write_port(int in_port) { int ret ; /** @par Detailed Design */ /** @li Call tc_write to write the port number */ ret = tc_write(&tc_dev , (char *)&in_port, sizeof(int)); /** @li Return the number of bytes written */ return(ret) ; } int Trick::MSSocket::write_name(char * in_data, size_t size) { /** @par Detailed Design */ /** @li Call tc_write to write the name (character array) */ tc_write(&tc_dev , (char *)in_data, size); /** @li Return the number of bytes written */ return(size) ; }