Thread: Callback recursion: stack overflow

  1. #1
    Registered User
    Join Date
    Feb 2010
    Posts
    38

    Callback recursion: stack overflow

    Okay, so I've got a socket class:

    Code:
    class ISocket {
    public:
    	ISocket();
    	~ISocket();
    	
    	virtual void OnConnect() = 0;
    	virtual void OnDisconnect() = 0;
    	virtual void OnRecv(const std::string& data) = 0;
    	virtual void OnTimeout() = 0;
    	virtual void OnError(const std::string& data) = 0;
    	
    	void SetHostname(const std::string& hostname);
    	void SetPort(const std::string& port);
    	void SetTimeoutUSec(long int usec);
    	void SetTimeoutSec(long int sec);
    	
    	const std::string GetHostname();
    	const std::string GetPort();
    	long int GetTimeoutSec();
    	long int GetTimeoutUSec();
    	
    	void Connect();
    	void Disconnect();
    	void SendData(const char* format, ...);
    private:
    	void RecvLoop();
    	std::string m_hostname;
    	std::string m_port;
    	long int m_sec;
    	long int m_usec;
    	int m_socket;
    	int pfd[2];
    };
    When Conenct() is called, it will attempt to conenct a socket; calling OnConnect on success, OnDisconnect() on failure, and OnTimeout() on connection timeout. Both OnTimeout() and OnDisconnect() call Connect() again, to automatically reconnect until success, causing recursion. Given enough calls, I'll get a stack overflow... anyone know of an elegant way around this, while maintaining my intended functionality?

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Put a loop in Connect(). Have OnDisconnect and OnTimeout return instead of calling Connect() again, the loop in Connect() will act the same way.

    You might have to add some extra logic, break the loop if calling OnConnect(), or return true or false from OnTimeout and OnDisconnect to break the loop or not. But you should be able to get it to work.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Yes, make the user of the class responsible for calling connect after disconnect.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Feb 2010
    Posts
    38
    Quote Originally Posted by Salem View Post
    Yes, make the user of the class responsible for calling connect after disconnect.
    The user of the class _is_ resonsible for calling connect after disconnect; those functions are pure virtuals.

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    The user of the class _is_ resonsible for calling connect after disconnect; those functions are pure virtuals.
    Just because they are pure virtuals does not mean you are forcing the user to call connect after disconnect. It does mean you are forcing the user to implement said functions but nothing says your base class impls cannot call pure virtual functions. So you cannot assume this type of design by looking at just the interface. The interface does not communicate this design to me in the least.

  6. #6
    Registered User
    Join Date
    Feb 2010
    Posts
    38
    Quote Originally Posted by Bubba View Post
    Just because they are pure virtuals does not mean you are forcing the user to call connect after disconnect. It does mean you are forcing the user to implement said functions but nothing says your base class impls cannot call pure virtual functions. So you cannot assume this type of design by looking at just the interface. The interface does not communicate this design to me in the least.
    I appologize for being misleading. I'm basically trying to reinvent the old mswinsock.ocx I used when programming
    in VB6 (my first language[10?]) years ago. I'm trying to encapsulate all the low-level nonsense in a class and use
    the virtual functions listed in my original post as "callbacks." I was happy with the design until I came home (left it ru-
    nning as a test) and found valgrind yelling at me for my poor choice.

    When connecting, the "callbacks" cause trouble, because no functions are actually capable of returning. RecvLoop()
    has the same problem when it calls OnDisconnect before returning.

    Bummer.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Use messages and a state machine then.

    At the end of say disconnected, you set a state "DISCONNECTED" and you send a message to yourself to "CONNECT".

    You can go round this all day and not eat stack space.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Feb 2010
    Posts
    38
    Quote Originally Posted by Salem View Post
    Use messages and a state machine then.

    At the end of say disconnected, you set a state "DISCONNECTED" and you send a message to yourself to "CONNECT".

    You can go round this all day and not eat stack space.
    Am I getting warmer?

    Code:
    enum {
    	STATE_IDLE,
    	STATE_CONNECTING,
    	STATE_CONNECTED,
    	STATE_DISCONNECTING,
    };
    
    constructor:
    	m_state = STATE_IDLE;
    
    connect:
    	m_state = STATE_CONNECTING
    
    disconnect:
    	m_state = STATE_DISCONNECTING
    
    int handle_socket:
    	// Returns 0 on idle (disconnected and waiting)
    	
    	switch(m_state) {
    	case STATE_IDLE:
    		break;
    	case STATE_CONNECTING:
    		if (m_socket)
    		close(m_socket)
    		// Make m_socket
    		// Set non blocking
    		// connect socket
    		switch (errorno) {
    		case EALREADY:
    			// clock_gettime() check for timeout
    			if (timeout) {
    				m_state = STATE_DISCONNECTING;
    				// OnTimeout()
    			}
    			break;
    		case EISCONN:
    			m_state = STATE_CONNECTED;
    			// OnConnect()
    			break;
    		default:
    			m_state = STATE_DISCONNECTING;
    			// OnError(data)
    		}
    	case STATE_CONNECTED:
    		ret = recv(m_socket);
    		if (ret == -1) {
    			switch (errorno) {
    			case EAGAIN:
    				break;
    			case EWOULDBLOCK:
    				break;
    			case ECONNREFUSED:
    				m_state = STATE_DISCONNECTING;
    				// OnDisconnect()
    				break;
    			default:
    				m_state = STATE_DISCONNECTING;
    				// OnError(data)
    			}
    		} else if (ret == 0) {
    			m_state = STATE_DISCONNECTING;
    			// OnDisconnect()
    		} else {
    			// OnRecv(data)
    		}
    	case STATE_DISCONNECTING:
    		if (m_socket)
    			close(m_socket);
    		m_socket = 0;
    		m_state = STATE_IDLE;
    	}
    	
    	return m_state;
    
    socket.OnConnect() {
    	// dostuff
    }
    
    socket.OnDisconnect() {
    	// dostuff
    	socket.connect
    }
    
    socket.OnRecv(data) {
    	// showstuff
    }
    
    socket.OnError(data) {
    	// showstuff
    	socket.connect
    }
    
    socket.OnTimeout() {
    	// dostuff
    	socket.connect
    }
    Also, how will I be calling handle_socket without losing performance or using too much CPU time?

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Yes, that's the kind of thing I was thinking about.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Stack overflow errors in 3 areas
    By ulillillia in forum C Programming
    Replies: 13
    Last Post: 04-29-2007, 03:20 PM
  2. stack and pointer problem
    By ramaadhitia in forum C Programming
    Replies: 2
    Last Post: 09-11-2006, 11:41 PM
  3. Question about a stack using array of pointers
    By Ricochet in forum C++ Programming
    Replies: 6
    Last Post: 11-17-2003, 10:12 PM
  4. error trying to compile stack program
    By KristTlove in forum C++ Programming
    Replies: 2
    Last Post: 11-03-2003, 06:27 PM
  5. Stack Program Here
    By Troll_King in forum C Programming
    Replies: 7
    Last Post: 10-15-2001, 05:36 PM