Bug 1160 : try{} catch exception not found; pde/networking library uncatchable peer disconnects, no clean client exits possible
Last modified: 2009-02-20 11:30




Status:
RESOLVED
Resolution:
INVALID -
Priority:
P2
Severity:
normal

 

Reporter:
h3
Assigned To:
fry

Attachment Type Created Size Actions
proxy server test case application/zip 2009-02-13 05:03 2.60 KB

Description:   Opened: 2009-02-13 03:57
pde attempts to help detect the try{}, but in doing so makes it not able to
catch errors when using network library, please post documentation to
network library if there is a work around.

example:

// proxy

import processing.net.*;

int max_delay=100000;

class User {
String name="", pwd="";
Client c,out;
String buffer="";
int pollDelay;
int descriptor;
boolean link_is_down=false;
User next;
}

class Pairs {
String[] pairs;
String[] keys;
int length=0;

String key( String k ) {
for ( int i=0; i<this.length; i++ )
if ( this.keys[i].equals(k) ) return this.pairs[i];
return "";
}

void file( String p ) {
String[] lines = loadStrings(p);
println("Reading Macro Definitions");
for ( int i=0; i<lines.length; i++ )
{ String[] words = split(lines[i],' ');
String pair="";
if ( words.length > 1 ) {
for ( int j=1; j<words.length; j++ ) {
pair=words[j]; if ( j!= words.length ) pair+=" ";
}
if ( words.length > 0 ) this.add( words[0],pair );
}
}
}

void add( String k, String p ) {
String[] kk = new String[this.length+1];
String[] pp = new String[this.length+1];
for ( int i=0; i<this.length; i++ ) {
kk[i]=this.keys[i];
pp[i]=this.pairs[i];
}
kk[this.length] = k;
pp[this.length] = p;
this.keys=kk;
this.pairs=pp;
this.length++;
}

// Adds ESC to the beginning of each key
void prependESC( ) {
String code= char(27)+"";
for ( int i=0; i<this.length; i++ )
keys[i] += code;
}

// Uses keys to write pairs to a string t
String replaceKeys( String t ) {
for( int i=0; i<this.length; i++ )
t= t.replace( this.keys[i], this.pairs[i] );
return t;
}
}


User user = null;
Pairs pairs = new Pairs();

Server myServer;
String host;
int target_port;

void setup() {
int port;
size(200, 20);
// Starts a myServer on port 5204
println("attempting to load required file config.txt");
String []lines = loadStrings("config.txt");
if ( lines.length < 3 ) {
println("ERROR: must contain 3 lines: line 1-> our port");
println(" line 2-> the server address
(usually localhost)");
println(" line 3-> port number");
exit();
}
port=int(lines[0]);
host=lines[1];
target_port=int(lines[2]);
println("attempting to load required file macro.txt, file can be empty
but must exist");
pairs.file("macro.txt");
println("Starting server on port "+port+" forwarding to "+host+"
"+target_port );
myServer = new Server(this, port);
pairs.prependESC();
}


void draw() {
for ( User u=user; u!=null; u=u.next ) {
if ( u.c.available() > 0 ) {
try
{
u.out.write(u.c.readString());
}
catch (SocketException ioe)
{
// Oops! Server is down, signal reconnect.
u.link_is_down=true;
}
}
if ( u.out.available() > 0 ) {
String content=u.out.readString();
if ( content.contains("#USERNAME") && u.name == "" ) {
// We're watching for #USERNAME <name> <temppwd> being fed through
this user's server output.
String[] broken = split(content,' ');
for ( int k=0; k<broken.length; k++ )
if ( broken[k].equals("#USERNAME") ) {
if ( k+1 < broken.length ) u.name = broken[k+1];
if ( k+2 < broken.length ) u.pwd = broken[k+2];
println("found username "+u.name+" password "+u.pwd );
content = content.replace("#USERNAME "+u.name+" "+u.pwd,"");
}
}
u.c.write(content);
}
}
}


// ServerEvent message is generated when a new client connects
// to an existing server.
void serverEvent(Server someServer, Client someClient) {
println("New client: " + someClient.ip());
User u = new User();
u.c = someClient; u.name=""; u.pwd="";
// u.c.write("Make It Proxy 1.0 is here to protect your connection.");
u.out = new Client(this,host,target_port);
u.pollDelay=max_delay;
u.next = user;
user=u;

// Write hostnames to file
String hostnames="";
for ( u=user; u!=null; u=u.next ) if ( u.name != "" ) hostnames+=u.name+'
'+u.c.ip()+'\n';
String []hosts=split(hostnames,'\n');
saveStrings("hostnames.txt",hosts);
}



PDE reports "Unreachable catch block for SocketException", but the
exception that is thrown is a SocketException, buried in the Networking
library. The networking library needs to give feedback when a client
disconnects client-side, it only offers server-side disconnection events.
Additional Comment #1 From h3 2009-02-13 04:02
if ( u.c.available() > 0 ) {
// try
// {
u.out.write(u.c.readString());
// }
// catch (SocketException ioe)
// {
// Oops! Server is down, signal reconnect.
// u.link_is_down=true;
// }
}


java.net.SocketException: Software caused connection abort: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(Unknown Source)
at java.net.SocketOutputStream.write(Unknown Source)
at processing.net.Client.write(Client.java:442)
at processing.net.Client.write(Client.java:468)
at jmimud.draw(jmimud.java:126)
at processing.core.PApplet.handleDraw(PApplet.java:1406)
at processing.core.PApplet.run(PApplet.java:1311)
at java.lang.Thread.run(Unknown Source)


Tried:

for ( User u=user; u!=null; u=u.next ) {
if ( u.c.available() > 0 ) {
try
{
u.out.write(u.c.readString());
}
catch (SocketException ioe)
{
// Oops! Server is down, signal reconnect.
u.link_is_down=true;
}
}


Additional Comment #2 From h3 2009-02-13 04:07
To test this error, you need a server running on the target_port.

If you do a server-side disconnect, the client crashes because it cannot
catch the exception.

So, I kicked the user from the server, and the client didn't know.
Additional Comment #3 From h3 2009-02-13 04:12
On ##java as nick "bdbdbd" :
[07:09] <jottinger> bdbdbd: check out the hierarchy for SocketException -
it may be an Error. Or: instead of Exception, look at Throwable.
[07:09] <-- KikiJiki has left this server (Client Quit).
[07:10] <-- kapipi has left this server ("Ah Nah!").
[07:10] <mitch0> socketexception is an ioexception
[07:10] <jottinger> mitch0: then Exception should have caught it
[07:10] <jottinger> there's something funky there for real then
[07:10] <mitch0> there's something else going on
[07:11] <mitch0> I don't even see where those stacks point to...
[07:11] <mitch0> so, it's hard to see what's wrong
Additional Comment #4 From h3 2009-02-13 04:15
[07:09] <jottinger> bdbdbd: check out the hierarchy for SocketException -
it may be an Error. Or: instead of Exception, look at Throwable.
[07:09] <-- KikiJiki has left this server (Client Quit).
[07:10] <-- kapipi has left this server ("Ah Nah!").
[07:10] <mitch0> socketexception is an ioexception
[07:10] <jottinger> mitch0: then Exception should have caught it
[07:10] <jottinger> there's something funky there for real then
[07:10] <mitch0> there's something else going on
[07:11] <mitch0> I don't even see where those stacks point to...
[07:11] <mitch0> so, it's hard to see what's wrong
Additional Comment #5 From h3 2009-02-13 04:19
Replacing Exception ioe with Throwable t yielded no different results.
Additional Comment #6 From h3 2009-02-13 04:24
Actually, I may have that backwards: the server doesn't know, the client has

disconnectEvent()

However, what if the client disconnects? There's something fishy,
hopefully you folks can find it.
Additional Comment #7 From h3 2009-02-13 04:26
[07:21] <mitch0> bdbd: which line the stack trace points to? (that is,
which line is processing.net.Client.write(Client.java:442))
[07:21] <bdbdbd> Hard to tell but it looks like a library
[07:22] <bdbdbd> To further answer your question, it is this library:
http://processing.org/reference/libraries/net/index.html
[07:22] <bdbdbd> I have submitted a bug report. It only offers
disconnectEvent() on the server-side.
[07:23] --> skoskav has joined this channel
(n=skoskav@c83-250-112-76.bredband.comhem.se).
[07:24] <mitch0> wtf, 65MB download? :)
[07:24] <bdbdbd> It's a great
[07:24] <bdbdbd> tool
[07:25] <bdbdbd> actually
[07:26] <bdbdbd> it only offers disconnect on the client-side.. hmm
Additional Comment #8 From h3 2009-02-13 05:03
edit]
proxy server test case

Please start here.

If you connect two clients to the server, the server will lose the ability to
drop data to all of the clients when one client disconnects abruptly.

Likewise, there is fishiness during disconnectEvent(), where it throws the
errors and executes the event, but then forces the server down.


To protect peers from stalling during a disconnect, or to stop the client from
crashing the server, more advanced Event handles must be provided with better
feedback. This could all be taken care of in something like available(), where
we check the state of the socket through polling, like is_connected() or
something to that effect.