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 |