This file is indexed.

/usr/share/tcltk/tcllib1.18/multiplexer/multiplexer.tcl is in tcllib 1.18-dfsg-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# multiplexer.tcl -- one-to-many comunication with sockets
#
#	Implementation of a one-to-many multiplexer in Tcl utilizing
#	sockets.

# Copyright (c) 2001-2003 by David N. Welton <davidw@dedasys.com>

# This file may be distributed under the same terms as Tcl.

# $Id: multiplexer.tcl,v 1.4 2004/01/15 06:36:13 andreas_kupries Exp $

package provide multiplexer 0.2
package require logger

namespace eval ::multiplexer {
    variable Unique 0
}

proc ::multiplexer::create {} {
    variable Unique
    set ns ::multiplexer::mp$Unique

    namespace eval $ns {
	# Use the namespace as the logger name.
	set log [logger::init [string trimleft [namespace current] ::]]
	# list of connected clients
	array set clients {}

	# filters to run at access (socket accept) time
	set accessfilters {}

	# filters to run on data
	set filters {}

	# hook to run at exit time
	set exitfilters {}

	# config options
	array set config {}
	set config(sendtoorigin) 0
	set config(debuglevel) warn
	${log}::disable $config(debuglevel)
	${log}::enable $config(debuglevel)

	# AddAccessFilter --
	#
	# Command to add an access filter that will be called like so:
	#
	# AccessFilter chan clientaddress clientport
	#
	# Arguments:
	#
	# function: proc to filter access to the multiplexer.  Takes chan,
	# clientaddress and clientport arguments.  Returns 0 on success, -1 on
	# failure.

	proc AddAccessFilter { function } {
	    variable accessfilters
	    lappend accessfilters $function
	}

	# AddFilter --

	# Command to add a filter for data that passes through the
	# multiplexer.  The filter proc is called like this:

	# Filter data chan clientaddress clientport

	# Arguments:

	# function: proc to filter data that arrives to the
	# multiplexer.
	# Takes data, chan, clientaddress, and clientport arguments.  Returns
	# filtered version of data.

	proc AddFilter { function } {
	    variable filters
	    lappend filters $function
	}

	# AddExitFilter --

	# Adds filter to be run when client socket generates an EOF condition.
	# ExitFilter functions look like the following:

	# ExitFilter chan clientaddress clientport

	# Arguments:

	# function: hook to be run when clients exit by generating an EOF.
	# Takes chan, clientaddress and clientport arguments, and returns
	# nothing.

	proc AddExitFilter { function } {
	    variable exitfilters
	    lappend exitfilters $function
	}

	# DelClient --

	# Deletes a client from the client list, and runs exit filters.

	# Arguments:

	# chan: channel that is closed.

	# client: address of client

	# clientport: port number of client.

	proc DelClient { chan client clientport } {
	    variable clients
	    variable exitfilters
	    variable config
	    variable log
	    foreach ef $exitfilters {
		catch {
		    $ef $chan $client $clientport
		} err
		${log}::debug "Error in DelClient: $err"
	    }
	    unset clients($chan)
	    close $chan
	}


	# MultiPlex --

	# Multiplex data

	# Arguments:

	# data - data to multiplex

	proc MultiPlex { data {chan ""} } {
	    variable clients
	    variable config
	    variable log

	    foreach c [array names clients] {
		if { $config(sendtoorigin) } {
		    puts -nonewline $c "$data"
		} else {
		    if { $chan != $c } {
			${log}::debug "Sending '$data' to $c"
			puts -nonewline $c "$data"
		    }
		}
	    }
	}


	# GetData --

	# Get data from clients, filter it, redistribute it.

	# Arguments:

	# chan: open channel

	# client: client address

	# clientport: port number of client

	proc GetData { chan client clientport } {
	    variable filters
	    variable clients
	    variable config
	    variable log
	    if { ! [eof $chan] } {
		set data [read $chan]
	#	gets $chan data
		${log}::debug "Tcl chan $chan from host $client and port $clientport sends: $data"
		# do data filters
		foreach f $filters {
		    catch {
			set data [$f $data $chan $client $clientport]
		    } err
		    ${log}::debug "GetData filter: $err"
		}
		set chans [array names clients]
		MultiPlex $data $chan
	    } else {
		${log}::debug "Deleting client $chan from host $client and port $clientport."
		DelClient $chan $client $clientport
	    }
	}

	# NewClient --

	# Sets up newly created connection after running access filters

	# Arguments:

	# chan: open channel

	# client: client address

	# clientport: port number of client

	proc NewClient { chan client clientport } {
	    variable clients
	    variable config
	    variable accessfilters
	    variable log
	    # run through access filters
	    foreach af $accessfilters {
		if { [$af $chan $client $clientport] == -1 } {
		    ${log}::debug "Access denied to $chan $client $clientport"
		    close $chan
		    return
		}
	    }
	    set clients($chan) $client

	    # We want to read data and immediately send it out again.
	    fconfigure $chan -blocking 0
	    fconfigure $chan -buffering none
	    fconfigure $chan -translation binary
	    fileevent $chan readable [list [namespace current]::GetData $chan $client $clientport]
	    ${log}::debug "Tcl channel $chan is host $client and port $clientport."
	}

	# Config --
	#
	# Configure global options, which currently include the
	# following:
	#
	# sendtoorigin: if 1, resend the data to all clients, including the
	# sender.  Defaults to 0
	#
	# debuglevel: a debug level understood by logger.
	#
	# Arguments:
	#
	# key: name of option to configure
	#
	# value: value for option.

	proc Config { key value } {
	    variable config
	    variable log
	    if { $key == "debuglevel" } {
		${log}::disable $config(debuglevel)
		${log}::enable $value
	    }
	    set config($key) $value
	}

	# Init --
	#
	# Start the server
	#
	# Arguments:
	#
	# port: port to listen on.

	proc Init { port } {
	    variable serversock
	    set serversock [socket -server [namespace current]::NewClient $port]
	}

	# destroy --
	#
	#	Destroy multiplexer instance.  It is important to do
	#	this, to free the resources used.
	#
	# Side Effects:
	#	Deletes namespace associated with multiplexer
	#	instance.


	proc destroy { } {
	    variable serversock
	    foreach c [array names clients] {
	        catch { close $c }
	    }
	    catch {
		close $serversock
	    }
	    namespace delete [namespace current]
	}

    }
    incr Unique
    return $ns
}

namespace eval multiplexer {
    namespace export create destroy
}