libassa 3.5.1
Socket.cpp
Go to the documentation of this file.
1// -*- c++ -*-
2//------------------------------------------------------------------------------
3// $Id: Socket.cpp,v 1.13 2006/09/24 17:35:33 vlg Exp $
4//------------------------------------------------------------------------------
5// Socket.C
6//------------------------------------------------------------------------------
7// Copyright (c) 1999,2005 by Vladislav Grinchenko
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Library General Public
11// License as published by the Free Software Foundation; either
12// version 2 of the License, or (at your option) any later version.
13//------------------------------------------------------------------------
14// Created: 03/22/99
15//------------------------------------------------------------------------
16
17#include <sstream>
18#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__CYGWIN32__) || defined (__GNU__)
19# include <sys/ioctl.h>
20#endif
21
22#if defined (__NetBSD__)
23# include <sys/filio.h>
24# include <sys/ioctl.h>
25#endif
26
27#if defined (WIN32)
28# define O_NONBLOCK 04000
29typedef unsigned int socklen_t;
30#endif
31
32#include "assa/Socket.h"
33#include "assa/XDRHack.h"
34
35using namespace ASSA;
36
37const int ASSA::Socket::PGSIZE = 4096;
38
46int
47Socket::
48getBytesAvail (void) const
49{
50 trace_with_mask("Socket::getBytesAvail",SOCKTRACE);
51
52 Socket* This = (Socket*) this;
53 u_long ba = 0;
54 int ret = 0;
55
56#if defined(WIN32)
57 ret = ioctlsocket (m_fd, FIONREAD, &ba);
58#else
59 ret = ioctl (m_fd, FIONREAD, &ba);
60#endif
61
62 if (ret == -1) {
63 EL((ASSAERR,"ioctl(2) failed with ret: %d\n", ret));
64 return ret;
65 }
66 ba += This->rdbuf ()->in_avail ();
67
68 DL((SOCKTRACE,"%ld bytes available for reading\n", ba));
69 return (int(ba));
70}
71
72Socket&
74flush ()
75{
76 if (good () && rdbuf ()) {
77 if (rdbuf ()->pubsync () == EOF) {
79 }
80 }
81 return (*this);
82}
83
84int
86set_option (int level_, int optname_, int val_)
87{
88 int ret = setsockopt (m_fd,
89 level_,
90 optname_,
91 (const char*) &val_,
92 sizeof (val_));
93 if (ret < 0) {
95 }
96 return ret;
97}
98
102int
104set_fd_options (long flags_)
105{
106 trace_with_mask("Socket::set_fd_options",SOCKTRACE);
107 int val;
108 int ret;
109
110#if defined (WIN32)
111
112 u_long set_nonblock = 1;
113 if ((val = ioctlsocket (m_fd, FIONBIO, &set_nonblock)) == 0) {
114 m_nonblocking = true;
115 return 0;
116 }
117 return -1;
118
119#else // POSIX/UNIX
120
121 if ((val = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
122 return -1;
123 }
124 val |= flags_; // turn flags on
125
126 DL ((SOCKTRACE,"Set flags fcntl(%d, %s)\n", m_fd,
127 decode_fcntl_flags (val).c_str ()));
128
129 ret = ::fcntl (m_fd, F_SETFL, val);
130
131 val = ::fcntl (m_fd, F_GETFL, 0);
132 DL ((SOCKTRACE,"Flags are set to %s via fcntl(25)\n",
133 decode_fcntl_flags (val).c_str ()));
134
135 return (ret);
136
137#endif
138}
139
145int
147clear_fd_options (long flags_)
148{
149 trace_with_mask("Socket::clear_fd_options",SOCKTRACE);
150 long oldflags;
151 long newflags;
152 int ret;
153
154#if defined (WIN32)
155
156 u_long set_block = 0;
157 if ((ret = ioctlsocket (m_fd, FIONBIO, &set_block)) == 0) {
158 m_nonblocking = false;
159 return 0;
160 }
161 return -1;
162
163#else
164
165 if ((oldflags = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
166 return -1;
167 }
168 newflags = oldflags & ~flags_; // clear flags
169
170 DL ((SOCKTRACE,"Set flags fcntl(%d, %s)\n", m_fd,
171 decode_fcntl_flags (newflags).c_str ()));
172
173 ret = ::fcntl (m_fd, F_SETFL, newflags);
174
175 newflags = ::fcntl (m_fd, F_GETFL, 0);
176 DL ((SOCKTRACE,"Flags are set to %s via fcntl(%d)\n",
177 decode_fcntl_flags (newflags).c_str ()));
178
179 return (ret);
180#endif
181}
182
183bool
185turnOptionOn (opt_t opt_)
186{
187 trace_with_mask("Socket::turnOptionOn",SOCKTRACE);
188
189 if (nonblocking == opt_)
190 return set_fd_options (O_NONBLOCK);
191
192 int optname;
193 if (reuseaddr == opt_)
194 optname = SO_REUSEADDR;
195 else {
196 EL((ASSAERR,"Invalid socket option\n"));
197 return false;
198 }
199 return set_option (SOL_SOCKET, optname, 1) == 0;
200}
201
202bool
204turnOptionOff (opt_t opt_)
205{
206 trace_with_mask("Socket::turnOptionOff",SOCKTRACE);
207
208 if (nonblocking == opt_)
209 return clear_fd_options (O_NONBLOCK);
210
211 int optname;
212 if (reuseaddr == opt_)
213 optname = SO_REUSEADDR;
214 else {
215 EL((ASSAERR,"Invalid socket option\n"));
216 return false;
217 }
218 return set_option (SOL_SOCKET, optname, 0) == 0;
219}
220
221bool
223setOption (opt_t opt_, int arg_)
224{
225 trace_with_mask("Socket::setOption(,)",SOCKTRACE);
226 int optname;
227
228 if (nonblocking == opt_) {
229 return (arg_ == 1) ? set_fd_options (O_NONBLOCK)
230 : clear_fd_options (O_NONBLOCK);
231 }
232
233 if (rcvlowat == opt_) {
234 optname = SO_RCVLOWAT;
235 }
236 else if (sndlowat == opt_) {
237 optname = SO_SNDLOWAT;
238 }
239 else {
240 EL((ASSAERR,"Invalid socket option\n"));
241 return false;
242 }
243 return set_option (SOL_SOCKET, optname, arg_) == 0;
244}
245
246int
248getOption (opt_t opt_) const
249{
250 trace_with_mask("Socket::getOption",SOCKTRACE);
251 int optval = 0;
252
253 if (nonblocking == opt_)
254 {
255#if defined (WIN32)
256 return (m_nonblocking ? 1 : 0);
257#else
258 if ((optval = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
259 return -1;
260 }
261 return ((optval & O_NONBLOCK) == O_NONBLOCK ? 1 : 0);
262#endif
263 }
264
265 int optname;
266 int level = SOL_SOCKET;
267 bool bin = false;
268
269 socklen_t len = sizeof (optval);
270 int ret;
271
272 if (rcvlowat == opt_) {
273 optname = SO_RCVLOWAT;
274 }
275 else if (sndlowat == opt_) {
276 optname = SO_SNDLOWAT;
277 }
278 else if (reuseaddr == opt_) {
279 optname = SO_REUSEADDR;
280 bin = true;
281 }
282 else {
283 EL((ASSAERR,"Invalid socket option\n"));
284 return (-1);
285 }
286
287#if defined (__CYGWIN32__) || defined (WIN32)
288
289 ret = getsockopt (m_fd, level, optname, (char*) &optval, (int*)&len);
290
291#else // posix/unix
292
293 ret = getsockopt (m_fd, level, optname, (char*) &optval, &len);
294
295#endif
296
297 if (ret < 0) {
298 return (-1);
299 }
300 if (bin) {
301 return (ret == 0 ? 0 : 1);
302 }
303 return (ret);
304}
305
306int
308ignore(int n_, int delim_)
309{
310 trace_with_mask("Socket::ignore",SOCKTRACE);
311 register int b;
312 register int count = 0;
313 register char c;
314
315 if (n_ == INT_MAX && delim_ == EOF) {
316 char buf[PGSIZE];
317 while ((b = read (buf, PGSIZE))) {
318 count += b;
319 }
321 return count;
322 }
323 for (; n_; n_--, count++) {
324 if ( (b = read (&c, 1)) == 0 ) {
326 break;
327 }
328 if ( c == delim_ )
329 break;
330 }
331 return count;
332}
333
334//-----------------------------------------------------------------------------
335// Input operators
336//-----------------------------------------------------------------------------
337
357Socket&
359operator>>(char& n_)
360{
361
362 int c = 0;
363 int len = sizeof (int);
364 XDR xdrs;
365 xdrmem_create (&xdrs, (caddr_t) &c, len, XDR_DECODE);
366
367 if (read ((char* ) &c, len) == len) {
368 xdr_char (&xdrs, &n_);
369 }
370 else {
372 }
373 xdr_destroy(&xdrs);
374 return *this;
375}
376
379Socket&
381operator>> (std::string& s_)
382{
383 char c = 0;
384 size_t n = 0;
385 s_ = "";
386
387 (*this) >> n;
388
389 if (n == 0) {
390 return *this;
391 }
392 size_t len = n;
393 while (len-- && read (&c, 1) == 1) {
394 s_ += c;
395 }
396 ignore (4 - n % 4);
397 return *this;
398}
399
400Socket&
402operator>> (short& n_)
403{
404 short val;
405 if (read ((char*) &val, sizeof(short)) == sizeof(short)) {
406 n_ = (short) ntohs ((short)val);
407 }
408 else {
410 }
411 return *this;
412}
413
414Socket&
416operator>> (unsigned short& n_)
417{
418 u_short val;
419 if (read ((char*) &val, sizeof(u_short)) == sizeof(u_short)) {
420 n_ = (u_short) ntohs ((u_short)val);
421 }
422 else {
424 }
425 return *this;
426}
427
428#define LONGEST long
429
430/* On 64-bit platforms, sizeof (long) = 8 bytes.
431 * ntohl()/htonh() operats only on int32_t types which is 4 bytes long
432 * everywhere. So, for 64-bit longs we need to process twice as much
433 * and swapt data accordingly.
434 */
435
436#define READ_INT(TYPE) \
437Socket& Socket::operator>>(TYPE& n_) \
438{\
439 LONGEST val;\
440 int typesz = sizeof(TYPE);\
441 if (read ( (char* ) &val, typesz) == typesz) {\
442 if (sizeof(int32_t) <= typesz) {\
443 n_ = (TYPE) ntohl (val); \
444 }\
445 else {\
446 if (Socket::is_little_endian ()) {\
447 *((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val)) );\
448 *((int32_t*)(&n_) ) = ntohl (*((int32_t*)(&val))+1);\
449 }\
450 else {\
451 *((int32_t*)(&n_) ) = ntohl (*((int32_t*)(&val)) );\
452 *((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val))+1);\
453 }\
454 }\
455 }\
456 else {\
457 setstate (Socket::eofbit|Socket::failbit);\
458 }\
459 return *this;\
460}
461
463READ_INT(unsigned int);
465READ_INT(unsigned long);
466
467Socket&
469operator>> (float& n_)
470{
471 float val;
472 XDR xdrs;
473 xdrmem_create (&xdrs, (caddr_t) &val, sizeof(float), XDR_DECODE);
474
475 if (read ((char*) &val, sizeof(float)) == sizeof(float)) {
476 xdr_float (&xdrs, &n_);
477 }
478 else {
480 }
481 xdr_destroy (&xdrs);
482 return *this;
483}
484
485Socket&
487operator>> (double& n_)
488{
489 double val = 0;
490 XDR xdrs;
491 xdrmem_create (&xdrs, (caddr_t) &val, sizeof(double), XDR_DECODE);
492 if (read ((char*) &val, sizeof(double)) == sizeof(double)) {
493 xdr_double (&xdrs, &n_);
494 }
495 else {
497 }
498 xdr_destroy (&xdrs);
499 return *this;
500}
501
502//-----------------------------------------------------------------------------
503// Output operators
504//-----------------------------------------------------------------------------
505
508operator<< (char n_)
509{
510 /* See comment to operator>>(char n_) */
511
512 int buf = 0;
513 int len = sizeof (int);
514 XDR xdrs;
515
516 xdrmem_create (&xdrs, (caddr_t) &buf, len, XDR_ENCODE);
517 xdr_char (&xdrs, &n_);
518
519 if (write ((const char*) &buf, len) != len) {
521 }
522 xdr_destroy (&xdrs);
523 return *this;
524}
525
546operator<< (const std::string& s_)
547{
548 static const char pad [4] = { 0, 0, 0, 0 };
549
550 (*this) << s_.length ();
551 int ret = write (s_.c_str (), s_.length ());
552 if ( ret != s_.length () ) {
554 }
555 size_t r = 4 - s_.length() % 4;
556 if (r) {
557 if (write (pad, r) != r) {
559 }
560 }
561 return *this;
562}
563
565operator<< (short n_)
566{
567 short val = (short) htons((short)n_);
568
569 if (write ((const char*) &val, sizeof(short)) != sizeof(short))
570 {
572 }
573 return *this;
574}
575
577operator<< (unsigned short n_)
578{
579 u_short val = (u_short) htons((u_short)n_);
580
581 if (write ((const char*) &val, sizeof(u_short)) != sizeof(u_short))
582 {
584 }
585 return *this;
586}
587
588#define WRITE_INT(TYPE) \
589Socket& Socket::operator<< (TYPE n_) \
590{ \
591 LONGEST val;\
592 int typesz = sizeof(TYPE);\
593 if (sizeof(int32_t) <= typesz) {\
594 val = (TYPE) ntohl (n_); \
595 }\
596 else {\
597 if (Socket::is_little_endian ()) {\
598 *((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_)) );\
599 *((int32_t*)(&val) ) = htonl (*((int32_t*)(&n_))+1);\
600 }\
601 else {\
602 *((int32_t*)(&val) ) = htonl (*((int32_t*)(&n_)) );\
603 *((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_))+1);\
604 }\
605 }\
606 if (write ((const char*) &val, typesz) != typesz) {\
607 setstate (Socket::eofbit|Socket::failbit);\
608 }\
609 return *this;\
610}
611
613WRITE_INT(unsigned int);
615WRITE_INT(unsigned long);
616
619operator<< (float n_)
620{
621 float buf, f = n_;
622 XDR xdrs;
623 xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(float), XDR_ENCODE);
624 xdr_float (&xdrs, &f);
625
626 int ret = write ((const char*) &buf, sizeof(float));
627 xdr_destroy (&xdrs);
628 if ( ret != sizeof(float) ) {
630 }
631 return *this;
632}
633
636operator<< (double n_)
637{
638 double buf, f = n_;
639 XDR xdrs;
640 xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(double), XDR_ENCODE);
641 xdr_double (&xdrs, &f);
642
643 int ret = write ((const char*) &buf, sizeof(double));
644 xdr_destroy (&xdrs);
645 if ( ret != sizeof(double) ) {
647 }
648 return *this;
649}
650
651void
653dumpState (void) const
654{
655 trace_with_mask("Socket::dumpState",SOCKTRACE);
656
657 char state_set[] = "[ set]\n";
658 char state_not_set[] = "[not set]\n";
659
660 std::ostringstream msg;
661
662 msg << "\n";
663 msg << "\tTesting good() ....... ";
664
665 if (this->good ()) msg << state_set;
666 else msg << state_not_set;
667
668 msg << "\tTesting eof() ........ ";
669 if (this->eof ()) msg << state_set;
670 else msg << state_not_set;
671
672 msg << "\tTesting fail() ....... ";
673 if (this->fail ()) msg << state_set;
674 else msg << state_not_set;
675
676 msg << "\tTesting bad() ........ ";
677 if (this->bad ()) msg << state_set;
678 else msg << state_not_set;
679
680 msg << "\tTesting !() .......... ";
681 if ( !(*this) ) msg << state_set;
682 else msg << state_not_set;
683
684 msg << "\tTesting void *() ..... ";
685 if ( *this ) msg << state_set;
686 else msg << state_not_set;
687
688 msg << "\tTesting nonblocking... ";
689 if (getOption (nonblocking) == 1) msg << state_set;
690 else msg << state_not_set;
691
692 /*--- Terminate stream buffer ---*/
693 msg << std::ends;
694
695 DL((SOCKTRACE,"%s\n", msg.str ().c_str ()));
696}
697
698bool
701{
702 union {
703 char c [sizeof (short)];
704 short v;
705 } endian_u;
706
707 endian_u.v = 256;
708 return (endian_u.c [0] == 0);
709}
710
711string
713decode_fcntl_flags (long mask_)
714{
715 string answer;
716
717#if !defined (WIN32)
718
719 if (mask_ & O_RDONLY) {
720 answer = "O_RDONLY|"; // 000000
721 }
722 if (mask_ & O_WRONLY) {
723 answer += "O_WRONLY|"; // 000001
724 }
725 if (mask_ & O_RDWR) {
726 answer += "O_RDWR|"; // 000002
727 }
728 if (mask_ & O_APPEND) {
729 answer += "O_APPEND|"; // 001000
730 }
731 if (mask_ & O_NONBLOCK) {
732 answer += "O_NONBLOCK|";// 004000
733 }
734 if (mask_ & O_SYNC) {
735 answer += "O_SYNC|"; // 010000
736 }
737
738 if (mask_ & O_ASYNC) { // 020000
739 answer += "O_ASYNC|";
740 }
741
742 answer.erase (answer.end () - 1);
743
744#endif
745
746 return answer;
747}
#define EL(X)
A macro for writing error message to the Logger.
Definition: Logger.h:285
#define DL(X)
A macro for writing debug message to the Logger.
Definition: Logger.h:273
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition: Logger.h:437
unsigned long u_long
Definition: Logger_Impl.h:41
unsigned short u_short
Definition: Logger_Impl.h:39
#define READ_INT(TYPE)
Definition: Socket.cpp:436
#define WRITE_INT(TYPE)
Definition: Socket.cpp:588
Abstraction of socket data type.
XDRHack provides XDR definitions for systems that have them missing.
bool fail() const
Indicates that earlier extraction opeartion has failed to match the required pattern of input.
Definition: Socket.h:328
int clear_fd_options(long flags_)
Gateway method for clearing file descriptor options.
Definition: Socket.cpp:147
Socket & operator>>(char &c)
Input of built-in char type. The value will be XDR-decoded.
Definition: Socket.cpp:359
virtual Streambuf * rdbuf()
Return a pointer to the Streambuf associated with the stream.
Definition: Socket.h:240
void dumpState() const
Write state bits of the socket to the log file.
Definition: Socket.cpp:653
void setstate(iostate flag_)
Set socket state to flag_ by adding flag_ to the existing state.
Definition: Socket.h:577
static string decode_fcntl_flags(long mask_)
Decipher flags packed into mask_ used in fcntl() call.
Definition: Socket.cpp:713
int set_fd_options(long flags_)
Gateway method for setting file descriptor options.
Definition: Socket.cpp:104
bool turnOptionOff(opt_t opt_)
Disable socket option.
Definition: Socket.cpp:204
virtual int read(char *buf_, const u_int size_)
Read expected number of bytes from the socket.
Definition: Socket.h:551
int set_option(int level_, int optname_, int val_)
Gateway method of setting socket options.
Definition: Socket.cpp:86
bool turnOptionOn(opt_t opt_)
Enable socket option.
Definition: Socket.cpp:185
opt_t
Socket options.
Definition: Socket.h:99
@ reuseaddr
Allow local address reuse.
Definition: Socket.h:100
@ 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
@ 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
@ nonblocking
Set Socket to a non-blocking mode (O_RDWR|O_NONBLOCK).
Definition: Socket.h:115
static bool is_little_endian()
Determine the endianess of the platform we are on.
Definition: Socket.cpp:700
bool eof() const
An earlier extraction operation has encountered the end of file of the input stream (peer closed its ...
Definition: Socket.h:321
handler_t m_fd
File descriptor.
Definition: Socket.h:485
bool bad() const
Socket fd == -1 or read/write error occured or some loss of integrity on assosiated stream buffer.
Definition: Socket.h:337
int getOption(opt_t opt_) const
Get current value of a socket option.
Definition: Socket.cpp:248
bool good() const
Indicates no error on the socket.
Definition: Socket.h:315
int ignore(int n_=INT_MAX, int delim_=EOF)
Extracts bytes and discards them.
Definition: Socket.cpp:308
Socket & operator<<(char c)
Output of built-in char type. The value will be XDR-encoded.
Definition: Socket.cpp:508
virtual Socket & flush()
This function simply calls the public "synchronizing" function rdbuf()->pubsync() (assuming the assoc...
Definition: Socket.cpp:74
@ eofbit
indicates that an input operation reached the end of an input sequence
Definition: Socket.h:82
@ badbit
indicates a loss of integrity in an input or output sequence (such as an irrecoverable read error fro...
Definition: Socket.h:87
@ failbit
indicates that an input operation failed to read the expected characters, or that an output operation...
Definition: Socket.h:84
static const int PGSIZE
Size of bytes of a kernel page.
Definition: Socket.h:74
bool setOption(opt_t opt_, int arg_)
Set socket option to value required.
Definition: Socket.cpp:223
virtual int write(const char *buf_, const u_int size_)
Write specified number of bytes to the socket.
Definition: Socket.h:544
int in_avail()
This function returns the number of characters immediately available in the get area.
Definition: Streambuf.h:399
Definition: Acceptor.h:40
Socket & ends(Socket &os_)
ends manipulator.
Definition: Socket.h:622
@ SOCKTRACE
Extended Socket & friends messages
Definition: LogMask.h:42
@ ASSAERR
ASSA and system errors
Definition: LogMask.h:34