blob: 06a3d0644ff8542e39c546e19266ecfd0f81e47f [file] [log] [blame]
/*
* Copyright 2015 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// This defines a very thin interface for basic functions that any connection
// should support. See connection.h for actual
// examples.
///////////////////////////////////////////////////////////////////////////////
#ifndef HERON_COMMON_SRC_CPP_NETWORK_BASECONNECTION_H_
#define HERON_COMMON_SRC_CPP_NETWORK_BASECONNECTION_H_
#include <sys/un.h>
#include <arpa/inet.h>
#include <functional>
#include "basics/basics.h"
#include "network/event_loop.h"
#include "network/network_error.h"
/**
* This denotes the endpoint of an connection. It consists of the socket
* address of the endpoint as well as the file descriptor that we use
* for read/writes.
*/
class ConnectionEndPoint {
public:
explicit ConnectionEndPoint(bool _unix_socket) {
fd_ = -1;
unix_socket_ = _unix_socket;
}
struct sockaddr* addr() {
if (unix_socket_) {
return (struct sockaddr*)&un_addr_;
} else {
return (struct sockaddr*)&in_addr_;
}
}
socklen_t addrlen() {
if (unix_socket_)
return sizeof(un_addr_);
else
return sizeof(in_addr_);
}
void set_fd(sp_int32 _fd) { fd_ = _fd; }
sp_int32 get_fd() { return fd_; }
bool is_unix_socket() const { return unix_socket_; }
private:
sp_int32 fd_;
bool unix_socket_;
struct sockaddr_in in_addr_;
struct sockaddr_un un_addr_;
};
/**
* Options that the server passes to the Connection.
* Currently we just have the maximum packet size allowed.
*/
struct ConnectionOptions {
sp_uint32 max_packet_size_;
sp_int64 high_watermark_;
sp_int64 low_watermark_;
};
/*
* An abstract base class to represent a network connection between 2 endpoints.
* Provides support for non-blocking reads and writes.
*/
class BaseConnection {
public:
// The state of the connection
enum State {
// This is the state of the connection when its created.
INIT = 0,
// Connected. Read/Write going fine
CONNECTED,
// socket disconnected. No read writes happening
DISCONNECTED,
// socket is marked to be disconnected.
TO_BE_DISCONNECTED,
};
// Whether a read/write would block?
enum ReadWriteState { NOTREGISTERED, READY, NOTREADY, ERROR };
BaseConnection(ConnectionEndPoint* _endpoint, ConnectionOptions* _options, EventLoop* eventLoop);
virtual ~BaseConnection();
/**
* Start the connection. Should only be called when in INIT state.
* Upon success, moves the state from INIT to CONNECTED.
* Return 0 -> success (ready to send/receive packets)
* Return -1 -> failure.
*
* TODO (vikasr): return the reason for failure (error codes)
*/
sp_int32 start();
/**
* Close the connection. This will disable the connection from receiving and sending the
* packets. This will also close the underlying socket structures and invoke a close callback
* if any was registered. Moves the state to DISCONNECTED.
*/
void closeConnection();
/**
* Register a callback to be called upon connection close
*/
void registerForClose(VCallback<NetworkErrorCode> cb);
sp_string getIPAddress();
sp_int32 getPort();
protected:
/**
* Writes data out on this connection
* This method is called by the base class if the connection fd is
* registeredForWrite and it is writable.
*
* A return value of:
* - 0 indicates the data is successfully written.
* - negative indicates some error.
*/
virtual sp_int32 writeIntoEndPoint(sp_int32 _fd) = 0;
/**
* A way for base class to know if the derived class still has data to be written.
* This is called after WriteIntoEndPoint.
* If true, base class will registerForWrite until this method returns false.
*/
virtual bool stillHaveDataToWrite() = 0;
/**
* Called after WriteIntoEndPoint is successful.
* Usually meant for cleaning up packets that have been sent.
*/
virtual void handleDataWritten() = 0;
/**
* Called by the base class when the connection fd is readable.
* The derived classes read in the data coming into the connection.
*
* A return value of:
* - 0 indicates the data is successfully read.
* - negative indicates some error.
*/
virtual sp_int32 readFromEndPoint(sp_int32 _fd) = 0;
/**
* Called after ReadFromEndPoint is successful.
* Meant for processing packets that have been received.
*/
virtual void handleDataRead() = 0;
/*
* Derived class calls this method when there is data to be sent over the connection.
* Base class will registerForWrite on the connection fd to be notified when it is writable.
*/
sp_int32 registerForWrite();
// Get the fd
sp_int32 getConnectionFd() const { return mEndpoint->get_fd(); }
// Endpoint read registration
sp_int32 unregisterEndpointForRead();
sp_int32 registerEndpointForRead();
// Connection otions.
ConnectionOptions* mOptions;
private:
// Internal callback that is invoked when a read event happens on a
// connected sate.
void handleRead(EventLoop::Status);
// Internal callback that is invoked when a write event happens on a
// connected sate. In this routine we actually send the packets out.
void handleWrite(EventLoop::Status);
// A Connection can get closed by the connection class itself(because
// of an io error). This is the method used to do that.
void internalClose();
// Connect status of this connection
State mState;
// Whether we are ready to read.
ReadWriteState mReadState;
// Whether we are ready to write.
ReadWriteState mWriteState;
// The user registered callbacks
VCallback<NetworkErrorCode> mOnClose;
// Our own callbacks that we register for internal reads/write events.
VCallback<EventLoop::Status> mOnRead;
VCallback<EventLoop::Status> mOnWrite;
// Connection Endpoint
ConnectionEndPoint* mEndpoint;
// The underlying event loop
EventLoop* mEventLoop;
bool mCanCloseConnection;
};
#endif // HERON_COMMON_SRC_CPP_NETWORK_BASECONNECTION_H_