// -*- c++ -*-
//------------------------------------------------------------------------------
//                             IPv4Socket.h
//------------------------------------------------------------------------------
//  Copyright (c) 1998 by Vladislav Grinchenko <vladg@erols.com>
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//------------------------------------------------------------------------------
#ifndef IPV4_SOCKET_Hh
#define IPV4_SOCKET_Hh

#include "assa/Socket.h"
#include "assa/Socketbuf.h"

/** @file IPv4Socket.h

Class IPv4Socket covers domain types AF_INET and AF_UNIX.
IPv4Socket does internal buffering via Socketbuf.
*/

namespace ASSA {
class IPv4Socket : public Socket 
{
public:
	/// Maximum TCP data frame (no options)
	static const int MAXTCPBUFSZ;

	/// Default constructor
	IPv4Socket() 
		: m_path (0), m_rdbuf (new Socketbuf (this)) {
		trace_with_mask("IPv4Socket::IPv4Socket()",SOCKTRACE);
	}

	/** Constructor from file descriptor.
	 *  @param fd_ file descriptor to use
	 */
	IPv4Socket(const int fd_) 
		: m_path (0), m_rdbuf (new Socketbuf (this)) {
		trace_with_mask("IPv4Socket::IPv4Socket(fd_)",SOCKTRACE);

		m_fd = fd_;
	}

	/** Destructor will close connection */
	~IPv4Socket() {
		trace_with_mask("IPv4Socket::~IPv4Socket",SOCKTRACE);
		this->close ();

 		if (m_rdbuf != 0) {
			delete m_rdbuf;
		}
	}

	/** "Virtual constructor".
	    clone() function creates an exact copy of Socket by 
	    dup(2)-ing file descriptor and copying Socket's 
	    internal state.
	*/
	IPv4Socket* clone () const;
	

	/** Create socket. Socket domain type is specified as
	 *  AF_INET for internet socket and AF_UNIX for UNIX domain socket 
	 *  (full duplex pipe). 
	 *
	 *  @param domain_ domain
	 *  @return true if socket is created successfully, false otherwise
	 */
	bool open(const int domain_);

	/** Close socket connection.
	 *  @return true if success, fail if call to ::close() failed.
	 */
	bool close();

	/** Client makes connection with the server at address_. 
	 *  If socket is set to non-blocking mode, most likely connect()
	 *  would return false with errno set to EINPROGRESS. See
	 *  connect(2) manpage for details.
	 *
	 *  @param address_ peer address to connect with
	 *  @return true for success, false for error
	 */

	bool connect(const Address& address_);

	/** Server binds listening socket to its local well-known port. 
	 *  This call should follow the call to open() and precede
	 *  the call to accept().
	 *
	 *  @param my_address_ address to bind to
	 *  @return true if success, false otherwise
	 */
	virtual bool bind (const Address& my_address_);

	/** Accept connection on the listening socket.
	 *  Returned is a COMPLETED connection (meaning that socket pair
	 *  is ready for data transfer and doesn't need call to ::open()).
	 *  This method will block waiting on connection to come if there 
	 *  is no connection requests waiting on the listenning socket queue. 
	 *  To avoid blocking, use ::select() first. 
	 *  
	 *  @return newly created connected socket to the client, 
	 *          or 0 if error.
	 */
	IPv4Socket* accept ();

	/** Read packet of specified size and save it to the given
	 *  buffer. 
	 *
	 *  @param buf_ buffer where packet will be stored
	 *  @param size_ size of the packet to expect
	 *
	 *  @return number of bytes read or -1 on error
	 *          indicating the reason in errno. 0 is returned
	 *          if remote host closed its socket connection.
	 */
	int read (char* buf_, const unsigned int size_);

	/** Perform blocking write by writing packet of specified size.
	 *
	 *  @param buf_ buffer to send
	 *  @param size_ packet size
	 *  @return number of bytes written or -1 for error
	 */
	int write (const char* buf_, const unsigned int size_);


	/// Get socket file descriptor
	const int getHandler () const { return m_fd; }

	/// Get socket domain type
	const int getDomain () const { return m_type; }

	/** Return a pointer to the <B> Socketbuf </B> associated with the 
	    stream. This is part of the construction of a stream, and the 
	    buffer class object is not normally changed. This function may be
	    used to get at <B> Socketbuf </B> functionality directly, 
	    given a Socket object.
	*/
	virtual Streambuf* rdbuf () { return m_rdbuf; }

	/** Set new Socketbuf for internal IO buffering.
	    IPv4Socket object assumes full ownership of the memory
	    pointed by sb_ (it will be release when ~IPv4Socket 
	    destructor is called).
	    @return Old Socketbuf object or sb_ if it is either NULL
	    or matches old Socketbuf object.
	*/
	virtual Streambuf* rdbuf (Streambuf* sb_);

	/** This function returns the number of characters  
	    immediately  available in the get area of the underlying
	    Socketbuf buffer without making a system call if Socket
	    is doing buffering I/O.
	*/
	virtual int in_avail () const { return m_rdbuf->in_avail (); }

private:
	// No copying
	IPv4Socket (const IPv4Socket&);
	IPv4Socket& operator= (const IPv4Socket&);

private:
	//@{

	/// Path of UNIX domain socket
	char*       m_path;

	/// Socketbuf 
	Streambuf*  m_rdbuf;
};

} // end namespace ASSA

#endif // IPV4_SOCKET_Hh



