#!/usr/bin/tclsh # # Copyright 2007 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # package require http load libdtntcl[info sharedlibextension] dtn #---------------------------------------------------------------------- proc shift { l } { upvar $l xx set xx [lrange $xx 1 end] } #---------------------------------------------------------------------- proc arg0 { l } { return [lindex $l 0] } #---------------------------------------------------------------------- proc dbg {args} { global opt if {$opt(verbose)} { set nonewline "" if {[arg0 $args] == "-nonewline"} { set nonewline -nonewline shift args } set chan stdout if {[llength $args] == 2} { set chan [arg0 $args] shift args } set msg [arg0 $args] if {$nonewline != ""} { puts $nonewline $chan $msg } else { puts $chan $msg } } } #---------------------------------------------------------------------- proc usage {} { puts "Usage: dtnhttpproxy \[Options\]" puts "" puts "Options:" puts " -h | --help Print help message" puts " -v | --verbose Verbose mode" puts " -e | --eid Set eid (default is dtn:///http)" } #---------------------------------------------------------------------- proc init { argv } { global opt set opt(verbose) 0 set opt(eid) "" # parse options while {[llength $argv] > 0} { switch -- [arg0 $argv] { -h - --help { usage; exit } -v - --verbose { set opt(verbose) 1 } -e - --eid { shift argv; set opt(eid) [arg0 $argv] } default { puts "illegal option \"[arg0 $argv]\""; usage; exit } } shift argv } } #---------------------------------------------------------------------- proc connect {} { global handle set handle [dtn_open] if {$handle == -1} { error "error in dtn_open_handle" } dbg "handle is $handle" } #---------------------------------------------------------------------- proc register {} { global handle opt regid DTN_REG_DEFER set eid $opt(eid) if {$eid == ""} { set eid [dtn_build_local_eid $handle "http"] if {$eid == ""} { error "error in dtn_build_local_eid: [dtn_strerror [dtn_errno $handle]]" } } dbg "eid is $eid" set regid [dtn_find_registration $handle $eid] if {$regid != -1} { dbg "found existing registration -- id $regid, calling bind..." dtn_bind $handle $regid } else { set regid [dtn_register $handle $eid $DTN_REG_DEFER 3600 false ""] dbg "created new registration -- id $regid" } } #---------------------------------------------------------------------- proc proxy_loop {} { global handle DTN_PAYLOAD_FILE while {1} { dbg "calling dtn_recv..." set bundle [dtn_recv $handle $DTN_PAYLOAD_FILE -1] if {$bundle == "NULL"} { error "error in dtn_recv: [dtn_strerror [dtn_errno $handle]]" } set source [dtn_bundle_source_get $bundle] set dest [dtn_bundle_dest_get $bundle] set payload_file [dtn_bundle_payload_get $bundle] set expiration [dtn_bundle_expiration_get $bundle] set creation_ts "[dtn_bundle_creation_secs_get $bundle].\ [dtn_bundle_creation_seqno_get $bundle]" dbg "received bundle:" dbg " source: $source" dbg " dest: $dest" dbg " expiration: $expiration" dbg " creation_ts: $creation_ts" dbg " payload: $payload_file" dbg " payload_size: [file size $payload_file]" set fd [open $payload_file r] # default values for params set params(mode) get set params(content_type) "text/plain" set paramlist [lindex [split $dest ?] 1] foreach param [split $paramlist \;] { foreach {var val} [split $param =] { set params($var) $val } } if {![info exists params(url)]} { puts stderr "no url in destination eid '$dest'" continue } set url $params(url) set url [regsub -all "%3a" $url :] set url [regsub -all "%2f" $url /] switch $params(mode) { upload { # need to wrap the multipart headers around the payload set temp_file "/tmp/dtnhttpproxy-[pid]" set tmpfd [open $temp_file w] if {![info exists params(upload_name)]} { set params(upload_name) "file" } puts -nonewline $tmpfd "--xYzZY\r\n" puts -nonewline $tmpfd "Content-Disposition: form-data; name=\"$params(upload_name)\"; filename=\"$temp_file\";\r\n" puts -nonewline $tmpfd "Content-Type: $params(content_type)\r\n" puts -nonewline $tmpfd "\r\n" while {![eof $fd]} { set buf [read $fd 1024] puts -nonewline $tmpfd $buf } puts -nonewline $tmpfd "--xYzZY--\r\n" close $fd close $tmpfd if [catch {file delete $payload_file} err] { puts "error removing payload file: $err" } set payload_file $temp_file set fd [open $temp_file] set params(content_type) "multipart/form-data, boundary=xYzZY" set channel -querychannel } default { puts stderr "mode $params(mode) not defined" continue } } if [catch { dbg -nonewline " calling http::geturl for $url..." set token [::http::geturl $url \ -type $params(content_type) \ -blocksize 1024 \ -progress http_progress \ $channel $fd] dbg -nonewline " waiting..." ::http::wait $token dbg "" dbg " status: [::http::status $token]" dbg " error: [::http::error $token]" } err] { puts "error in geturl: $err" } puts stderr "" if [catch {file delete $payload_file} err] { puts "error removing payload file: $err" } close $fd } } proc http_progress {token total current} { dbg -nonewline . flush stdout } #---------------------------------------------------------------------- init $argv while {1} { if [catch { connect register proxy_loop } err] { puts "$err" } catch {dtn_close $handle} err after 5000 }