visual.tcl 4.81 KB
#!/morse/m3/bugnion/tcl-dp3.4b2/dpwish -f
#
# Copyright (C) 1996-1998 by the Board of Trustees
#    of Leland Stanford Junior University.
# 
# This file is part of the SimOS distribution. 
# See LICENSE file for terms of the license. 
#



#############################################################################
# visual
# 
# Connects to a simos process, opens up the data stream. Ready to accept RPCs.
#
# The rpc interface takes a Tcl-SimoS script and sends the return value back
# the visual shell. 
#
# Tcl-SimOS overloads the log command. logs that occur within the evaluation
# of an RPC script and during the interpreration of annotations that were
# installed by an RPC script will be written to a data stream handled by
# the visualization process. 
#
# The data stream output can be in the form of Tcl scripts too. These
# will be evaluated within the context of the visual process. 
# ProcessDataProc takes care of that
#
# ###########################################################################
proc visual {host port} { 
    global simosHost serverSocknum hostport  localSockNum localHost 
    global listen_sd control_sd data_sd
    global statsList
    
    set simosHost $host 
    set serverSocknum $port
    set hostport $host:$port
    set localHost [exec hostname]
  
    puts stdout "SimosHOST: $simosHost; SimosPORT $serverSocknum "; # taco
        
    if {[catch ListenDataportProc errMsg]} {
        error "Visual Error: $errMsg  Couldn't setup data port."
    }

    if {[catch {ConnectSimosProc $simosHost $serverSocknum} errMsg]} {
	error "Visual Error: $errMsg. \n Please make sure simos is running on host."
    }

    dp_filehandler $listen_sd r AcceptDataConnectProc

    set msg "VISUALstream $localHost $localSockNum"
    rpc $msg 
}

################################################################################
# rpc
# 
# Remote procedure call. The remote Tcl script will be interpreted within
# the SimOS interpreter. All Tcl-SimOS extensions may be used. 
# The Tcl-SimOS log command has been overloeaded. 
# Logs within RPCs and within annotations installed during an RPC 
# will be send to the data stream and handled by ProcessDataProc
#
# 
################################################################################
proc rpc { s } {
    global control_sd
    dp_send $control_sd $s
    GetPacketProc $control_sd
}

  
proc ProcessDataProc { mode sd } {
    global data_sd logfile
    if {$sd != $data_sd} {
	error "Visual Fatal Error Fatal error: Data socket descriptor screwup"
    }     
    set x  [GetPacketProc $sd]
    
    # for debugging only: print out the script to be evaluated.
    # ########################################################
    puts "DataStream: $x"
    
    # pretty generic. But do we really want to evaluate
    # #### eval $x  
}

proc ConnectSimosProc {simosHost serverSocknum} {
    global localHost localSockNum listen_sd control_sd data_sd
    
    # Pop up alert box that goes away after a while
    puts stdout "Attempting to connect to $simosHost:$serverSocknum"
    set returnVal [catch {dp_connect $simosHost $serverSocknum} connectResult]
    if {$returnVal != 0} {
	error "$connectResult" -1
    }
    puts stdout "Connection established"
    set control_sd [lindex $connectResult 0]
    dp_socketOption $control_sd autoClose no 
    dp_socketOption $control_sd noblock no
    if {[lindex $connectResult 1] != $serverSocknum} {
	set serverSocknum [lindex $connectResult 1]
    }
}


proc AcceptDataConnectProc {mode sd} {
    global listen_sd data_sd control_sd
    
    # Let's pop up an alert box that goes away after a while
    puts stdout "--> Accepting connection on data socket..."
    if {$sd != $listen_sd} {
	error "SimVisual Fatal Error: listen socket descriptor screwup"
    }
    dp_filehandler $listen_sd  ;# Connection accepted, remove handler
    set data_sd [lindex [split [dp_accept $listen_sd]] 0]
    #   dp_socketOption $data_sd autoClose no 
    dp_socketOption $data_sd noblock no
    dp_filehandler $data_sd r ProcessDataProc
}

proc ListenDataportProc {} {
    global listen_sd localSockNum maxSockNum

    while {[catch {dp_connect -server $localSockNum -reuseAddr} \
	    localSockAndPort] && $localSockNum < 3001} {
	incr localSockNum;
    }

    # 3999 is an arbitrary number. It allows for testing of 1000 different
    # ports before giving up.

    if { $localSockNum == $maxSockNum } {
	error "Listen Data Port Error -- Can't get a local socket port"
    }

    set listen_sd [lindex [split $localSockAndPort] 0]
}

proc GetPacketProc {sd} {
    set data ""

    # first get the number of bytes of the packet
    # ###########################################

    set strlen "[dp_receive $sd 8]"
    return [dp_receive $sd $strlen]

}

set localSockNum   2999    ; # Arbitrary value, goes upward if already used
set maxSockNum     3999    ; # Maximum value to try for localSockNum