|
From: <mik...@us...> - 2003-12-26 10:04:54
|
Update of /cvsroot/sharedaemon/sharedaemon-ui-web/src/server/network
In directory sc8-pr-cvs1:/tmp/cvs-serv24435/src/server/network
Added Files:
Socket.h Socket.cpp ServerSocket.cpp ServerSocket.h
Log Message:
26/12/2003 Mikael Barbeaux
* Implemented Socket, ServerSocket and SocketException classes.
* Added simple test program for Sockets.
--- NEW FILE: Socket.h ---
/*
* This file is part of webInterface.
* Copyright (C) 2003 Mikael Barbeaux <mik...@us...>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SOCKET_H_
#define _SOCKET_H_
#include <unistd.h>
#include <cstdlib>
#include <string>
#ifdef _WIN32_
#include <winsock.h>
#include <winuser.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
#include "../../exceptions/SocketException.h"
/**
*
* Defines a standard socket implementation.
* This socket simply sends data bytes and receives
* data bytes.
* For a HTTP socket, use the corresponding class into
* http directory.
*
*/
class Socket {
private:
// inet address of this socket
sockaddr_in socket_address;
// state of this socket
bool closed;
// socket's id
int socket_id;
public:
/**
* Create a unconnected socket.
*/
Socket();
/**
* Create a socket ( considered as connected )
* with the given identifiant and address.
*
* @param id - Socket's id
* @param address - inet address of this socket
*/
Socket(int id, sockaddr_in& address);
/**
* Socket destructor
*/
~Socket();
/**
* Test if the socket is closed.
*
* @return bool
*/
bool isClosed();
/**
* Close the socket.
*
* @throw SocketException
*/
void close() throw (SocketException);
/**
* Test if the socket is valid ( have been instancied ).
*
* @return bool
*/
bool isValid();
/**
* Returns this socket's id
*
* @return int
*/
int getId();
/**
* Sends bytes to the client.
*
* @param data - data to send.
* @param size - Size of data.
* @param max - Maximum number of bytes to send each time.
* @throw SocketException.
*/
void send(const char* data, unsigned long int size,
unsigned int max = 4096) throw (SocketException);
/**
* Receives bytes from the client.
*
* @param data - A buffer where to save data.
* @param max - Maximum number of bytes to receive each time.
* @return Number of bytes received.
* @throw SocketException.
*/
unsigned long int receive(char** data, unsigned int max = 4096)
throw (SocketException);
};
#endif
--- NEW FILE: Socket.cpp ---
/*
* This file is part of webInterface.
* Copyright (C) 2003 Mikael Barbeaux <mik...@us...>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Socket.h"
/**
* Default Socket constructor.
* As it doesn't need parameters, the socket
* is considered as not yet connected and
* without any inet address.
*/
Socket::Socket() {
socket_id = -1;
closed = false;
}
/**
* Default Socket constructor.
* As it doesn't need parameters, the socket
* is considered as not yet connected and
* without any inet address.
*/
Socket::Socket(int id, sockaddr_in& addr) {
socket_id = id;
socket_address = addr;
closed = false;
}
/**
* Socket destructor.
*/
Socket::~Socket() {
}
/**
* Returns true if the socket is closed, else return
* false.
*/
bool Socket::isClosed() {
return closed;
}
/**
* Close the socket.
* Throws a SocketException if this socket had
* already been closed or if it's an invalid
* socket.
*/
void Socket::close() throw (SocketException) {
// Throw an exception if invalid or already closed.
if(! isValid())
throw SocketException(InvalidSockExcp,"Invalid socket.","Socket::close");
if(isClosed())
throw SocketException(ClosedSockExcp,"Socket already closed.","Socket::close");
// Close the socket.
#ifdef _WIN32_
::closesocket(socket_id);
#else
::close(socket_id);
#endif
// Set socket's state.
closed = true;
}
/**
* Returns true if the socket is valid (id not equals to -1 ),
* else returns false.
*/
bool Socket::isValid() {
return (socket_id != -1);
}
/**
* Returns this socket's id.
*/
int Socket::getId() {
return socket_id;
}
/**
* Send size bytes to the client connected with this socket.
* At one time, only 'max' bytes are sent to the client.
* Throws a SocketException if an error occurs while
* sending datas.
*/
void Socket::send(const char* data, unsigned long int size,
unsigned int max) throw(SocketException) {
// Throw an exception if invalid or already closed.
if(! isValid())
throw SocketException(InvalidSockExcp,"Invalid socket.","Socket::send");
if(isClosed())
throw SocketException(ClosedSockExcp,"Socket is closed.",
"Socket::send");
// Total number of bytes sent
unsigned long int total_sent = 0;
// Number of bytes sent this time
long int sent = 0;
while(total_sent < size) {
// Try to send max bytes...
if((sent = ::send(socket_id,
data,
((size - total_sent) > max) ? max : (size - total_sent),
0)) > 0) {
total_sent += sent;
data += sent;
}
else if(sent < 0)
// error while sending...
throw SocketException(SendSockExcp, "Error while sending data.",
"Socket::send");
}
}
/**
* Receives data from the client connected to this socket.
* At one time, only 'max' bytes are received from the client.
* Returns the number of bytes received.
* Throws a SocketException if an error occurs while
* receiving data from the client.
*/
unsigned long int Socket::receive(char** data, unsigned int max)
throw (SocketException) {
// Throw an exception if invalid or already closed.
if(! isValid())
throw SocketException(InvalidSockExcp,"Invalid socket.","Socket::receive");
if(isClosed())
throw SocketException(ClosedSockExcp,"Socket is closed.",
"Socket::receive");
// Total number of bytes read
unsigned long int total_read = 0;
// Number of bytes read this time
long int read = max;
// Receive as much data as possible...
while((read > 0) && (read == (int) max)) {
char *buffer = new char[total_read+max+1];
// copy already received bytes
memcpy(buffer,*data,total_read);
delete[] (*data);
// Receive new bytes
read = ::recv(socket_id, (buffer+total_read), max, 0);
if(read <= 0) {
delete[] buffer;
break;
}
buffer[total_read+read] = '\0';
total_read += read;
// Update data
*data = buffer;
}
if(read <= 0)
throw SocketException(RecvSockExcp, "Error while receiving data.",
"Socket::receive");
return total_read;
}
--- NEW FILE: ServerSocket.cpp ---
/*
* This file is part of webInterface.
* Copyright (C) 2003 Mikael Barbeaux <mik...@us...>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ServerSocket.h"
#ifdef _WIN32_
#define socklen_t int
#endif
/**
* Creates a generic ServerSocket.
* At initialization, this socket will
* be unconnected and invalid.
* Call the connect() method to start
* listening for connections.
*/
ServerSocket::ServerSocket() {
// Initialization of server state.
bound = false;
closed = false;
listening = false;
server_id = -1;
}
/**
* Destructs a server socket object.
* It will close the server if not yet
* done.
*/
ServerSocket::~ServerSocket() {
if(! isClosed())
close();
}
/**
* Returns true if the server socket is
* binding to a port, else returns false.
*/
bool ServerSocket::isBound() {
return bound;
}
/**
* Returns true if the server socket is
* listening to a port, else returns false.
*/
bool ServerSocket::isListening() {
return listening;
}
/**
* Returns true if the server socket is
* valid, else returns false.
*/
bool ServerSocket::isValid() {
return (server_id != -1);
}
/**
* Returns true if the server socket is
* closed, else returns false.
*/
bool ServerSocket::isClosed() {
return closed;
}
/**
* Close the server socket.
* Throws a SocketException if the server socket is
* invalid or had been already closed.
*/
void ServerSocket::close() throw (SocketException) {
if(server_id == -1)
throw SocketException(InvalidSockExcp, "Invalid server socket.",
"ServerSocket::close");
if(closed)
throw SocketException(ClosedSockExcp, "Server socket already closed",
"ServerSocket::close");
// Close the server socket
#ifdef _WIN32_
::closesocket(server_id);
#else
::close(server_id);
#endif
// Change server socket state
closed = true;
}
/**
* Validates the server socket. It instanciates
* the socket listening for connections.
* Throws a SocketException if cannot validate
* the socket.
*/
void ServerSocket::validate() throw(SocketException) {
if(server_id != -1)
throw SocketException(AlreadyValidSockExcp, "Server socket is already valid.",
"ServerSocket::validate");
if(closed)
throw SocketException(ClosedSockExcp, "Server socket is closed.",
"ServerSocket::validate");
// create socket ( TCP and Internet )
server_id = socket(AF_INET, SOCK_STREAM, 0);
if(server_id == -1)
throw SocketException(CantCreateSockExcp, "Cannot create server socket.",
"ServerSocket::validate");
}
/**
* Binds the server socket to a given port.
* Throws a SocketException if a problem occured
* while binding : server already bounded, server
* not valid, or cannot bind to given port.
*/
void ServerSocket::bind(int port) throw (SocketException) {
if(server_id == -1)
throw SocketException(InvalidSockExcp, "Invalid server socket.",
"ServerSocket::bind");
if(closed)
throw SocketException(ClosedSockExcp, "Server socket is closed.",
"ServerSocket::bind");
if(bound)
throw SocketException(AlreadyBoundSockExcp, "Server socket is already bound",
"ServerSocket::bind");
// Bind the server socket to given port
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(port);
int ret = ::bind(server_id, (struct sockaddr *) &server_address,
sizeof(struct sockaddr_in));
if(ret == -1)
throw SocketException(CantBindSockExcp, "Cannot bind server socket.",
"ServerSocket::bind");
// change state
bound = true;
}
/**
* Makes the server socket listening for connections.
* Throws a SocketException if it's invalid, if it's not bound
* or if it cannot be listening.
*
* @param max_conn - Maximum number of simultaneous connections.
*/
void ServerSocket::listen(unsigned int max_conn) throw (SocketException) {
if(server_id == -1)
throw SocketException(InvalidSockExcp, "Invalid server socket.",
"ServerSocket::listen");
if(closed)
throw SocketException(ClosedSockExcp, "Server socket is closed.",
"ServerSocket::listen");
if(! bound)
throw SocketException(UnboundSockExcp, "Server socket isn't bound",
"ServerSocket::listen");
// listen for connection
int ret = ::listen(server_id, max_conn);
if(ret == -1)
throw SocketException(CantListenSockExcp,
"Server socket can't listen for connections.", "ServerSocket::listen");
listening = true;
}
/**
* Accepts a connection. It creates a connection
* to a client and inserts it into the Socket object.
* Throws a SocketException if an error occurs when
* accepting or any other reasons ( not valid, not
* bound, not listening ).
*/
Socket* ServerSocket::accept() throw (SocketException) {
if(server_id == -1)
throw SocketException(InvalidSockExcp, "Invalid server socket.",
"ServerSocket::accept");
if(closed)
throw SocketException(ClosedSockExcp, "Server socket is closed.",
"ServerSocket::accept");
if(! bound)
throw SocketException(UnboundSockExcp, "Server socket isn't bound",
"ServerSocket::accept");
if(! listening)
throw SocketException(NotListeningSockExcp,
"Server socket isn't listening for connections", "ServerSocket::accept");
// Client informations
int client_id;
sockaddr_in client_address;
int address_length = sizeof(struct sockaddr_in);
// Accepting connection
client_id = ::accept(server_id, (sockaddr *) &client_address,
(socklen_t *) &address_length);
if(client_id <= 0)
throw SocketException(InvalidSockExcp, "Received socket is invalid.",
"ServerSocket::accept");
// Create socket for this connection
Socket *client = new Socket(client_id, client_address);
return client;
}
--- NEW FILE: ServerSocket.h ---
/*
* This file is part of webInterface.
* Copyright (C) 2003 Mikael Barbeaux <mik...@us...>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SERVER_SOCKET_H_
#define _SERVER_SOCKET_H_
#ifdef _MACOSX_
#define _BSD_SOCKLEN_T_
#endif
#include "Socket.h"
#include "../../exceptions/SocketException.h"
/**
*
* Defines a generic socket for acting as a server.
* This socket will listen for connection and accept
* them, creating an associated Socket object to
* discuss with the client.
*
*/
class ServerSocket {
private:
// address of this server socket
sockaddr_in server_address;
// bound state
bool bound;
// closed state
bool closed;
// listening state
bool listening;
// server identifiant
int server_id;
public:
/**
* Creates a generic server socket.
*/
ServerSocket();
/**
* ServerSocket destructor
*/
~ServerSocket();
/**
* Test if the server socket is bound.
*/
bool isBound();
/**
* Test if the server socket is listening.
*/
bool isListening();
/**
* Test if the server socket is valid.
*/
bool isValid();
/**
* Test if the server socket is closed.
*/
bool isClosed();
/**
* Close the server socket.
*
* @throw SocketException
*/
void close() throw (SocketException);
/**
* Validates the server socket.
*
* @throw SocketException
*/
void validate() throw (SocketException);
/**
* Binds the server socket on the given port.
*
* @param port - Port where to bind server
* @throw SocketException
*/
void bind(int port) throw (SocketException);
/**
* Makes the server socket listening for connections.
*
* @param max_conn - Maximum number of simultaneous connections.
* @throw SocketException
*/
void listen(unsigned int max_conn) throw (SocketException);
/**
* Accepts a connection.
*
* @return Socket* - The connected socket.
* @throw SocketException
*/
Socket* accept() throw (SocketException);
};
#endif
|