Loading...
Searching...
No Matches
Socket.cpp
Go to the documentation of this file.
// -*- c++ -*-
//------------------------------------------------------------------------------
// $Id: Socket.cpp,v 1.13 2006/09/24 17:35:33 vlg Exp $
//------------------------------------------------------------------------------
// Socket.C
//------------------------------------------------------------------------------
// Copyright (c) 1999,2005 by 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.
//------------------------------------------------------------------------
// Created: 03/22/99
//------------------------------------------------------------------------
#include <sstream>
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__CYGWIN32__) || defined (__GNU__)
# include <sys/ioctl.h>
#endif
#if defined (__NetBSD__)
# include <sys/filio.h>
# include <sys/ioctl.h>
#endif
#if defined (WIN32)
# define O_NONBLOCK 04000
typedef unsigned int socklen_t;
#endif
#include "assa/Socket.h"
#include "assa/XDRHack.h"
using namespace ASSA;
const int ASSA::Socket::PGSIZE = 4096;
int
Socket::
getBytesAvail (void) const
{
trace_with_mask("Socket::getBytesAvail",SOCKTRACE);
Socket* This = (Socket*) this;
u_long ba = 0;
int ret = 0;
#if defined(WIN32)
ret = ioctlsocket (m_fd, FIONREAD, &ba);
#else
ret = ioctl (m_fd, FIONREAD, &ba);
#endif
if (ret == -1) {
EL((ASSAERR,"ioctl(2) failed with ret: %d\n", ret));
return ret;
}
ba += This->rdbuf ()->in_avail ();
DL((SOCKTRACE,"%ld bytes available for reading\n", ba));
return (int(ba));
}
Socket&
Socket::
flush ()
{
if (good () && rdbuf ()) {
if (rdbuf ()->pubsync () == EOF) {
setstate (badbit);
}
}
return (*this);
}
int
Socket::
set_option (int level_, int optname_, int val_)
{
int ret = setsockopt (m_fd,
level_,
optname_,
(const char*) &val_,
sizeof (val_));
if (ret < 0) {
setstate (Socket::failbit);
}
return ret;
}
int
Socket::
set_fd_options (long flags_)
{
trace_with_mask("Socket::set_fd_options",SOCKTRACE);
int val;
int ret;
#if defined (WIN32)
u_long set_nonblock = 1;
if ((val = ioctlsocket (m_fd, FIONBIO, &set_nonblock)) == 0) {
m_nonblocking = true;
return 0;
}
return -1;
#else // POSIX/UNIX
if ((val = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
return -1;
}
val |= flags_; // turn flags on
DL ((SOCKTRACE,"Set flags fcntl(%d, %s)\n", m_fd,
decode_fcntl_flags (val).c_str ()));
ret = ::fcntl (m_fd, F_SETFL, val);
val = ::fcntl (m_fd, F_GETFL, 0);
DL ((SOCKTRACE,"Flags are set to %s via fcntl(25)\n",
decode_fcntl_flags (val).c_str ()));
return (ret);
#endif
}
int
Socket::
clear_fd_options (long flags_)
{
trace_with_mask("Socket::clear_fd_options",SOCKTRACE);
long oldflags;
long newflags;
int ret;
#if defined (WIN32)
u_long set_block = 0;
if ((ret = ioctlsocket (m_fd, FIONBIO, &set_block)) == 0) {
m_nonblocking = false;
return 0;
}
return -1;
#else
if ((oldflags = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
return -1;
}
newflags = oldflags & ~flags_; // clear flags
DL ((SOCKTRACE,"Set flags fcntl(%d, %s)\n", m_fd,
decode_fcntl_flags (newflags).c_str ()));
ret = ::fcntl (m_fd, F_SETFL, newflags);
newflags = ::fcntl (m_fd, F_GETFL, 0);
DL ((SOCKTRACE,"Flags are set to %s via fcntl(%d)\n",
decode_fcntl_flags (newflags).c_str ()));
return (ret);
#endif
}
bool
Socket::
turnOptionOn (opt_t opt_)
{
trace_with_mask("Socket::turnOptionOn",SOCKTRACE);
if (nonblocking == opt_)
return set_fd_options (O_NONBLOCK);
int optname;
if (reuseaddr == opt_)
optname = SO_REUSEADDR;
else {
EL((ASSAERR,"Invalid socket option\n"));
return false;
}
return set_option (SOL_SOCKET, optname, 1) == 0;
}
bool
Socket::
turnOptionOff (opt_t opt_)
{
trace_with_mask("Socket::turnOptionOff",SOCKTRACE);
if (nonblocking == opt_)
return clear_fd_options (O_NONBLOCK);
int optname;
if (reuseaddr == opt_)
optname = SO_REUSEADDR;
else {
EL((ASSAERR,"Invalid socket option\n"));
return false;
}
return set_option (SOL_SOCKET, optname, 0) == 0;
}
bool
Socket::
setOption (opt_t opt_, int arg_)
{
trace_with_mask("Socket::setOption(,)",SOCKTRACE);
int optname;
if (nonblocking == opt_) {
return (arg_ == 1) ? set_fd_options (O_NONBLOCK)
: clear_fd_options (O_NONBLOCK);
}
if (rcvlowat == opt_) {
optname = SO_RCVLOWAT;
}
else if (sndlowat == opt_) {
optname = SO_SNDLOWAT;
}
else {
EL((ASSAERR,"Invalid socket option\n"));
return false;
}
return set_option (SOL_SOCKET, optname, arg_) == 0;
}
int
Socket::
getOption (opt_t opt_) const
{
trace_with_mask("Socket::getOption",SOCKTRACE);
int optval = 0;
if (nonblocking == opt_)
{
#if defined (WIN32)
return (m_nonblocking ? 1 : 0);
#else
if ((optval = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
return -1;
}
return ((optval & O_NONBLOCK) == O_NONBLOCK ? 1 : 0);
#endif
}
int optname;
int level = SOL_SOCKET;
bool bin = false;
socklen_t len = sizeof (optval);
int ret;
if (rcvlowat == opt_) {
optname = SO_RCVLOWAT;
}
else if (sndlowat == opt_) {
optname = SO_SNDLOWAT;
}
else if (reuseaddr == opt_) {
optname = SO_REUSEADDR;
bin = true;
}
else {
EL((ASSAERR,"Invalid socket option\n"));
return (-1);
}
#if defined (__CYGWIN32__) || defined (WIN32)
ret = getsockopt (m_fd, level, optname, (char*) &optval, (int*)&len);
#else // posix/unix
ret = getsockopt (m_fd, level, optname, (char*) &optval, &len);
#endif
if (ret < 0) {
return (-1);
}
if (bin) {
return (ret == 0 ? 0 : 1);
}
return (ret);
}
int
Socket::
ignore(int n_, int delim_)
{
trace_with_mask("Socket::ignore",SOCKTRACE);
register int b;
register int count = 0;
register char c;
if (n_ == INT_MAX && delim_ == EOF) {
char buf[PGSIZE];
while ((b = read (buf, PGSIZE))) {
count += b;
}
setstate (Socket::eofbit|Socket::failbit);
return count;
}
for (; n_; n_--, count++) {
if ( (b = read (&c, 1)) == 0 ) {
setstate (Socket::eofbit|Socket::failbit);
break;
}
if ( c == delim_ )
break;
}
return count;
}
//-----------------------------------------------------------------------------
// Input operators
//-----------------------------------------------------------------------------
Socket&
Socket::
operator>>(char& n_)
{
int c = 0;
int len = sizeof (int);
XDR xdrs;
xdrmem_create (&xdrs, (caddr_t) &c, len, XDR_DECODE);
if (read ((char* ) &c, len) == len) {
xdr_char (&xdrs, &n_);
}
else {
setstate (Socket::eofbit|Socket::failbit);
}
xdr_destroy(&xdrs);
return *this;
}
Socket&
Socket::
operator>> (std::string& s_)
{
char c = 0;
size_t n = 0;
s_ = "";
(*this) >> n;
if (n == 0) {
return *this;
}
size_t len = n;
while (len-- && read (&c, 1) == 1) {
s_ += c;
}
ignore (4 - n % 4);
return *this;
}
Socket&
Socket::
operator>> (short& n_)
{
short val;
if (read ((char*) &val, sizeof(short)) == sizeof(short)) {
n_ = (short) ntohs ((short)val);
}
else {
setstate (Socket::eofbit|Socket::failbit);
}
return *this;
}
Socket&
Socket::
operator>> (unsigned short& n_)
{
u_short val;
if (read ((char*) &val, sizeof(u_short)) == sizeof(u_short)) {
n_ = (u_short) ntohs ((u_short)val);
}
else {
setstate (Socket::eofbit|Socket::failbit);
}
return *this;
}
#define LONGEST long
/* On 64-bit platforms, sizeof (long) = 8 bytes.
* ntohl()/htonh() operats only on int32_t types which is 4 bytes long
* everywhere. So, for 64-bit longs we need to process twice as much
* and swapt data accordingly.
*/
#define READ_INT(TYPE) \
Socket& Socket::operator>>(TYPE& n_) \
{\
LONGEST val;\
int typesz = sizeof(TYPE);\
if (read ( (char* ) &val, typesz) == typesz) {\
if (sizeof(int32_t) <= typesz) {\
n_ = (TYPE) ntohl (val); \
}\
else {\
if (Socket::is_little_endian ()) {\
*((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val)) );\
*((int32_t*)(&n_) ) = ntohl (*((int32_t*)(&val))+1);\
}\
else {\
*((int32_t*)(&n_) ) = ntohl (*((int32_t*)(&val)) );\
*((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val))+1);\
}\
}\
}\
else {\
setstate (Socket::eofbit|Socket::failbit);\
}\
return *this;\
}
READ_INT(int);
READ_INT(unsigned int);
READ_INT(long);
READ_INT(unsigned long);
Socket&
Socket::
operator>> (float& n_)
{
float val;
XDR xdrs;
xdrmem_create (&xdrs, (caddr_t) &val, sizeof(float), XDR_DECODE);
if (read ((char*) &val, sizeof(float)) == sizeof(float)) {
xdr_float (&xdrs, &n_);
}
else {
setstate (Socket::eofbit|Socket::failbit);
}
xdr_destroy (&xdrs);
return *this;
}
Socket&
Socket::
operator>> (double& n_)
{
double val = 0;
XDR xdrs;
xdrmem_create (&xdrs, (caddr_t) &val, sizeof(double), XDR_DECODE);
if (read ((char*) &val, sizeof(double)) == sizeof(double)) {
xdr_double (&xdrs, &n_);
}
else {
setstate (Socket::eofbit|Socket::failbit);
}
xdr_destroy (&xdrs);
return *this;
}
//-----------------------------------------------------------------------------
// Output operators
//-----------------------------------------------------------------------------
Socket&
Socket::
operator<< (char n_)
{
/* See comment to operator>>(char n_) */
int buf = 0;
int len = sizeof (int);
XDR xdrs;
xdrmem_create (&xdrs, (caddr_t) &buf, len, XDR_ENCODE);
xdr_char (&xdrs, &n_);
if (write ((const char*) &buf, len) != len) {
(Socket::eofbit|Socket::failbit);
}
xdr_destroy (&xdrs);
return *this;
}
Socket&
Socket::
operator<< (const std::string& s_)
{
static const char pad [4] = { 0, 0, 0, 0 };
(*this) << s_.length ();
int ret = write (s_.c_str (), s_.length ());
if ( ret != s_.length () ) {
setstate (Socket::eofbit|Socket::failbit);
}
size_t r = 4 - s_.length() % 4;
if (r) {
if (write (pad, r) != r) {
setstate (Socket::eofbit|Socket::failbit);
}
}
return *this;
}
Socket& Socket::
operator<< (short n_)
{
short val = (short) htons((short)n_);
if (write ((const char*) &val, sizeof(short)) != sizeof(short))
{
setstate (Socket::eofbit|Socket::failbit);
}
return *this;
}
Socket& Socket::
operator<< (unsigned short n_)
{
u_short val = (u_short) htons((u_short)n_);
if (write ((const char*) &val, sizeof(u_short)) != sizeof(u_short))
{
setstate (Socket::eofbit|Socket::failbit);
}
return *this;
}
#define WRITE_INT(TYPE) \
Socket& Socket::operator<< (TYPE n_) \
{ \
LONGEST val;\
int typesz = sizeof(TYPE);\
if (sizeof(int32_t) <= typesz) {\
val = (TYPE) ntohl (n_); \
}\
else {\
if (Socket::is_little_endian ()) {\
*((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_)) );\
*((int32_t*)(&val) ) = htonl (*((int32_t*)(&n_))+1);\
}\
else {\
*((int32_t*)(&val) ) = htonl (*((int32_t*)(&n_)) );\
*((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_))+1);\
}\
}\
if (write ((const char*) &val, typesz) != typesz) {\
setstate (Socket::eofbit|Socket::failbit);\
}\
return *this;\
}
WRITE_INT(int);
WRITE_INT(unsigned int);
WRITE_INT(long);
WRITE_INT(unsigned long);
Socket&
Socket::
operator<< (float n_)
{
float buf, f = n_;
XDR xdrs;
xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(float), XDR_ENCODE);
xdr_float (&xdrs, &f);
int ret = write ((const char*) &buf, sizeof(float));
xdr_destroy (&xdrs);
if ( ret != sizeof(float) ) {
setstate (Socket::eofbit|Socket::failbit);
}
return *this;
}
Socket&
Socket::
operator<< (double n_)
{
double buf, f = n_;
XDR xdrs;
xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(double), XDR_ENCODE);
xdr_double (&xdrs, &f);
int ret = write ((const char*) &buf, sizeof(double));
xdr_destroy (&xdrs);
if ( ret != sizeof(double) ) {
setstate (Socket::eofbit|Socket::failbit);
}
return *this;
}
void
Socket::
dumpState (void) const
{
trace_with_mask("Socket::dumpState",SOCKTRACE);
char state_set[] = "[ set]\n";
char state_not_set[] = "[not set]\n";
std::ostringstream msg;
msg << "\n";
msg << "\tTesting good() ....... ";
if (this->good ()) msg << state_set;
else msg << state_not_set;
msg << "\tTesting eof() ........ ";
if (this->eof ()) msg << state_set;
else msg << state_not_set;
msg << "\tTesting fail() ....... ";
if (this->fail ()) msg << state_set;
else msg << state_not_set;
msg << "\tTesting bad() ........ ";
if (this->bad ()) msg << state_set;
else msg << state_not_set;
msg << "\tTesting !() .......... ";
if ( !(*this) ) msg << state_set;
else msg << state_not_set;
msg << "\tTesting void *() ..... ";
if ( *this ) msg << state_set;
else msg << state_not_set;
msg << "\tTesting nonblocking... ";
if (getOption (nonblocking) == 1) msg << state_set;
else msg << state_not_set;
/*--- Terminate stream buffer ---*/
msg << std::ends;
DL((SOCKTRACE,"%s\n", msg.str ().c_str ()));
}
bool
Socket::
is_little_endian ()
{
union {
char c [sizeof (short)];
short v;
} endian_u;
endian_u.v = 256;
return (endian_u.c [0] == 0);
}
string
Socket::
decode_fcntl_flags (long mask_)
{
string answer;
#if !defined (WIN32)
if (mask_ & O_RDONLY) {
answer = "O_RDONLY|"; // 000000
}
if (mask_ & O_WRONLY) {
answer += "O_WRONLY|"; // 000001
}
if (mask_ & O_RDWR) {
answer += "O_RDWR|"; // 000002
}
if (mask_ & O_APPEND) {
answer += "O_APPEND|"; // 001000
}
if (mask_ & O_NONBLOCK) {
answer += "O_NONBLOCK|";// 004000
}
if (mask_ & O_SYNC) {
answer += "O_SYNC|"; // 010000
}
if (mask_ & O_ASYNC) { // 020000
answer += "O_ASYNC|";
}
answer.erase (answer.end () - 1);
#endif
return answer;
}
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
u_long
unsigned long u_long
Definition Logger_Impl.h:41
u_short
unsigned short u_short
Definition Logger_Impl.h:39
READ_INT
#define READ_INT(TYPE)
Definition Socket.cpp:436
WRITE_INT
#define WRITE_INT(TYPE)
Definition Socket.cpp:588
Socket.h
Abstraction of socket data type.
XDRHack.h
XDRHack provides XDR definitions for systems that have them missing.
ASSA::Socket
Definition Socket.h:71
ASSA::Socket::fail
bool fail() const
Indicates that earlier extraction opeartion has failed to match the required pattern of input.
Definition Socket.h:328
ASSA::Socket::Socket
Socket()
Constructor.
Definition Socket.h:518
ASSA::Socket::clear_fd_options
int clear_fd_options(long flags_)
Gateway method for clearing file descriptor options.
Definition Socket.cpp:147
ASSA::Socket::operator>>
Socket & operator>>(char &c)
Input of built-in char type. The value will be XDR-decoded.
Definition Socket.cpp:359
ASSA::Socket::rdbuf
virtual Streambuf * rdbuf()
Return a pointer to the Streambuf associated with the stream.
Definition Socket.h:240
ASSA::Socket::dumpState
void dumpState() const
Write state bits of the socket to the log file.
Definition Socket.cpp:653
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::decode_fcntl_flags
static string decode_fcntl_flags(long mask_)
Decipher flags packed into mask_ used in fcntl() call.
Definition Socket.cpp:713
ASSA::Socket::set_fd_options
int set_fd_options(long flags_)
Gateway method for setting file descriptor options.
Definition Socket.cpp:104
ASSA::Socket::turnOptionOff
bool turnOptionOff(opt_t opt_)
Disable socket option.
Definition Socket.cpp:204
ASSA::Socket::read
virtual int read(char *buf_, const u_int size_)
Read expected number of bytes from the socket.
Definition Socket.h:551
ASSA::Socket::set_option
int set_option(int level_, int optname_, int val_)
Gateway method of setting socket options.
Definition Socket.cpp:86
ASSA::Socket::turnOptionOn
bool turnOptionOn(opt_t opt_)
Enable socket option.
Definition Socket.cpp:185
ASSA::Socket::opt_t
opt_t
Socket options.
Definition Socket.h:99
ASSA::Socket::reuseaddr
@ reuseaddr
Allow local address reuse.
Definition Socket.h:100
ASSA::Socket::sndlowat
@ sndlowat
The send low-water mark si the amount of available space that must exist in the socket send buffer fo...
Definition Socket.h:108
ASSA::Socket::rcvlowat
@ rcvlowat
The receiver low-water mark is the amount of data that must be in the socket receive buffer for selec...
Definition Socket.h:102
ASSA::Socket::nonblocking
@ nonblocking
Set Socket to a non-blocking mode (O_RDWR|O_NONBLOCK).
Definition Socket.h:115
ASSA::Socket::is_little_endian
static bool is_little_endian()
Determine the endianess of the platform we are on.
Definition Socket.cpp:700
ASSA::Socket::eof
bool eof() const
An earlier extraction operation has encountered the end of file of the input stream (peer closed its ...
Definition Socket.h:321
ASSA::Socket::m_fd
handler_t m_fd
File descriptor.
Definition Socket.h:485
ASSA::Socket::bad
bool bad() const
Socket fd == -1 or read/write error occured or some loss of integrity on assosiated stream buffer.
Definition Socket.h:337
ASSA::Socket::getOption
int getOption(opt_t opt_) const
Get current value of a socket option.
Definition Socket.cpp:248
ASSA::Socket::good
bool good() const
Indicates no error on the socket.
Definition Socket.h:315
ASSA::Socket::ignore
int ignore(int n_=INT_MAX, int delim_=EOF)
Extracts bytes and discards them.
Definition Socket.cpp:308
ASSA::Socket::operator<<
Socket & operator<<(char c)
Output of built-in char type. The value will be XDR-encoded.
Definition Socket.cpp:508
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::badbit
@ badbit
indicates a loss of integrity in an input or output sequence (such as an irrecoverable read error fro...
Definition Socket.h:87
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::Socket::PGSIZE
static const int PGSIZE
Size of bytes of a kernel page.
Definition Socket.h:74
ASSA::Socket::setOption
bool setOption(opt_t opt_, int arg_)
Set socket option to value required.
Definition Socket.cpp:223
ASSA::Socket::write
virtual int write(const char *buf_, const u_int size_)
Write specified number of bytes to the socket.
Definition Socket.h:544
ASSA::Socket::getBytesAvail
int getBytesAvail(void) const
Return number of bytes available in socket receive buffer.
Definition Socket.cpp:48
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
Definition Acceptor.h:40
ASSA::SOCKTRACE
@ SOCKTRACE
Extended Socket & friends messages.
Definition LogMask.h:42
ASSA::ASSAERR
@ ASSAERR
ASSA and system errors.
Definition LogMask.h:34