Thread: Sockets
View Single Post
Old 25th October 2003, 04:22 PM   #4
Dennis
Senior Member
Professional user
 
Dennis's Avatar
 
Join Date: Jul 2003
Posts: 899
Default Re: Sockets

Spoke too soon - started happening again after a little while. I ended up looking at the ac3d.tcl code after all - by the way, it's a very clean implementation, with sensible function names and easy-to-follow logic - it's almost self documenting.

I traced the problem down to the socket #'s being grabbed. I was alternating between socket 400 and 412 when I established a connection. However, if I grabbed the same socket twice in a row, AC3D closed it immediately the second time.

I found this code in ac3d.tcl:

Code:
proc do_connection {sock ip port} {

	fileevent $sock readable "get_cmd $sock"
	puts "New socket connected to AC3D (socket id $sock, remote ip:port $ip:$port)"

	close_current_command_socket
	set_command_socket $sock
}
When I make a second connection against a running AC3D session, and let's say I grab the same socket number as the last connection I made (412 in this example), do_connection issues a "close_current_command_socket" to close the last socket it remembers (which, in this case, is still 412). So it closes the socket immediately after it opens the new one.

I was able to fix this by editing my copy of ac3d.tcl to pass the new socket number to close_current_command_socket, then changing the logic to only close the old one if it was a different socket. This allows me to grab the same socket twice in a row w/o getting it clipped by close_current_command_socket.

fyi, I also tried the sample ac3dshell.tcl --- it seems to work fine, since the ac3dshell.tcl doesn't close the socket when it's done (it lets AC3D do it). In my own app, I allow the socket to be opened and closed.

I ended up changing 4 lines of code across three functions. The changes I made in my file are as follows (see comments):

Code:
proc do_connection {sock ip port} {

	fileevent $sock readable "get_cmd $sock"
	puts "New socket connected to AC3D (socket id $sock, remote ip:port $ip:$port)"

	# DH - Added $sock parameter
	close_current_command_socket $sock
	set_command_socket $sock
}
Code:
proc disable_socket_commands {} {

	global listensock

	if { $listensock != 0 } {

		# DH - Added 0 parameter
		close_current_command_socket 0

		set err [catch { close $listensock }]
		set listensock 0
	}

	puts "Command socket connections disabled"
}
Code:
# DH - Added "sock" argument, which is the currently open socket
#         (sock == 0 if we want to force a close).
#      This allows close_current_command_socket to compare the old
#      socket (the one it's trying to close) against the new socket,
#      in the event a function like "do_connection" cleans up the
#      old socket first.
proc close_current_command_socket { sock } {

	global rsock

        # DH - added "&& $rsock != $sock"
	if { $rsock != 0 && $rsock != $sock } {
		set err [catch { close $rsock }]
		puts "tcl socket $rsock disconnected by AC3D"
		set rsock 0
	}
}
In all, a quick and easy fix (whew!).

I'm not sure how often this feature of AC3D gets used, but I'm *really* glad it's there. So far, it's allowing me to write a fairly robust property editor with my own GUI (so I'm not so dependent on TCL, with which I'm not terribly adept).

Thanks,
Dennis
Dennis is offline   Reply With Quote