Loading...
Searching...
No Matches
IPv4Socket.cpp
Go to the documentation of this file.
// -*- c++ -*-
//------------------------------------------------------------------------------
// IPv4Socket.cpp
//------------------------------------------------------------------------------
// Copyright (C) 1997-2002 Vladislav Grinchenko
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//------------------------------------------------------------------------------
//
#if defined(WIN32)
# include <errno.h>
# include <ws2tcpip.h>
#else
# include <sys/errno.h>
#endif
#include "assa/MemDump.h"
#include "assa/IPv4Socket.h"
using namespace ASSA;
Streambuf*
IPv4Socket::
rdbuf (Streambuf* sb_)
{
trace_with_mask("IPv4Socket::rdbuf(sb_)",SOCKTRACE);
if (sb_ == 0 || sb_ == m_rdbuf) {
return (sb_);
}
Streambuf* old = m_rdbuf;
m_rdbuf = sb_;
return (old);
}
bool
IPv4Socket::
open (const int domain_)
{
trace_with_mask("IPv4Socket::open",SOCKTRACE);
m_type = domain_;
m_fd = ::socket(domain_, SOCK_STREAM, 0);
if (!is_valid_handler (m_fd)) {
EL((ASSAERR,"OS::socket() error: m_fd = %d\n", m_fd));
setstate (Socket::failbit);
disable_handler (m_fd);
return (false);
}
DL ((SOCK,"domain = %d, m_fd = %d\n", domain_, m_fd));
clear ();
turnOptionOn (Socket::nonblocking);
return (true);
}
bool
IPv4Socket::
close()
{
trace_with_mask("IPv4Socket::close()",SOCKTRACE);
if (is_valid_handler (m_fd)) {
DL((SOCK,"Closed FD: %d\n",m_fd));
/*--- Flush data in output stream buffer ---*/
flush ();
close_handler(m_fd);
setstate (Socket::failbit);
/*---
Socket can be re-opened in the future.
If there is some bytes left in it since last read(2),
clean them up.
---*/
if (m_rdbuf && m_rdbuf->in_avail ()) {
for (int c; (c=m_rdbuf->sbumpc ()) != EOF;) { }
}
}
return (true);
}
bool
IPv4Socket::
connect (const Address& his_address_)
{
trace_with_mask("IPv4Socket::connect()",SOCKTRACE);
if (!is_valid_handler (m_fd) && open (getDomain()) == false) {
return false;
}
int ret = ::connect (m_fd,
(SA*) his_address_.getAddress(),
his_address_.getLength());
if (ret < 0)
{
int e = get_errno (); // is ASYNC connect in progress?
if (e == EINPROGRESS || e == EWOULDBLOCK) {
DL((SOCK,"FD: %d OS::connect() error\n",m_fd));
}
else {
EL((SOCK,"FD: %d OS::connect() error\n",m_fd));
}
return (false);
}
clear ();
DL((SOCK,"Connection opened on FD: %d\n", m_fd));
return (true);
}
bool
IPv4Socket::
bind (const Address& addr_)
{
trace_with_mask("IPv4Socket::bind",SOCKTRACE);
#if !defined(WIN32)
if ( getDomain() == AF_UNIX ) {
char* p = ((SA_UN *) addr_.getAddress())->sun_path;
m_path = new char[strlen(p)+1];
strcpy(m_path, p);
struct stat sb;
if (stat (m_path, &sb) == 0) {
if ( S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode) ) {
unlink(m_path);
}
}
}
#endif
/*---
From Stevens, Ch 7.5 (p.196):
"Set the SO_REUSEADDR socket option before calling bind(2)
in all TCP servers."
---*/
Assure_return ( turnOptionOn (reuseaddr) );
int rt = ::bind(m_fd, addr_.getAddress(), addr_.getLength());
if ( rt < 0) {
EL((SOCK,"::bind() FD: %d failed\n",m_fd));
setstate (Socket::failbit);
return (false);
}
Assure_return ( (::listen(m_fd, 5) == 0) );
return (true);
}
IPv4Socket*
IPv4Socket::
accept ()
{
trace_with_mask("IPv4Socket::accept",SOCKTRACE);
socklen_t length = 0;
SA* remote_address = NULL;
handler_t new_fd;
disable_handler (new_fd);
if ( getDomain() == AF_UNIX ) {
length = sizeof(struct sockaddr_in);
remote_address = (SA*) new SA_IN;
}
else /* AF_INET */
{
remote_address = (SA*) new SA_UN;
length = sizeof(struct sockaddr_un);
}
memset(remote_address, 0, length);
#if !defined (_CYGWIN32__)
new_fd = ::accept(m_fd, remote_address, &length);
#else
new_fd = ::accept(m_fd, remote_address, (int*)&length);
#endif
if (!is_valid_handler (new_fd)) {
EL((ASSAERR,"::accept() failed (new_fd=%d)\n", new_fd));
close();
return NULL;
}
if (length == sizeof(SA_IN)) {
SA_IN* sa_in = (SA_IN*) remote_address;
DL((SOCK,"Accepted new TCP connection from Addr %s, port %d\n",
inet_ntoa(sa_in->sin_addr), ntohs( sa_in->sin_port)));
}
else {
#if !defined(WIN32)
SA_UN* sa_un = (SA_UN*) remote_address;
DL((SOCK,"Accepted new UNIX connection from %s\n", sa_un->sun_path));
#endif
}
delete remote_address;
IPv4Socket* s = new IPv4Socket (new_fd);
s->clear ();
s->turnOptionOn (Socket::nonblocking);
return s;
}
int
IPv4Socket::
read (char* packet_, const unsigned int size_)
{
trace_with_mask("IPv4Socket::read",SOCKTRACE);
register int len;
register int sz = size_;
char* tmp = packet_;
if (!is_valid_handler (m_fd) < 0) {
return -1;
}
len = 0;
if (m_rdbuf->unbuffered ()) {
/*
--- This needs to be redesigned ---
I should read a character at a time in loop,
until I get all characters, or EWOULDBLOCK or EOF.
If ::read() returns 0 or -1, it will be converted
by sbumpc() into EOF. Otherwise, sbumpc() returns
character read. Is this the right thing here to do?
*/
if ((len = m_rdbuf->sbumpc ()) >= 0) {
*tmp = len;
len = 1;
}
}
else {
len = m_rdbuf->sgetn (tmp, sz);
}
if (len == -1)
{
if (get_errno () != EWOULDBLOCK) {
EL((ASSAERR,"::read (fd=%d) failed.\n",m_fd));
setstate (Socket::failbit);
}
return len;
}
tmp += len;
sz -= len;
if ((size_ - sz) == 0)
{
DL((SOCK,"Peer has dropped connection FD: %d\n",m_fd));
setstate (Socket::failbit | Socket::eofbit);
return 0;
}
DL((SOCKTRACE,"==> FD: %d Received %d bytes\n", m_fd, size_ - sz));
MemDump::dump_to_log (SOCKTRACE, "Data received:", packet_, size_ - sz);
/*
Return number of bytes read. If all requested bytes have been
read, then sz is 0 and size_ is returned. If sz != 0, then
writer has sent us a partial packet.
*/
return (size_ - sz);
}
int
IPv4Socket::
write(const char* packet_, const unsigned int size_)
{
trace_with_mask("IPv4Socket::write()",SOCKTRACE);
int ret = 0;
if (!is_valid_handler (m_fd)) {
return -1;
}
if (m_rdbuf->unbuffered ())
{
int wlen = size_;
char* p = (char*) packet_;
while (wlen-- > 0) {
if (m_rdbuf->sputc (*p++) == EOF) {
return (EOF);
}
}
ret = p - packet_;
}
else {
ret = m_rdbuf->sputn ((char*) packet_, size_);
}
if (ret > 0) {
DL((SOCK,"<= FD: %d Wrote %d bytes (requested %d bytes)\n",
m_fd, ret, size_));
MemDump::dump_to_log (SOCK, "Data written", (char*)packet_, ret);
}
return ret;
}
IPv4Socket*
IPv4Socket::
clone () const
{
const char self[] = "IPv4Socket::clone";
trace_with_mask(self,SOCKTRACE);
handler_t nfd = dup (m_fd);
IPv4Socket* s = new IPv4Socket (nfd);
DL((SOCK,"Original socket has %d bytes in its get_area\n",
m_rdbuf->in_avail ()));
if (!is_valid_handler (nfd) || !good ()) {
s->setstate (Socket::failbit);
}
else {
s->clear ();
}
return s;
}
Assure_return
#define Assure_return(exp_)
Test condition and return bool from a function if assertion fails.
Definition Assure.h:64
IPv4Socket.h
Class IPv4Socket covers domain types AF_INET and AF_UNIX.
EL
#define EL(X)
A macro for writing error message to the Logger.
Definition Logger.h:285
DL
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
trace_with_mask
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
MemDump.h
A Hex/Ascii memory dump of similar to od(1) UNIX utility.
ASSA::Address
Definition Address.h:51
ASSA::AutoPtrRef
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
ASSA::IPv4Socket
Definition IPv4Socket.h:26
ASSA::IPv4Socket::accept
IPv4Socket * accept()
Accept connection on the listening socket.
Definition IPv4Socket.cpp:177
ASSA::IPv4Socket::write
int write(const char *buf_, const unsigned int size_)
Perform blocking write by writing packet of specified size.
Definition IPv4Socket.cpp:294
ASSA::IPv4Socket::IPv4Socket
IPv4Socket()
Default constructor.
Definition IPv4Socket.h:32
ASSA::IPv4Socket::clone
IPv4Socket * clone() const
"Virtual constructor".
Definition IPv4Socket.cpp:330
ASSA::IPv4Socket::rdbuf
virtual Streambuf * rdbuf()
Return a pointer to the Socketbuf associated with the stream.
Definition IPv4Socket.h:146
ASSA::IPv4Socket::close
bool close()
Close socket connection.
Definition IPv4Socket.cpp:66
ASSA::IPv4Socket::connect
bool connect(const Address &address_)
Client makes connection with the server at address_.
Definition IPv4Socket.cpp:93
ASSA::IPv4Socket::open
bool open(const int domain_)
Create socket.
Definition IPv4Socket.cpp:42
ASSA::IPv4Socket::m_rdbuf
Streambuf * m_rdbuf
Socketbuf.
Definition IPv4Socket.h:176
ASSA::IPv4Socket::bind
virtual bool bind(const Address &my_address_)
Server binds listening socket to its local well-known port.
Definition IPv4Socket.cpp:124
ASSA::IPv4Socket::getDomain
const int getDomain() const
Get socket domain type.
Definition IPv4Socket.h:138
ASSA::IPv4Socket::read
int read(char *buf_, const unsigned int size_)
Read packet of specified size and save it to the given buffer.
Definition IPv4Socket.cpp:231
ASSA::IPv4Socket::m_path
char * m_path
Path of UNIX domain socket.
Definition IPv4Socket.h:173
ASSA::MemDump::dump_to_log
static void dump_to_log(unsigned long mask_, const char *info_, const char *msg_, int len_)
Write hex/ascii dump of a memory region to log file.
Definition MemDump.cpp:111
ASSA::Socket::m_type
int m_type
Socket domain type.
Definition Socket.h:488
ASSA::Socket::setstate
void setstate(iostate flag_)
Set socket state to flag_ by adding flag_ to the existing state.
Definition Socket.h:577
ASSA::Socket::close_handler
static void close_handler(handler_t &socket_)
Close socket endpoint in a portable way.
Definition Socket.h:448
ASSA::Socket::turnOptionOn
bool turnOptionOn(opt_t opt_)
Enable socket option.
Definition Socket.cpp:185
ASSA::Socket::reuseaddr
@ reuseaddr
Allow local address reuse.
Definition Socket.h:100
ASSA::Socket::nonblocking
@ nonblocking
Set Socket to a non-blocking mode (O_RDWR|O_NONBLOCK).
Definition Socket.h:115
ASSA::Socket::m_fd
handler_t m_fd
File descriptor.
Definition Socket.h:485
ASSA::Socket::good
bool good() const
Indicates no error on the socket.
Definition Socket.h:315
ASSA::Socket::clear
void clear(iostate state_=Socket::goodbit)
Clear the socket state. Closed socket remains in bad state.
Definition Socket.h:571
ASSA::Socket::flush
virtual Socket & flush()
This function simply calls the public "synchronizing" function rdbuf()->pubsync() (assuming the assoc...
Definition Socket.cpp:74
ASSA::Socket::eofbit
@ eofbit
indicates that an input operation reached the end of an input sequence
Definition Socket.h:82
ASSA::Socket::failbit
@ failbit
indicates that an input operation failed to read the expected characters, or that an output operation...
Definition Socket.h:84
ASSA::Streambuf
Streambuf class.
Definition Streambuf.h:91
ASSA::Streambuf::sputc
int sputc(char c_)
This function stores c just after the put pointer, and advances the pointer one position,...
Definition Streambuf.h:568
ASSA::Streambuf::sbumpc
int sbumpc()
This function should probably have been called `‘sgetc’'.
Definition Streambuf.h:539
ASSA::Streambuf::in_avail
int in_avail()
This function returns the number of characters immediately available in the get area.
Definition Streambuf.h:399
ASSA::Streambuf::unbuffered
void unbuffered(int i_)
If i_ is non-zero, then all IO operations are buffered.
Definition Streambuf.h:417
ASSA::Streambuf::sputn
int sputn(char *b_, int len_)
From the location pointed to by ptr, stores exactly len characters after the put pointer,...
Definition Streambuf.h:579
ASSA::Streambuf::sgetn
int sgetn(char *b_, int len_)
This function gets the next len_ characters following the get pointer, copying them to the char array...
Definition Streambuf.h:559
ASSA
Definition Acceptor.h:40
ASSA::SOCK
@ SOCK
Class Socket & friends messages
Definition LogMask.h:41
ASSA::SOCKTRACE
@ SOCKTRACE
Extended Socket & friends messages
Definition LogMask.h:42
ASSA::ASSAERR
@ ASSAERR
ASSA and system errors
Definition LogMask.h:34
ASSA::is_valid_handler
bool is_valid_handler(handler_t socket_)
Detect socket() error in a portable way.
Definition Logger_Impl.h:100
ASSA::disable_handler
void disable_handler(handler_t &socket_)
Set socket descriptor to invalid value in a portable way.
Definition Logger_Impl.h:108
ASSA::get_errno
int get_errno()
Fetch error number in a portable way.
Definition Logger_Impl.h:115