# The abstract base class

class SWBaseSocket
  Constructor
  enum base_error
  class SWBaseError
  enum block_type
  listen()
  accept()
  disconnect()
  close_fd()
  send()
  sendmsg()
  recv()
  recvmsg()
  fsend()
  fsendmsg()
  frecv()
  get_fd()
  get_host()
  get_peer()
  set_timeout()
  print_error()
  get_error()
Typical Use
  Server side example
  Client side example
Additional Datatypes

## SWBaseSocket

This is the abstract base class for all socket classes in SocketW. You can't use this class directly but every derived class must implement the methods in this class.
Constructor:

> SWBaseSocket()
> Abstract constructor.

Methods and datatypes:

> enum base_error{ok, fatal, notReady, portInUse, notConnected, msgTooLong, terminated, noResponse, timeout, interrupted}
> The possible error types for this class (and derived classes), see "Error handling" for more information.
> - ok - Operation successful.
> - fatal - Unspecified error.
> - notReady - You should call the method again. Indicates that the function would block (if in noWait/nonblocking mode).
> - portInUse - The port binded to the socket is used by another socket.
> - notConnected - Socket is not connected to any peer or is not valid.
> - msgTooLong - The message size it too big for send(). Not very common, most systems will just wait for the buffer to empty and try again.
> - terminated - Connection terminated. You should call disconnect().
> - noResponse - Peer refuses to respond or there is no one listening on the remote address.
> - timeout - A read/write operation timed out waiting for data (only if a timeout value is set and if in blocking mode).
> - interrupted - The method call was interrupted by a nonblocked system signal (probably when waiting for data).
> class SWBaseError
> The SWBaseError class is defined here.
> enum block_type{blocking, noWait, nonblocking}
> Used in derived classes constructors to set the blocking behaviour of the class:
> - blocking - Everything blocks until completely done.
> - noWait - Methods will assume that data is available when called and will return with the notReady error type if there is a change of blocking a second time (e.g. frecv() can call recv() several times, but will trust the user the first time that data is available and return with notReady if more calls to recv() is necessary). Useful if you want to wait yourself with select().
> - nonblocking - The socket will be truly nonblocking. The error type notReady will be returned if data is not available. You should wait with select() or similar to know when data is available.
> virtual bool listen(int qLimit = 5, SWBaseError *error = NULL)
> Make the socket listen for connections. To accept connections a socket must first be binded to a local address and then a willingness to accept incoming connections must be specified with listen(), and then the connections are accepted with accept(). The optional qLimit argument defines the maximum length the queue of pending connections may grow to. Returns true on success. Possible error types: portInUse, notConnected and fatal.
> virtual SWBaseSocket* accept(SWBaseError *error = NULL)
> Accept an incoming connection. Returns a new socket class connected with the peer or NULL on failure. You can cast the class to the correct type if you need to (e.g. (SWInetSocket *)mysocket). If there is no incoming connection accept() will block until there is one (if not in nonblocking mode). The returned class should be freed with delete when not needed any longer. Possible error types: notReady, notConnected, interrupted, timeout and fatal.
> virtual bool disconnect(SWBaseError *error = NULL)
> Do the disconnect ritual (signal peer, wait for close signal and then close socket). Returns true on success. Possible error types: notConnected, notReady, interrupted, timeout, noResponse and fatal.
> virtual bool close_fd()
> Closes the socket without waiting for the remote peer. Use with care, disconnect() is cleaner. Returns false if the socket already is closed.
> virtual int send(const char *buf, int bytes, SWBaseError *error = NULL)
> Transmit at most the specified number of bytes of "buf" to remote peer. On most systems "bytes" will be the exact number of bytes transmitted if using a blocking socket but some systems might transmit less. If using a nonblocking socket, most systems will however return before the full amount of bytes have been transmitted if it must block (e.g. wait for a buffer) to transmit the remaining bytes (will indicate notReady in that case). Returns the actual amount of bytes sent or -1 on failure. Possible error types: notConnected, notReady, interrupted, timeout, msgTooLong, fatal and terminated.
> virtual int sendmsg(const std::string msg, SWBaseError *error = NULL)
> Same as send() but with a std::string instead.
> virtual int recv(char *buf, int bytes, SWBaseError *error = NULL)
> Receive at most the specified number of bytes and place them in "buf". This means that recv() fetch any data available, up to the requested amount, rather than waiting for the full amount requested. If no data is available, recv() waits until there is (or returns notReady if using a nonblocking socket). You should try to receive as much data as possible every time so no data is discarded (data might be discarded if you leave to much data waiting in the system buffer). Returns the actual amount of bytes received or -1 on failure and 0 if terminated. Possible error types: notConnected, notReady, interrupted, timeout, terminated, fatal and noResponse.
> virtual std::string recvmsg(int bytes = 256, SWBaseError *error = NULL)
> Same as recv() but the received data will be copied to the returned std::string. The returned string will be empty on failure.
> virtual int fsend(const char *buf, int bytes, SWBaseError *error = NULL)
> If using a blocking socket this method should work just as send(). If using the noWait or nonblocking mode then this method might have some advantages over using send() directly. Anyway, this method makes sure that the exact number of bytes specified are sent. In nonblocking mode this method will return with notReady just as send() but will handle the "buf" pointer itself, i.e. you must call this method with exactly the same arguments until all data is sent unlike send() where you must recalculate the arguments every call. Returns "bytes" when finished or a negative integer on failure. If the error type returned is notReady then the returned failure value is the amount of bytes sent so far but negated. The same error types as send().
> virtual int fsendmsg(const std::string msg, SWBaseError *error = NULL)
> Same as fsend() but with a std::string instead. Unlike sendmsg() there is no need to reformat the string on notReady before repeating the call.
> virtual int frecv(char *buf, int bytes, SWBaseError *error = NULL)
> Same as recv() but the exact number of bytes specified are received. In noWait or nonblocking mode notReady is returned if not enough data is available and then the method must be called again with exactly the same arguments (i.e. the "buf" pointer should not be recalculated). Be sure that the remote peer really is going to send at least the specified number of bytes or you might trying to receive bytes that will never be sent. Returns "bytes" when finished, 0 if terminated and a negative integer on failure. If the error type returned is notReady then the returned failure value is the amount of bytes sent so far but negated. The same error types as recv().
> virtual int get_fd(SWBaseError *error)
> Get the socket descriptor. Can for example be used with select(). Returns -1 on failure. Possible error types: notConnected.
> virtual bool get_host(sockaddr *host, SWBaseError *error = NULL)
> Fills the provided sockaddr structure with info about the local host. See man unix(7) or ip(7) for more information about the structure. Returns true on success. Possible error types: fatal and notConnected.
> virtual bool get_peer(sockaddr *peer, SWBaseError *error = NULL)
> Fills the provided sockaddr structure with info about the remote peer. See man unix(7) or ip(7) for more information about the structure. Returns true on success. Possible error types: fatal and notConnected.
> void set_timeout(Uint32 sec, Uint32 usec)
> Sets the timeout value in seconds and microseconds. Used in blocking mode when a method waits for data. This affects the methods with a timeout error type. Doing set_timeout(0,0) means wait forever (default). No errors possible.
> virtual void print_error()
> Prints the last error if any as a human readable message to stderr.
> virtual std::string get_error()
> Returns the last error as a human readable message. The returned string is empty if the last method call didn't fail.

## Typical Use

Sockets are typically used in two ways; server side or client side. The server side starts with binding (bind()) to a local address where it will be listening for incoming connections from the client side. Then the willingness to accept incoming connections must be specified with listen(), and finally incoming connections are accepted with accept(). A new socket connected to the client is created when accepting an incoming connection. The original socket (the listener) can be used to accept more connections and is not itself connected to any client.
The client side only needs to connect() to the server side. The connected socket can then be used to transfer data to and from the server.
Server side example:

    #include "SocketW.h"
    ...
    SWInetSocket listener;
    SWInetSocket *mySocket;

    listener.bind(...);  // bind() is implemented in derived classes
    listener.listen();

    mySocket = (SWInetSocket *)listener.accept();

    // do something with mySocket...
    mySocket->sendmsg("Hello Client!");

    // disconnect and clean up
    mySocket->disconnect();
    delete mySocket;

Client side example:

    #include "SocketW.h"
    ...
    SWInetSocket mySocket;

    mySocket.connect(...);  // connect() is implemented in derived classes

    // do something with mySocket...
    string msg = mySocket.recvmsg();

    // disconnect
    mySocket.disconnect();

## Additional Datatypes

SocketW has some additional datatypes that can be practical to use when it is important to know the exact size of the data you're working with. These datatypes are guaranteed to be the correct size (this is checked when SocketW is compiled).

- Uint8 - Unsigned 8bit (unsigned char).
- Sint8 - Signed 8bit (signed char).
- Uint16 - Unsigned 16bit (unsigned short).
- Sint16 - Signed 16bit (signed short).
- Uint32 - Unsigned 32bit (unsigned int).
- Sint32 - Signed 32bit (signed int).

These are the same datatypes as used in libSDL so make sure to include "SDL.h" before "SocketW.h" to avoid double definitions if you use SocketW with SDL.

Copyright © 2003 Anders Lindström
Last updated 031025