Thread: Multithreaded Application Networking

  1. #1
    Rat with a C++ compiler Rodaxoleaux's Avatar
    Join Date
    Sep 2011
    Location
    ntdll.dll
    Posts
    203

    Multithreaded Application Networking

    I'm applying a client-server interaction in a program. Both the client and the server both do extra things and have the connection in a separate thread. However, no matter what I do, it seems to disconnect while using recv(). I can't locate a problem. recv() just returns -1 every time.

    Client Connection
    Code:
    Socket lSocket(port);
    
    
        if(!lSocket.Listen(10))
        {
            wxMessageBox("Listen failed","Error!",wxOK);
        }
    
    
        while(true)
        {
            try
            {
                Socket ServerSocket(lSocket.Accept());
    
    
                *StatusLogBox << "Attempted connection located.";
    
    
                ServerSocket.SetTimeout(3000);
                string received = ServerSocket.Receive();
    
    ...
    Server
    Code:
    WSAData wsd;
        WSAStartup(MAKEWORD(2,2),&wsd);
    
    
        Socket s;
        string IP = GetIP();
        cout << "IP Address: " << IP << endl;
    
    
        cout << "Connecting to: " << Client.hostName << ":" << Client.port << endl;
    
    
        while(!s.ConnectToHost(Client.hostName,(int)Client.port));
    
    
        cout << "Connected" << endl;
    
    
        s.Send(RKL_IP_DATA);
        string rec = s.Receive();
    Socket::Receive()
    Code:
    std::string Socket::Receive()
    {
        if (Timeout > 0) //If a timeout is set, then use select to wait
        {
            fd_set Sockets;
            Sockets.fd_count = 1;
            Sockets.fd_array[0] = s;
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = Timeout;
            int sel = select(s+1,&Sockets,NULL,NULL,&tv);
    
    
            if (sel)
            {
                std::string retval;
    
    
                char buf[1024];
    
    
                while (true)
                {
                    u_long arg = 0;
    
    
                    if (ioctlsocket(s,FIONREAD,&arg) != 0)
                    {
                        stringstream error;
                        error << WSAGetLastError();
                        return error.str();
                    }
    
    
                    if (arg > 1024)
                        arg = 1024;
    
    
                    int received = recv(s,buf,arg,0);
    
    
                    if (received > 0)
                    {
                        std::string t;
                        t.assign(buf,received);
                        retval += t;
                        break;
                    }
                }
    
    
                return retval;
            }
            else
            {
                return "";
            }
        }
        else
        {
            std::string retval;
    
    
            char buf[1024];
    
    
            while (true)
            {
                u_long arg = 0;
    
    
                if (ioctlsocket(s,FIONREAD,&arg) != 0)
                {
                    stringstream error;
                    error << WSAGetLastError();
                    return error.str();
                }
    
    
                if (arg > 1024)
                    arg = 1024;
    
    
                int received = recv(s,buf,arg,0);
    
    
                if (received > 0)
                {
                    std::string t;
                    t.assign(buf,received);
                    retval += t;
                    break;
                }
                if (received == -1)
                {
                    cout << "Receive fail: " << WSAGetLastError() << endl;
                    break;
                }
            }
    
    
            return retval;
        }
    }


    There is a timeout right now on the client but not the server so take the "select()" path. I'm not sure what I'm doing wrong. There is no error in ioctlsocket o.o I double-checked to make sure I wasn't messing up on my blocking calls, as accept() blocks fine.
    How to ask smart questions
    Code:
    DWORD dwBytesOverwritten;
    BYTE rgucOverWrite[] = {0xe9,0,0,0,0};
    WriteProcessMemory(hTaskManager,(LPVOID)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQuerySystemInformation"),rgucOverWrite,5,&dwBytesOverwritten);

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Maybe these Windows example programs will help:
    Client
    Server

  3. #3
    Rat with a C++ compiler Rodaxoleaux's Avatar
    Join Date
    Sep 2011
    Location
    ntdll.dll
    Posts
    203
    I think the only difference is they use getaddrinfo() instead of the sockaddr_in method.

    EDIT:: And changing it back (I used getaddrinfo() before but changed it (not because of a problem, it just seemed easier to use for me)) didn't do anything.
    Last edited by Rodaxoleaux; 03-05-2012 at 07:04 PM.
    How to ask smart questions
    Code:
    DWORD dwBytesOverwritten;
    BYTE rgucOverWrite[] = {0xe9,0,0,0,0};
    WriteProcessMemory(hTaskManager,(LPVOID)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQuerySystemInformation"),rgucOverWrite,5,&dwBytesOverwritten);

  4. #4
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Well, they also check the return value of WSAStartup, for example.

  5. #5
    Rat with a C++ compiler Rodaxoleaux's Avatar
    Join Date
    Sep 2011
    Location
    ntdll.dll
    Posts
    203
    Quote Originally Posted by oogabooga View Post
    Well, they also check the return value of WSAStartup, for example.
    Well, that's a fail on my part. I'll see what I can find.
    How to ask smart questions
    Code:
    DWORD dwBytesOverwritten;
    BYTE rgucOverWrite[] = {0xe9,0,0,0,0};
    WriteProcessMemory(hTaskManager,(LPVOID)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQuerySystemInformation"),rgucOverWrite,5,&dwBytesOverwritten);

  6. #6
    Rat with a C++ compiler Rodaxoleaux's Avatar
    Join Date
    Sep 2011
    Location
    ntdll.dll
    Posts
    203
    Can't edit my post for some reason. I erased that WSAStartup as the Socket class starts it up in a static method (and it works. I've tested it on other things,) however it still doesn't work. I don't understand what's wrong. I'm checking for every other problem. Here is my socket class.
    [spoiler]
    Code:
    #include "rSocket.h"
    #include <iostream>
    #include <sstream>
    
    
    using std::string;
    using std::stringstream;
    using std::cout;
    using std::endl;
    
    
    void Socket::Initialize()
    {
        WSADATA wsd;
    
    
        if (WSAStartup(MAKEWORD(2,2),&wsd))
        {
            cout << "Unable to setup Winsock.";
        }
    }
    
    
    Socket::Socket() : s(0)
    {
        Initialize();
    
    
        Blocking = true;
        Timeout = 0;
    
    
        s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    
    
        if (s == INVALID_SOCKET)
        {
            cout << "Invalid Socket: " << WSAGetLastError();
        }
    
    
        BOOL opt = TRUE;
        int optl = sizeof(BOOL);
    
    
        if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char*)&opt,optl) == SOCKET_ERROR)
        {
            cout << "Setting reusable address option failed: " << WSAGetLastError();
        }
    }
    
    
    Socket::Socket(SOCKET i) : s(i)
    {
        Initialize();
    
    
        if (s != 0)
        {
            BOOL opt = TRUE;
            int optl = sizeof(BOOL);
    
    
            if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char*)&opt,optl) == SOCKET_ERROR)
            {
                cout << "Setting reusable address option failed: " << WSAGetLastError();
            }
        }
        else
        {
            cout << "Socket supplied was invalid. " << WSAGetLastError();
        }
    
    
        Blocking = true;
        Timeout = 0;
    }
    
    
    Socket::Socket(int BindPort) : s(0)
    {
        Initialize();
    
    
        Blocking = true;
        Timeout = 0;
    
    
        s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    
    
        if (s == INVALID_SOCKET)
        {
            cout << "Invalid Socket: " << WSAGetLastError();
        }
    
    
        BOOL opt = TRUE;
        int optl = sizeof(BOOL);
    
    
        if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char*)&opt,optl) == SOCKET_ERROR)
        {
            cout << "Setting reusable address option failed: " << WSAGetLastError();
        }
    
    
        struct addrinfo* portaddr, hints;
        memset(&hints,0,sizeof(hints));
    
    
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags    = AI_PASSIVE;
    
    
        getaddrinfo(NULL,BindPort,&hints,&result);
    
    
        if(bind(s,result->ai_addr,result->ai_addrlen) != 0)
        {
            cout << "Bind error: " << WSAGetLastError() << std::endl;
        }
    
    
    }
    
    
    Socket::~Socket()
    {
        Close();
    }
    
    
    std::string Socket::Receive()
    {
        if (Timeout > 0) //If a timeout is set, then use select to wait
        {
            fd_set Sockets;
            Sockets.fd_count = 1;
            Sockets.fd_array[0] = s;
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = Timeout;
            int sel = select(s+1,&Sockets,NULL,NULL,&tv);
    
    
            if (sel)
            {
                std::string retval;
    
    
                char buf[1024];
    
    
                while (true)
                {
                    u_long arg = 0;
    
    
                    if (ioctlsocket(s,FIONREAD,&arg) != 0)
                    {
                        stringstream error;
                        error << WSAGetLastError();
                        return error.str();
                    }
    
    
                    if (arg > 1024)
                        arg = 1024;
    
    
                    int received = recv(s,buf,arg,0);
    
    
                    if (received > 0)
                    {
                        std::string t;
                        t.assign(buf,received);
                        retval += t;
                        break;
                    }
                }
    
    
                return retval;
            }
            else
            {
                return "";
            }
        }
        else
        {
            std::string retval;
    
    
            char buf[1024];
    
    
            while (true)
            {
                u_long arg = 0;
    
    
                if (ioctlsocket(s,FIONREAD,&arg) != 0)
                {
                    stringstream error;
                    error << WSAGetLastError();
                    return error.str();
                }
    
    
                if (arg > 1024)
                    arg = 1024;
    
    
                int received = recv(s,buf,arg,0);
    
    
                if (received > 0)
                {
                    std::string t;
                    t.assign(buf,received);
                    retval += t;
                    break;
                }
                if (received == -1)
                {
                    cout << "Receive fail: " << WSAGetLastError() << endl;
                    break;
                }
            }
    
    
            return retval;
        }
    }
    
    
    int Socket::Send(const std::string& msg)
    {
        int sent = 0;
    
    
        if (Timeout > 0) //If a timeout is set, then use select to wait
        {
            fd_set Sockets;
            Sockets.fd_count = 1;
            Sockets.fd_array[0] = s;
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = Timeout;
    
    
            while (true)
            {
                unsigned int sel = select(s+1,NULL,&Sockets,NULL,&tv);
    
    
                if (sel)
                {
                    while (sent < msg.length())
                    {
                        sent += send(s,msg.c_str(),msg.length(),0);
                    }
                }
            }
        }
        else
        {
    
    
            while (sent < msg.length())
            {
                sent += send(s,msg.c_str(),msg.length(),0);
            }
        }
    
    
        return sent;
    
    
    }
    
    
    bool Socket::ConnectToHTTPHost(const std::string& host)
    {
        hostent* he;
    
    
        if ((he = gethostbyname(host.c_str())) == 0)
        {
            cout << errno;
            return false;
        }
    
    
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(80);
        addr.sin_addr = *((in_addr *)he->h_addr);
        memset(&(addr.sin_zero),0,8);
    
    
        if (connect(s,(sockaddr *) &addr, sizeof(sockaddr)) != 0)
        {
            cout << WSAGetLastError();
            return false;
        }
    
    
        return true;
    }
    
    
    bool Socket::ConnectToHost(const std::string& host, int port)
    {
        hostent* he;
    
    
        if ((he = gethostbyname(host.c_str())) == 0)
        {
            cout << errno;
            return false;
        }
    
    
        struct addrinfo* portaddr, hints;
        memset(&hints,0,sizeof(hints));
    
    
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags    = AI_PASSIVE;
    
    
        getaddrinfo(host.c_str(),port,&hints,&result);
    
    
        if (connect(s,result->ai_addr,result->ai_addrlen) != 0)
        {
            cout << WSAGetLastError();
            return false;
        }
    
    
        return true;
    }
    
    
    bool Socket::Listen(int NumConn)
    {
        int ret = listen(s,NumConn);
    
    
        if (ret == SOCKET_ERROR)
            return false;
    
    
        return true;
    }
    
    
    Socket Socket::Accept()
    {
        if (Timeout > 0) //If a timeout is set, then use select to wait
        {
            fd_set Sockets;
            Sockets.fd_count = 1;
            Sockets.fd_array[0] = s;
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = Timeout;
            int sel = select(s+1,&Sockets,NULL,NULL,&tv);
    
    
            if (sel)
            {
                SOCKET newConn = accept(s,0,0);
                Socket ret(newConn);
    
    
                return ret;
            }
            else
            {
                return Socket(0);
            }
        }
        else //just carry on normally
        {
            SOCKET newConn = accept(s,0,0);
            Socket ret(newConn);
    
    
            return ret;
        }
    }
    
    
    void Socket::Drop()
    {
        closesocket(s);
    }
    
    
    int Socket::SetBlocking(bool blocking)
    {
        u_long sets = 1;
    
    
        if (blocking)
        {
            sets = 0;
            Timeout = 0;
        }
    
    
        Blocking = sets > 0 ? false : true;
    
    
        int ret = ioctlsocket(s,FIONBIO,&sets);
    
    
        return ret;
    }
    
    
    void Socket::SetTimeout(int ms)
    {
        Timeout = ms * 1000;
    }
    
    
    
    
    void Socket::Close()
    {
        closesocket(s);
    }
    
    
    SOCKET Socket::GetSocketFileDescriptor()
    {
         return s;
    }
    [/spoiler]
    Anyone who might need this can use it |3
    How to ask smart questions
    Code:
    DWORD dwBytesOverwritten;
    BYTE rgucOverWrite[] = {0xe9,0,0,0,0};
    WriteProcessMemory(hTaskManager,(LPVOID)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQuerySystemInformation"),rgucOverWrite,5,&dwBytesOverwritten);

  7. #7
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Quote Originally Posted by Rodaxoleaux View Post
    However, no matter what I do, it seems to disconnect while using recv(). I can't locate a problem. recv() just returns -1 every time.
    Did you ever lookup what that error number you print out actually means? I haven't compiled your code but can tell its going to be 10038. That, coupled with your Accept function (where the socket originates from) should've made it quite easy to spot the problem.

    This should help, you're missing the second one. And this laundry list:

    Missing the matching number of calls to WSACleanup (1 per WSAStartup)
    The first case in Receive has an infinite loop is recv errors or closes
    A nonsense s+1 value to all your select()'s (it's ignored in Windows but not if you ever port it)
    The send() loops have incorrect logic unless you intended to send the whole message from the start everytime
    result from getaddrinfo is never freed
    Filling in the wrong member of all the timeval structs
    You should probably shutdown() the sockets before closing them

    Code:
    if ((he = gethostbyname(host.c_str())) == 0)
        {
            cout << errno;
            return false;
        }
    and how come the error strategy suddenly switches from WSAGetLastError to errno?
    Last edited by adeyblue; 03-06-2012 at 08:32 PM.

  8. #8
    Rat with a C++ compiler Rodaxoleaux's Avatar
    Join Date
    Sep 2011
    Location
    ntdll.dll
    Posts
    203
    Quote Originally Posted by adeyblue View Post
    Did you ever lookup what that error number you print out actually means? I haven't compiled your code but can tell its going to be 10038. That, coupled with your Accept function (where the socket originates from) should've made it quite easy to spot the problem.
    Yes, I have. 10053* means that the application has shutdown the connection. That's all the documentation for that error states. I tried implementing the Accept function by just using the GetSocketFileDescriptor() function to get the socket itself, and there was no change in the problem.

    Quote Originally Posted by adeyblue View Post
    Missing the matching number of calls to WSACleanup (1 per WSAStartup)
    Didn't know that one. I thought WSAStartup and Cleanup were static so it didn't matter.

    Quote Originally Posted by adeyblue View Post
    The first case in Receive has an infinite loop is recv errors or closes
    True. I wasn't using it though, but thanks for the heads up

    Quote Originally Posted by adeyblue View Post
    A nonsense s+1 value to all your select()'s (it's ignored in Windows but not if you ever port it)
    nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

    ^ man page

    Quote Originally Posted by adeyblue View Post
    The send() loops have incorrect logic unless you intended to send the whole message from the start everytime.
    That explains the problem I had before. Thanks!

    Quote Originally Posted by adeyblue View Post
    result from getaddrinfo is never freed
    My fault.

    Quote Originally Posted by adeyblue View Post
    Filling in the wrong member of all the timeval structs
    No. It's correct. u_sec is microseconds so I get the amount of ms and multiply it by 1000 to get correct time.

    Quote Originally Posted by adeyblue View Post
    You should probably shutdown() the sockets before closing them
    Just read about that a while back, but never implemented it.

    Quote Originally Posted by adeyblue View Post
    Code:
    if ((he = gethostbyname(host.c_str())) == 0)
        {
            cout << errno;
            return false;
        }
    and how come the error strategy suddenly switches from WSAGetLastError to errno?
    I got that from previous code, and never changed it.
    Last edited by Rodaxoleaux; 03-07-2012 at 12:45 PM.
    How to ask smart questions
    Code:
    DWORD dwBytesOverwritten;
    BYTE rgucOverWrite[] = {0xe9,0,0,0,0};
    WriteProcessMemory(hTaskManager,(LPVOID)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQuerySystemInformation"),rgucOverWrite,5,&dwBytesOverwritten);

  9. #9
    Rat with a C++ compiler Rodaxoleaux's Avatar
    Join Date
    Sep 2011
    Location
    ntdll.dll
    Posts
    203
    getaddrinfo accepts a char* for the port, not an integer. My error.
    How to ask smart questions
    Code:
    DWORD dwBytesOverwritten;
    BYTE rgucOverWrite[] = {0xe9,0,0,0,0};
    WriteProcessMemory(hTaskManager,(LPVOID)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQuerySystemInformation"),rgucOverWrite,5,&dwBytesOverwritten);

  10. #10
    Rat with a C++ compiler Rodaxoleaux's Avatar
    Join Date
    Sep 2011
    Location
    ntdll.dll
    Posts
    203
    Still having a problem, however. Now I DO get a 10038 error. Although, the socket is valid. Or at least it seems to be as returned by accept(). That doesn't return an error.
    How to ask smart questions
    Code:
    DWORD dwBytesOverwritten;
    BYTE rgucOverWrite[] = {0xe9,0,0,0,0};
    WriteProcessMemory(hTaskManager,(LPVOID)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQuerySystemInformation"),rgucOverWrite,5,&dwBytesOverwritten);

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. fprintf functionality in a multithreaded application
    By dulanjal in forum C Programming
    Replies: 7
    Last Post: 04-07-2011, 08:45 PM
  2. MultiThreaded GUI.
    By execute in forum Windows Programming
    Replies: 6
    Last Post: 05-18-2006, 01:00 PM
  3. Multithreaded
    By adr in forum C++ Programming
    Replies: 14
    Last Post: 02-04-2006, 02:51 PM
  4. Multithreaded Winsock
    By X PaYnE X in forum Windows Programming
    Replies: 6
    Last Post: 01-05-2004, 09:00 AM
  5. writing Multithreaded GUI's
    By WebmasterMattD in forum Linux Programming
    Replies: 2
    Last Post: 01-27-2003, 09:37 AM