libassa  3.5.1
IPv4Socket.cpp
Go to the documentation of this file.
1 // -*- c++ -*-
2 //------------------------------------------------------------------------------
3 // IPv4Socket.cpp
4 //------------------------------------------------------------------------------
5 // Copyright (C) 1997-2002 Vladislav Grinchenko
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Library General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //------------------------------------------------------------------------------
12 //
13 #if defined(WIN32)
14 # include <errno.h>
15 # include <ws2tcpip.h>
16 #else
17 # include <sys/errno.h>
18 #endif
19 
20 #include "assa/MemDump.h"
21 #include "assa/IPv4Socket.h"
22 
23 using namespace ASSA;
24 
25 Streambuf*
27 rdbuf (Streambuf* sb_)
28 {
29  trace_with_mask("IPv4Socket::rdbuf(sb_)",SOCKTRACE);
30 
31  if (sb_ == 0 || sb_ == m_rdbuf) {
32  return (sb_);
33  }
34  Streambuf* old = m_rdbuf;
35  m_rdbuf = sb_;
36  return (old);
37 }
38 
39 
40 bool
42 open (const int domain_)
43 {
44  trace_with_mask("IPv4Socket::open",SOCKTRACE);
45 
46  m_type = domain_;
47 
48  m_fd = ::socket(domain_, SOCK_STREAM, 0);
49 
50  if (!is_valid_handler (m_fd)) {
51  EL((ASSAERR,"OS::socket() error: m_fd = %d\n", m_fd));
54  return (false);
55  }
56  DL ((SOCK,"domain = %d, m_fd = %d\n", domain_, m_fd));
57 
58  clear ();
60 
61  return (true);
62 }
63 
64 bool
66 close()
67 {
68  trace_with_mask("IPv4Socket::close()",SOCKTRACE);
69 
70  if (is_valid_handler (m_fd)) {
71  DL((SOCK,"Closed FD: %d\n",m_fd));
72 
73  /*--- Flush data in output stream buffer ---*/
74  flush ();
77 
78  /*---
79  Socket can be re-opened in the future.
80  If there is some bytes left in it since last read(2),
81  clean them up.
82  ---*/
83 
84  if (m_rdbuf && m_rdbuf->in_avail ()) {
85  for (int c; (c=m_rdbuf->sbumpc ()) != EOF;) { }
86  }
87  }
88  return (true);
89 }
90 
91 bool
93 connect (const Address& his_address_)
94 {
95  trace_with_mask("IPv4Socket::connect()",SOCKTRACE);
96 
97  if (!is_valid_handler (m_fd) && open (getDomain()) == false) {
98  return false;
99  }
100 
101  int ret = ::connect (m_fd,
102  (SA*) his_address_.getAddress(),
103  his_address_.getLength());
104  if (ret < 0)
105  {
106  int e = get_errno (); // is ASYNC connect in progress?
107  if (e == EINPROGRESS || e == EWOULDBLOCK) {
108  DL((SOCK,"FD: %d OS::connect() error\n",m_fd));
109  }
110  else {
111  EL((SOCK,"FD: %d OS::connect() error\n",m_fd));
112  }
113  return (false);
114  }
115 
116  clear ();
117 
118  DL((SOCK,"Connection opened on FD: %d\n", m_fd));
119  return (true);
120 }
121 
122 bool
124 bind (const Address& addr_)
125 {
126  trace_with_mask("IPv4Socket::bind",SOCKTRACE);
127 
128 #if !defined(WIN32)
132  if ( getDomain() == AF_UNIX ) {
133  char* p = ((SA_UN *) addr_.getAddress())->sun_path;
134  m_path = new char[strlen(p)+1];
135  strcpy(m_path, p);
136  struct stat sb;
137 
138  if (stat (m_path, &sb) == 0) {
139  if ( S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode) ) {
140  unlink(m_path);
141  }
142  }
143  }
144 #endif
145 
146  /*---
147  From Stevens, Ch 7.5 (p.196):
148  "Set the SO_REUSEADDR socket option before calling bind(2)
149  in all TCP servers."
150  ---*/
152 
153  int rt = ::bind(m_fd, addr_.getAddress(), addr_.getLength());
154 
155  if ( rt < 0) {
156  EL((SOCK,"::bind() FD: %d failed\n",m_fd));
158  return (false);
159  }
160  Assure_return ( (::listen(m_fd, 5) == 0) );
161  return (true);
162 }
163 
175 IPv4Socket*
177 accept ()
178 {
179  trace_with_mask("IPv4Socket::accept",SOCKTRACE);
180 
181  socklen_t length = 0;
182  SA* remote_address = NULL;
183  handler_t new_fd;
184 
185  disable_handler (new_fd);
186 
187  if ( getDomain() == AF_UNIX ) {
188  length = sizeof(struct sockaddr_in);
189  remote_address = (SA*) new SA_IN;
190  }
191  else /* AF_INET */
192  {
193  remote_address = (SA*) new SA_UN;
194  length = sizeof(struct sockaddr_un);
195  }
196  memset(remote_address, 0, length);
197 
198 #if !defined (_CYGWIN32__)
199  new_fd = ::accept(m_fd, remote_address, &length);
200 #else
201  new_fd = ::accept(m_fd, remote_address, (int*)&length);
202 #endif
203 
204  if (!is_valid_handler (new_fd)) {
205  EL((ASSAERR,"::accept() failed (new_fd=%d)\n", new_fd));
206  close();
207  return NULL;
208  }
209  if (length == sizeof(SA_IN)) {
210  SA_IN* sa_in = (SA_IN*) remote_address;
211 
212  DL((SOCK,"Accepted new TCP connection from Addr %s, port %d\n",
213  inet_ntoa(sa_in->sin_addr), ntohs( sa_in->sin_port)));
214  }
215  else {
216 #if !defined(WIN32)
217  SA_UN* sa_un = (SA_UN*) remote_address;
218  DL((SOCK,"Accepted new UNIX connection from %s\n", sa_un->sun_path));
219 #endif
220  }
221  delete remote_address;
222 
223  IPv4Socket* s = new IPv4Socket (new_fd);
224  s->clear ();
226  return s;
227 }
228 
229 int
231 read (char* packet_, const unsigned int size_)
232 {
233  trace_with_mask("IPv4Socket::read",SOCKTRACE);
234 
235  register int len;
236  register int sz = size_;
237  char* tmp = packet_;
238 
239  if (!is_valid_handler (m_fd) < 0) {
240  return -1;
241  }
242 
243  len = 0;
244  if (m_rdbuf->unbuffered ()) {
245  /*
246  --- This needs to be redesigned ---
247  I should read a character at a time in loop,
248  until I get all characters, or EWOULDBLOCK or EOF.
249  If ::read() returns 0 or -1, it will be converted
250  by sbumpc() into EOF. Otherwise, sbumpc() returns
251  character read. Is this the right thing here to do?
252  */
253  if ((len = m_rdbuf->sbumpc ()) >= 0) {
254  *tmp = len;
255  len = 1;
256  }
257  }
258  else {
259  len = m_rdbuf->sgetn (tmp, sz);
260  }
261  if (len == -1)
262  {
265  if (get_errno () != EWOULDBLOCK) {
266  EL((ASSAERR,"::read (fd=%d) failed.\n",m_fd));
268  }
269  return len;
270  }
271  tmp += len;
272  sz -= len;
273 
274  if ((size_ - sz) == 0)
275  {
276  DL((SOCK,"Peer has dropped connection FD: %d\n",m_fd));
278  return 0;
279  }
280 
281  DL((SOCKTRACE,"==> FD: %d Received %d bytes\n", m_fd, size_ - sz));
282  MemDump::dump_to_log (SOCKTRACE, "Data received:", packet_, size_ - sz);
283 
284  /*
285  Return number of bytes read. If all requested bytes have been
286  read, then sz is 0 and size_ is returned. If sz != 0, then
287  writer has sent us a partial packet.
288  */
289  return (size_ - sz);
290 }
291 
292 int
294 write(const char* packet_, const unsigned int size_)
295 {
296  trace_with_mask("IPv4Socket::write()",SOCKTRACE);
297 
298  int ret = 0;
299 
300  if (!is_valid_handler (m_fd)) {
301  return -1;
302  }
303 
304  if (m_rdbuf->unbuffered ())
305  {
306  int wlen = size_;
307  char* p = (char*) packet_;
308 
309  while (wlen-- > 0) {
310  if (m_rdbuf->sputc (*p++) == EOF) {
311  return (EOF);
312  }
313  }
314  ret = p - packet_;
315  }
316  else {
317  ret = m_rdbuf->sputn ((char*) packet_, size_);
318  }
319 
320  if (ret > 0) {
321  DL((SOCK,"<= FD: %d Wrote %d bytes (requested %d bytes)\n",
322  m_fd, ret, size_));
323  MemDump::dump_to_log (SOCK, "Data written", (char*)packet_, ret);
324  }
325  return ret;
326 }
327 
328 IPv4Socket*
330 clone () const
331 {
332  const char self[] = "IPv4Socket::clone";
334 
335  handler_t nfd = dup (m_fd);
336  IPv4Socket* s = new IPv4Socket (nfd);
337 
338  DL((SOCK,"Original socket has %d bytes in its get_area\n",
339  m_rdbuf->in_avail ()));
340 
341  if (!is_valid_handler (nfd) || !good ()) {
343  }
344  else {
345  s->clear ();
346  }
347 
348  return s;
349 }
350 
351 
#define Assure_return(exp_)
Test condition and return bool from a function if assertion fails.
Definition: Assure.h:64
Class IPv4Socket covers domain types AF_INET and AF_UNIX.
#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
int handler_t
Definition: Logger_Impl.h:82
A Hex/Ascii memory dump of similar to od(1) UNIX utility.
virtual SA * getAddress() const =0
Retrieve pointer to the address structure.
virtual const int getLength() const =0
Return length of the underlying address structure.
IPv4Socket * accept()
Accept connection on the listening socket.
Definition: IPv4Socket.cpp:177
int write(const char *buf_, const unsigned int size_)
Perform blocking write by writing packet of specified size.
Definition: IPv4Socket.cpp:294
IPv4Socket()
Default constructor.
Definition: IPv4Socket.h:32
IPv4Socket * clone() const
"Virtual constructor".
Definition: IPv4Socket.cpp:330
virtual Streambuf * rdbuf()
Return a pointer to the Socketbuf associated with the stream.
Definition: IPv4Socket.h:146
bool close()
Close socket connection.
Definition: IPv4Socket.cpp:66
bool connect(const Address &address_)
Client makes connection with the server at address_.
Definition: IPv4Socket.cpp:93
bool open(const int domain_)
Create socket.
Definition: IPv4Socket.cpp:42
Streambuf * m_rdbuf
Socketbuf.
Definition: IPv4Socket.h:176
virtual bool bind(const Address &my_address_)
Server binds listening socket to its local well-known port.
Definition: IPv4Socket.cpp:124
const int getDomain() const
Get socket domain type.
Definition: IPv4Socket.h:138
int read(char *buf_, const unsigned int size_)
Read packet of specified size and save it to the given buffer.
Definition: IPv4Socket.cpp:231
char * m_path
Path of UNIX domain socket.
Definition: IPv4Socket.h:173
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
int m_type
Socket domain type.
Definition: Socket.h:488
void setstate(iostate flag_)
Set socket state to flag_ by adding flag_ to the existing state.
Definition: Socket.h:577
static void close_handler(handler_t &socket_)
Close socket endpoint in a portable way.
Definition: Socket.h:448
bool turnOptionOn(opt_t opt_)
Enable socket option.
Definition: Socket.cpp:185
@ reuseaddr
Allow local address reuse.
Definition: Socket.h:100
@ nonblocking
Set Socket to a non-blocking mode (O_RDWR|O_NONBLOCK).
Definition: Socket.h:115
handler_t m_fd
File descriptor.
Definition: Socket.h:485
bool good() const
Indicates no error on the socket.
Definition: Socket.h:315
void clear(iostate state_=Socket::goodbit)
Clear the socket state. Closed socket remains in bad state.
Definition: Socket.h:571
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
@ failbit
indicates that an input operation failed to read the expected characters, or that an output operation...
Definition: Socket.h:84
Streambuf class.
Definition: Streambuf.h:91
int sputc(char c_)
This function stores c just after the put pointer, and advances the pointer one position,...
Definition: Streambuf.h:568
int sbumpc()
This function should probably have been called `‘sgetc’'.
Definition: Streambuf.h:539
int in_avail()
This function returns the number of characters immediately available in the get area.
Definition: Streambuf.h:399
void unbuffered(int i_)
If i_ is non-zero, then all IO operations are buffered.
Definition: Streambuf.h:417
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
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
Definition: Acceptor.h:40
struct sockaddr_in SA_IN
Definition: Address.h:34
struct sockaddr_un SA_UN
Definition: Address.h:44
@ SOCK
Class Socket & friends messages
Definition: LogMask.h:41
@ SOCKTRACE
Extended Socket & friends messages
Definition: LogMask.h:42
@ ASSAERR
ASSA and system errors
Definition: LogMask.h:34
struct sockaddr SA
Definition: Address.h:33
bool is_valid_handler(handler_t socket_)
Detect socket() error in a portable way.
Definition: Logger_Impl.h:100
void disable_handler(handler_t &socket_)
Set socket descriptor to invalid value in a portable way.
Definition: Logger_Impl.h:108
int get_errno()
Fetch error number in a portable way.
Definition: Logger_Impl.h:115