www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Bug in std.socket

reply Graham St Jack <graham.stjack internode.on.net> writes:
Forgive my ignorance, but can anyone tell me how to post a ticket for 
phobos?

I want to report a bug in std.socket's TcpSocket.accept() (at least it 
manifests itself there for me) introduced in D 2.0.27 and still there in 
2.0.28. The following code runs to completion in 2.026 and blocks on 
accept in later compiler versions.


import std.socket;
import std.stdio;
import core.thread;


class Server {
    private {
        InternetAddress mAddress;
        Thread          mThread;
    }

    this(InternetAddress address) {
        mAddress     = address;
        mThread      = new Thread(&run);
        mThread.name = "server".dup;
        mThread.start;
    }

    void join() {
        mThread.join;
    }

    void run() {
        try {
            writefln("server - setting up server socket");
            auto listener = new TcpSocket();
            listener.bind(mAddress);
            listener.listen(5);

            // wait for a connection
            writefln("server - waiting for a client connection");
            auto socket = listener.accept();
            writefln("server - got a client connection");

            // read some data and write it back
            writefln("server - reading data from the client");
            ubyte[100] data;
            int qty = socket.receive(data);
            writefln("server - writing the data back to the client");
            socket.send(data[0..qty]);
        }
        catch (Exception ex) {
            writefln("server - server got exception: %s", ex);
        }

        // terminate
        writefln("server - terminating");
    }
}

class Client {
    private {
        InternetAddress mAddress;
        Thread          mThread;
    }

    this(InternetAddress address) {
        mAddress = address;
        mThread = new Thread(&run);
        mThread.name = "client".dup;
        mThread.start;
    }

    void join() {
        mThread.join;
    }

    void run() {
        try {
            // connect
            writefln("client - connecting to server");
            auto socket = new TcpSocket(mAddress);
            writefln("client - connected to server");

            // send and receive some data
            writefln("client - sending data to server");
            ubyte[3] send_data;
            send_data[0] = 41;
            send_data[1] = 42;
            send_data[2] = 43;
            int qty = socket.send(send_data);
            assert(qty == send_data.length);
            writefln("client - receiving data from server");
            ubyte[100] receive_data;
            qty = socket.receive(receive_data);
            writefln("client - got %s bytes from server", qty);
        }
        catch (Exception ex) {
            writefln("client - client got exception %s", ex);
        }

        // terminate
        writefln("client - terminating");
    }
}



int main(string[] args) {
    writefln("test starting");

    try {
        InternetAddress address = new InternetAddress("localhost", 12345);
        Server server = new Server(address);
        Client client = new Client(address);
        writefln("joining with server");
        server.join;
        writefln("joining with client");
        client.join;
        writefln("finished");
    }
    catch (Exception ex) {
        writefln("unexpected exception %s", ex);
    }
    return 0;
}
Apr 14 2009
next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 15 Apr 2009 01:20:38 +0400, Graham St Jack
<graham.stjack internode.on.net> wrote:

 Forgive my ignorance, but can anyone tell me how to post a ticket for
 phobos?

 I want to report a bug in std.socket's TcpSocket.accept() (at least it
 manifests itself there for me) introduced in D 2.0.27 and still there in
 2.0.28. The following code runs to completion in 2.026 and blocks on
 accept in later compiler versions.


 import std.socket;
 import std.stdio;
 import core.thread;


 class Server {
     private {
         InternetAddress mAddress;
         Thread          mThread;
     }

     this(InternetAddress address) {
         mAddress     = address;
         mThread      = new Thread(&run);
         mThread.name = "server".dup;
         mThread.start;
     }

     void join() {
         mThread.join;
     }

     void run() {
         try {
             writefln("server - setting up server socket");
             auto listener = new TcpSocket();
             listener.bind(mAddress);
             listener.listen(5);

             // wait for a connection
             writefln("server - waiting for a client connection");
             auto socket = listener.accept();
             writefln("server - got a client connection");

             // read some data and write it back
             writefln("server - reading data from the client");
             ubyte[100] data;
             int qty = socket.receive(data);
             writefln("server - writing the data back to the client");
             socket.send(data[0..qty]);
         }
         catch (Exception ex) {
             writefln("server - server got exception: %s", ex);
         }

         // terminate
         writefln("server - terminating");
     }
 }

 class Client {
     private {
         InternetAddress mAddress;
         Thread          mThread;
     }

     this(InternetAddress address) {
         mAddress = address;
         mThread = new Thread(&run);
         mThread.name = "client".dup;
         mThread.start;
     }

     void join() {
         mThread.join;
     }

     void run() {
         try {
             // connect
             writefln("client - connecting to server");
             auto socket = new TcpSocket(mAddress);
             writefln("client - connected to server");

             // send and receive some data
             writefln("client - sending data to server");
             ubyte[3] send_data;
             send_data[0] = 41;
             send_data[1] = 42;
             send_data[2] = 43;
             int qty = socket.send(send_data);
             assert(qty == send_data.length);
             writefln("client - receiving data from server");
             ubyte[100] receive_data;
             qty = socket.receive(receive_data);
             writefln("client - got %s bytes from server", qty);
         }
         catch (Exception ex) {
             writefln("client - client got exception %s", ex);
         }

         // terminate
         writefln("client - terminating");
     }
 }



 int main(string[] args) {
     writefln("test starting");

     try {
         InternetAddress address = new InternetAddress("localhost",  
 12345);
         Server server = new Server(address);
         Client client = new Client(address);
         writefln("joining with server");
         server.join;
         writefln("joining with client");
         client.join;
         writefln("finished");
     }
     catch (Exception ex) {
         writefln("unexpected exception %s", ex);
     }
     return 0;
 }

http://d.puremagic.com/issues/enter_bug.cgi
Apr 14 2009
prev sibling next sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Graham St Jack wrote:
 Forgive my ignorance, but can anyone tell me how to post a ticket for 
 phobos?

http://d.puremagic.com/issues/ Once you've set yourself up there, use the "New" link, select "D" and then "Phobos" from the component list. Stewart.
Apr 14 2009
prev sibling next sibling parent Brad Roberts <braddr bellevue.puremagic.com> writes:
Your code is inherently racy.  The client thread could attempt to connect 
before the server thread has finished the steps prior to accept.

Also, there's no second . in the version scheme for DMD, it's just 1.xxx 
or 2.xxx.

Later,
Brad

On Tue, 14 Apr 2009, Graham St Jack wrote:

 Forgive my ignorance, but can anyone tell me how to post a ticket for 
 phobos?
 
 I want to report a bug in std.socket's TcpSocket.accept() (at least it 
 manifests itself there for me) introduced in D 2.0.27 and still there in 
 2.0.28. The following code runs to completion in 2.026 and blocks on 
 accept in later compiler versions.
 
 
 import std.socket;
 import std.stdio;
 import core.thread;
 
 
 class Server {
     private {
         InternetAddress mAddress;
         Thread          mThread;
     }
 
     this(InternetAddress address) {
         mAddress     = address;
         mThread      = new Thread(&run);
         mThread.name = "server".dup;
         mThread.start;
     }
 
     void join() {
         mThread.join;
     }
 
     void run() {
         try {
             writefln("server - setting up server socket");
             auto listener = new TcpSocket();
             listener.bind(mAddress);
             listener.listen(5);
 
             // wait for a connection
             writefln("server - waiting for a client connection");
             auto socket = listener.accept();
             writefln("server - got a client connection");
 
             // read some data and write it back
             writefln("server - reading data from the client");
             ubyte[100] data;
             int qty = socket.receive(data);
             writefln("server - writing the data back to the client");
             socket.send(data[0..qty]);
         }
         catch (Exception ex) {
             writefln("server - server got exception: %s", ex);
         }
 
         // terminate
         writefln("server - terminating");
     }
 }
 
 class Client {
     private {
         InternetAddress mAddress;
         Thread          mThread;
     }
 
     this(InternetAddress address) {
         mAddress = address;
         mThread = new Thread(&run);
         mThread.name = "client".dup;
         mThread.start;
     }
 
     void join() {
         mThread.join;
     }
 
     void run() {
         try {
             // connect
             writefln("client - connecting to server");
             auto socket = new TcpSocket(mAddress);
             writefln("client - connected to server");
 
             // send and receive some data
             writefln("client - sending data to server");
             ubyte[3] send_data;
             send_data[0] = 41;
             send_data[1] = 42;
             send_data[2] = 43;
             int qty = socket.send(send_data);
             assert(qty == send_data.length);
             writefln("client - receiving data from server");
             ubyte[100] receive_data;
             qty = socket.receive(receive_data);
             writefln("client - got %s bytes from server", qty);
         }
         catch (Exception ex) {
             writefln("client - client got exception %s", ex);
         }
 
         // terminate
         writefln("client - terminating");
     }
 }
 
 
 
 int main(string[] args) {
     writefln("test starting");
 
     try {
         InternetAddress address = new InternetAddress("localhost", 12345);
         Server server = new Server(address);
         Client client = new Client(address);
         writefln("joining with server");
         server.join;
         writefln("joining with client");
         client.join;
         writefln("finished");
     }
     catch (Exception ex) {
         writefln("unexpected exception %s", ex);
     }
     return 0;
 }
 

Apr 14 2009
prev sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
Does waiting for a keypress in the client thread do you any favors?

Also, you can get some mileage by doing a select() (see SocketSet) on 
the socket first.  This will tell you if you need to accept(), and also 
allow you to do timeouts.  I'm a big fan of non-blocking sockets, you 
can improve connect() this way too.

-[Unknown]


Graham St Jack wrote:
 Forgive my ignorance, but can anyone tell me how to post a ticket for 
 phobos?
 
 I want to report a bug in std.socket's TcpSocket.accept() (at least it 
 manifests itself there for me) introduced in D 2.0.27 and still there in 
 2.0.28. The following code runs to completion in 2.026 and blocks on 
 accept in later compiler versions.
 
 
 import std.socket;
 import std.stdio;
 import core.thread;
 
 
 class Server {
     private {
         InternetAddress mAddress;
         Thread          mThread;
     }
 
     this(InternetAddress address) {
         mAddress     = address;
         mThread      = new Thread(&run);
         mThread.name = "server".dup;
         mThread.start;
     }
 
     void join() {
         mThread.join;
     }
 
     void run() {
         try {
             writefln("server - setting up server socket");
             auto listener = new TcpSocket();
             listener.bind(mAddress);
             listener.listen(5);
 
             // wait for a connection
             writefln("server - waiting for a client connection");
             auto socket = listener.accept();
             writefln("server - got a client connection");
 
             // read some data and write it back
             writefln("server - reading data from the client");
             ubyte[100] data;
             int qty = socket.receive(data);
             writefln("server - writing the data back to the client");
             socket.send(data[0..qty]);
         }
         catch (Exception ex) {
             writefln("server - server got exception: %s", ex);
         }
 
         // terminate
         writefln("server - terminating");
     }
 }
 
 class Client {
     private {
         InternetAddress mAddress;
         Thread          mThread;
     }
 
     this(InternetAddress address) {
         mAddress = address;
         mThread = new Thread(&run);
         mThread.name = "client".dup;
         mThread.start;
     }
 
     void join() {
         mThread.join;
     }
 
     void run() {
         try {
             // connect
             writefln("client - connecting to server");
             auto socket = new TcpSocket(mAddress);
             writefln("client - connected to server");
 
             // send and receive some data
             writefln("client - sending data to server");
             ubyte[3] send_data;
             send_data[0] = 41;
             send_data[1] = 42;
             send_data[2] = 43;
             int qty = socket.send(send_data);
             assert(qty == send_data.length);
             writefln("client - receiving data from server");
             ubyte[100] receive_data;
             qty = socket.receive(receive_data);
             writefln("client - got %s bytes from server", qty);
         }
         catch (Exception ex) {
             writefln("client - client got exception %s", ex);
         }
 
         // terminate
         writefln("client - terminating");
     }
 }
 
 
 
 int main(string[] args) {
     writefln("test starting");
 
     try {
         InternetAddress address = new InternetAddress("localhost", 12345);
         Server server = new Server(address);
         Client client = new Client(address);
         writefln("joining with server");
         server.join;
         writefln("joining with client");
         client.join;
         writefln("finished");
     }
     catch (Exception ex) {
         writefln("unexpected exception %s", ex);
     }
     return 0;
 }

Apr 15 2009
next sibling parent Graham St Jack <graham.stjack internode.on.net> writes:
On Wed, 15 Apr 2009 00:38:33 -0700, Unknown W. Brackets wrote:

 Does waiting for a keypress in the client thread do you any favors?
 
 Also, you can get some mileage by doing a select() (see SocketSet) on
 the socket first.  This will tell you if you need to accept(), and also
 allow you to do timeouts.  I'm a big fan of non-blocking sockets, you
 can improve connect() this way too.
 
 -[Unknown]

Thanks for all the useful suggestions. I'm on the ticket bandwagon at last. I realise that the code I posted was a bit rough (although I missed the race, which is definitely there). It was a heavily cut-down version of something a lot larger that does indeed use select, uses non-blocking I/ O, retries connection attempts, and even uses Fibers. What I wanted was a small and simple test case to attach to the ticket, not something serious.
Apr 15 2009
prev sibling next sibling parent Brad Roberts <braddr puremagic.com> writes:
Graham St Jack wrote:
 On Wed, 15 Apr 2009 00:38:33 -0700, Unknown W. Brackets wrote:
 
 Does waiting for a keypress in the client thread do you any favors?

 Also, you can get some mileage by doing a select() (see SocketSet) on
 the socket first.  This will tell you if you need to accept(), and also
 allow you to do timeouts.  I'm a big fan of non-blocking sockets, you
 can improve connect() this way too.

 -[Unknown]

Thanks for all the useful suggestions. I'm on the ticket bandwagon at last. I realise that the code I posted was a bit rough (although I missed the race, which is definitely there). It was a heavily cut-down version of something a lot larger that does indeed use select, uses non-blocking I/ O, retries connection attempts, and even uses Fibers. What I wanted was a small and simple test case to attach to the ticket, not something serious.

I was about to close the ticket as invalid due to buggy reproduction code. Can you demonstrate the problem with an example app that's _not_ buggy? If so, please attach it to the bug report. Later, Brad
Apr 15 2009
prev sibling parent Graham St Jack <graham.stjack internode.on.net> writes:
On Wed, 15 Apr 2009 09:35:45 -0700, Brad Roberts wrote:

 Graham St Jack wrote:
 On Wed, 15 Apr 2009 00:38:33 -0700, Unknown W. Brackets wrote:
 
 Does waiting for a keypress in the client thread do you any favors?

 Also, you can get some mileage by doing a select() (see SocketSet) on
 the socket first.  This will tell you if you need to accept(), and
 also allow you to do timeouts.  I'm a big fan of non-blocking sockets,
 you can improve connect() this way too.

 -[Unknown]

last. I realise that the code I posted was a bit rough (although I missed the race, which is definitely there). It was a heavily cut-down version of something a lot larger that does indeed use select, uses non-blocking I/ O, retries connection attempts, and even uses Fibers. What I wanted was a small and simple test case to attach to the ticket, not something serious.

I was about to close the ticket as invalid due to buggy reproduction code. Can you demonstrate the problem with an example app that's _not_ buggy? If so, please attach it to the bug report. Later, Brad

Someone else already provided a much simpler test case without bugs.
Apr 15 2009