/*****************************
File:      sockwrap.h
Language:   C++ (header)
Project:    H3DNetworkingUtils
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is H3DNetworkingUtils v1.0.

The Initial Developer of the Original Code is CSIRO.
Portions created by the Initial Developer are Copyright (C) 1009 CSIRO. All Rights Reserved.
Contributor(s):
    Chris Gunn  <Chris.Gunn@csiro.au> <ChrisJGunn@gmail.com>
***************************/

// The sockwrap class provides a class wrapper for socket communications.

#ifndef _sockwrap_
#define _sockwrap_

/* Distributed under a BSD type license. See the netwrap COPYRIGHT file */

#include "H3DNetworkingUtils/inetaddr.h"
#include "H3DNetworkingUtils/Config.h"

#ifndef SHUT_RD
#define SHUT_RD   0
#define SHUT_WR	  1
#define SHUT_RDWR 2
#endif

//****	 Abstract socket class, all inherit from

class H3D_NETWORKING_UTILS_DLL_SPEC  CoreSock {
  public:
    CoreSock ();
    virtual ~CoreSock ();

    // No operations to open: depends on subclass
    virtual void close ();

    // Binary IO
    virtual int read (void * dest, int max);
    virtual int readLine (char * line, int max);

    // Text IO
    virtual int write (void * source, int count);
    virtual int writeLine (char * line);

};

//****	Common code for UDP and TCP sockets

class H3D_NETWORKING_UTILS_DLL_SPEC  InetSock : public CoreSock {
  protected:
    int	   sock;
    int	   kind;	// STREAM or DGRAM
    InetAddr local, remote;

  public:
    InetSock (int kind, int fd);
    virtual ~InetSock ();
    
    virtual void close ();

    // Client connect    
    virtual int connect (InetAddr * endpoint);

    // For servers. Queue length is meaningless for DGRAM sockets
    // and has one special value "don't listen" for STREAMs
    virtual int bind (InetAddr * endpoint, int qLength = 4);
    enum { ActiveBind = -1 };

    // Attributes
    void * sysRef ()  { return (void *)sock; };

    virtual InetAddr * localAddress ();
    virtual InetAddr * remoteAddress ();

    virtual int isUDP ();
    virtual int isTCP ();

    // Set time out for read (useful) and write (less so)
    virtual void setTimeOut (int millisecs);
    virtual int  timeOut ();

    bool dataReady();
    // Returns true if there is data on the socket ready for reading.

  protected:
    int	   ioWait;	// In milliseconds. Default zero = forever
    struct timeval tv;
};

//****	UDP datagram socket	****

class H3D_NETWORKING_UTILS_DLL_SPEC  UDPSock : public InetSock {

  public:
    UDPSock ();
    virtual ~UDPSock ();

    // Remember that these won't return EOF for unconnected
    virtual int read (void * dest, int max);
    virtual int write (void * source, int count);

    // Needed by servers which accept incoming from anyone.
    // Typically address filled in by receive is used for send.
    virtual int receive (void * dest, int max, InetAddr * sender);
    virtual int send (void * source, int count, InetAddr * target);
    
    
};

//****	TCP stream socket

class H3D_NETWORKING_UTILS_DLL_SPEC  TCPSock : public InetSock {
  protected:
    // Needed for thread-safe readline
    char * readBuf;	// Allocated MaxLineSize
    char * bufPtr;
    int	   bufCount;

    int nextChar (char * c);

  public:
    TCPSock (int fd); // Need to create from existing socket on accept
    virtual ~TCPSock ();

    enum { MaxLineSize = 256 };
    
    virtual TCPSock * accept ();

    virtual void shutdown (int direction);

    virtual int read (void * dest, int max);
    virtual int readLine (char * line, int max);

    virtual int write (void * source, int count);
    virtual int writeLine (char * line);
    
};

// Next version: add a file socket that is created from two
// stdio streams so we can simulate network traffic from disk.

#endif
