Index: tls.htm ================================================================== --- tls.htm +++ tls.htm @@ -101,11 +101,18 @@
This is a helper function that utilizes the underlying commands (tls::import). It behaves exactly the same as the native Tcl socket command except that the options can include any of the applicable tls:import - options.
+ options with one additional option: +
+
+
-autoservername bool
+
Automatically send the -servername as the host argument + (default: false)
+
+
 
tls::handshake channel
Forces handshake to take place, and returns 0 if handshake is still in progress (non-blocking), or 1 if the handshake was successful. If the handshake failed Index: tls.tcl ================================================================== --- tls.tcl +++ tls.tcl @@ -60,55 +60,90 @@ # Helper function - behaves exactly as the native socket command. # proc tls::socket {args} { variable socketCmd variable defaults + + # server,option,variable,args + set usageRules { + {0 -async sopts 0} + {* -myaddr sopts 1} + {0 -myport sopts 1} + {* -type sopts 1} + {* -cadir iopts 1} + {* -cafile iopts 1} + {* -certfile iopts 1} + {* -cipher iopts 1} + {* -command iopts 1} + {* -dhparams iopts 1} + {* -keyfile iopts 1} + {* -password iopts 1} + {* -request iopts 1} + {* -require iopts 1} + {0 -autoservername discardOpts 1} + {* -servername iopts 1} + {* -ssl2 iopts 1} + {* -ssl3 iopts 1} + {* -tls1 iopts 1} + {* -tls1.1 iopts 1} + {* -tls1.2 iopts 1} + } + set idx [lsearch $args -server] if {$idx != -1} { set server 1 set callback [lindex $args [expr {$idx+1}]] set args [lreplace $args $idx [expr {$idx+1}]] set usage "wrong # args: should be \"tls::socket -server command ?options? port\"" - set options "-cadir, -cafile, -certfile, -cipher, -command, -dhparams, -keyfile, -myaddr, -password, -request, -require, -servername, -ssl2, -ssl3, -tls1, -tls1.1 or -tls1.2" } else { set server 0 set usage "wrong # args: should be \"tls::socket ?options? host port\"" - set options "-async, -cadir, -cafile, -certfile, -cipher, -command, -dhparams, -keyfile, -myaddr, -myport, -password, -request, -require, -servername, -ssl2, -ssl3, -tls1, -tls1.1 or -tls1.2" + } + + # Create several structures from our list of options + ## 1. options: a text representation of the valid options for the current + ## server type + ## 2. argSwitchBody: Switch body for processing arguments + set options [list] + set argSwitchBody [list] + foreach usageRule $usageRules { + set ruleServer [lindex $usageRule 0] + set ruleOption [lindex $usageRule 1] + set ruleVarToUpdate [lindex $usageRule 2] + set ruleVarArgsToConsume [lindex $usageRule 3] + + if {![string match $ruleServer $server]} { + continue + } + + lappend options $ruleOption + switch -- $ruleVarArgsToConsume { + 0 { set argToExecute {lappend @VAR@ $arg; set argsArray($arg) true} } + 1 { set argToExecute {set argValue [lindex $args [incr idx]]; lappend @VAR@ $arg $argValue; set argsArray($arg) $argValue} } + default { return -code error "Internal argument construction error" } + } + lappend argSwitchBody $ruleServer,$ruleOption [string map [list @VAR@ $ruleVarToUpdate] $argToExecute] } + set options [join $options {, }] + lappend argSwitchBody {*,-*} {return -code error "bad option \"$arg\": must be one of $options"} + lappend argSwitchBody default break + + # Combine defaults with current options + set args [concat $defaults $args] + set argc [llength $args] set sopts {} - set iopts [concat [list -server $server] $defaults] ;# Import options + set iopts [list -server $server] + array set argsArray [list] for {set idx 0} {$idx < $argc} {incr idx} { set arg [lindex $args $idx] - switch -glob -- $server,$arg { - 0,-async {lappend sopts $arg} - 0,-myport - - *,-type - - *,-myaddr {lappend sopts $arg [lindex $args [incr idx]]} - *,-cadir - - *,-cafile - - *,-certfile - - *,-cipher - - *,-command - - *,-dhparams - - *,-keyfile - - *,-password - - *,-request - - *,-require - - *,-servername - - *,-ssl2 - - *,-ssl3 - - *,-tls1 - - *,-tls1.1 - - *,-tls1.2 {lappend iopts $arg [lindex $args [incr idx]]} - -* {return -code error "bad option \"$arg\": must be one of $options"} - default {break} - } - } + switch -glob -- $server,$arg $argSwitchBody + } + if {$server} { if {($idx + 1) != $argc} { return -code error $usage } set uid [incr ::tls::srvuid] @@ -120,12 +155,22 @@ #set sopts [linsert $sopts 0 -server [list tls::_accept $uid $callback]] } else { if {($idx + 2) != $argc} { return -code error $usage } + set host [lindex $args [expr {$argc-2}]] set port [lindex $args [expr {$argc-1}]] + + # If an "-autoservername" option is found, honor it + if {[info exists argsArray(-autoservername)] && $argsArray(-autoservername)} { + if {![info exists argsArray(-servername)]} { + set argsArray(-servername) $host + lappend iopts -servername $host + } + } + lappend sopts $host $port } # # Create TCP/IP socket #