blob: 335aa04d03d033889da428a182c7051a6f7f464e [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39/**
40 * @file commoncpp/tcp.h
41 * @short tcp derived socket classes.
42 **/
43
44#ifndef COMMONCPP_TCP_H_
45#define COMMONCPP_TCP_H_
46
47#include <cstdio>
48
49#ifndef COMMONCPP_CONFIG_H_
50#include <commoncpp/config.h>
51#endif
52
53#ifndef COMMONCPP_STRING_H_
54#include <commoncpp/string.h>
55#endif
56
57#ifndef COMMONCPP_ADDRESS_H_
58#include <commoncpp/address.h>
59#endif
60
61#ifndef COMMONCPP_SOCKET_H_
62#include <commoncpp/socket.h>
63#endif
64
65NAMESPACE_COMMONCPP
66
67/**
68 * TCP sockets are used for stream based connected sessions between two
69 * sockets. Both error recovery and flow control operate transparently
70 * for a TCP socket connection. The TCP socket base class is primary used
71 * to bind a TCP "server" for accepting TCP streams.
72 *
73 * An implicit and unique TCPSocket object exists in Common C++ to represent
74 * a bound TCP socket acting as a "server" for receiving connection requests.
75 * This class is not part of TCPStream because such objects normally perform
76 * no physical I/O (read or write operations) other than to specify a listen
77 * backlog queue and perform "accept" operations for pending connections.
78 * The Common C++ TCPSocket offers a Peek method to examine where the next
79 * pending connection is coming from, and a Reject method to flush the next
80 * request from the queue without having to create a session.
81 *
82 * The TCPSocket also supports a "OnAccept" method which can be called when a
83 * TCPStream related object is created from a TCPSocket. By creating a
84 * TCPStream from a TCPSocket, an accept operation automatically occurs, and
85 * the TCPSocket can then still reject the client connection through the
86 * return status of it's OnAccept method.
87 *
88 * @author David Sugar <dyfet@tycho.com>
89 * @short bound server for TCP streams and sessions.
90 */
91class __EXPORT TCPSocket : protected Socket
92{
93protected:
94 int segsize;
95 void setSegmentSize(unsigned mss);
96
97public:
98 /**
99 * A method to call in a derived TCPSocket class that is acting
100 * as a server when a connection request is being accepted. The
101 * server can implement protocol specific rules to exclude the
102 * remote socket from being accepted by returning false. The
103 * Peek method can also be used for this purpose.
104 *
105 * @return true if client should be accepted.
106 * @param ia internet host address of the client.
107 * @param port number of the client.
108 */
109 virtual bool onAccept(const IPV4Host &ia, tpport_t port);
110
111 /**
112 * Fetch out the socket.
113 */
114 inline SOCKET getSocket(void)
115 {return so;};
116
117 /**
118 * Get the buffer size for servers.
119 */
120 inline int getSegmentSize(void)
121 {return segsize;};
122
123 /**
124 * A TCP "server" is created as a TCP socket that is bound
125 * to a hardware address and port number on the local machine
126 * and that has a backlog queue to listen for remote connection
127 * requests. If the server cannot be created, an exception is
128 * thrown.
129 *
130 * @param bind local ip address or interface to use.
131 * @param port number to bind socket under.
132 * @param backlog size of connection request queue.
133 * @param mss maximum segment size for accepted streams.
134 */
135 TCPSocket(const IPV4Address &bind, tpport_t port, unsigned backlog = 5, unsigned mss = 536);
136
137 /**
138 * Create a named tcp socket by service and/or interface id.
139 * For IPV4 we use [host:]svc or [host/]svc for the string.
140 * If we have getaddrinfo, we use that to obtain the addr to
141 * bind for.
142 *
143 * @param name of host interface and service port to bind.
144 * @param backlog size of connection request queue.
145 * @param mss maximum segment size for streaming buffers.
146 */
147 TCPSocket(const char *name, unsigned backlog = 5, unsigned mss = 536);
148
149 /**
150 * Return address and port of next connection request. This
151 * can be used instead of OnAccept() to pre-evaluate connection
152 * requests.
153 *
154 * @return host requesting a connection.
155 * @param port number of requestor.
156 */
157 inline IPV4Host getRequest(tpport_t *port = NULL) const
158 {return Socket::getIPV4Sender(port);}
159
160 /**
161 * Used to reject the next incoming connection request.
162 */
163 void reject(void);
164
165 /**
166 * Used to get local bound address.
167 */
168 inline IPV4Host getLocal(tpport_t *port = NULL) const
169 {return Socket::getIPV4Local(port);}
170
171 /**
172 * Used to wait for pending connection requests.
173 * @return true if data packets available.
174 * @param timeout in milliseconds. TIMEOUT_INF if not specified.
175 */
176 inline bool isPendingConnection(timeout_t timeout = TIMEOUT_INF) /* not const -- jfc */
177 {return Socket::isPending(Socket::pendingInput, timeout);}
178
179 /**
180 * Use base socket handler for ending this socket.
181 */
182 virtual ~TCPSocket();
183};
184
185#ifdef CCXX_IPV6
186/**
187 * TCPV6 sockets are used for stream based connected sessions between two
188 * ipv6 sockets. Both error recovery and flow control operate transparently
189 * for a TCP socket connection. The TCP socket base class is primary used
190 * to bind a TCP "server" for accepting TCP streams.
191 *
192 * An implicit and unique TCPV6Socket object exists in Common C++ to represent
193 * a bound ipv6 TCP socket acting as a "server" for receiving connection requests.
194 * This class is not part of TCPStream because such objects normally perform
195 * no physical I/O (read or write operations) other than to specify a listen
196 * backlog queue and perform "accept" operations for pending connections.
197 * The Common C++ TCPV6Socket offers a Peek method to examine where the next
198 * pending connection is coming from, and a Reject method to flush the next
199 * request from the queue without having to create a session.
200 *
201 * The TCPV6Socket also supports a "OnAccept" method which can be called when a
202 * TCPStream related object is created from a TCPSocket. By creating a
203 * TCPStream from a TCPV6Socket, an accept operation automatically occurs, and
204 * the TCPV6Socket can then still reject the client connection through the
205 * return status of it's OnAccept method.
206 *
207 * @author David Sugar <dyfet@tycho.com>
208 * @short bound server for TCP streams and sessions.
209 */
210class __EXPORT TCPV6Socket : protected Socket
211{
212private:
213 int segsize;
214 void setSegmentSize(unsigned mss);
215
216public:
217 /**
218 * A method to call in a derived TCPSocket class that is acting
219 * as a server when a connection request is being accepted. The
220 * server can implement protocol specific rules to exclude the
221 * remote socket from being accepted by returning false. The
222 * Peek method can also be used for this purpose.
223 *
224 * @return true if client should be accepted.
225 * @param ia internet host address of the client.
226 * @param port number of the client.
227 */
228 virtual bool onAccept(const IPV6Host &ia, tpport_t port);
229
230 /**
231 * Fetch out the socket.
232 */
233 inline SOCKET getSocket(void)
234 {return so;};
235
236 inline int getSegmentSize(void)
237 {return segsize;};
238
239 /**
240 * A TCP "server" is created as a TCP socket that is bound
241 * to a hardware address and port number on the local machine
242 * and that has a backlog queue to listen for remote connection
243 * requests. If the server cannot be created, an exception is
244 * thrown.
245 *
246 * @param bind local ip address or interface to use.
247 * @param port number to bind socket under.
248 * @param backlog size of connection request queue.
249 * @param mss maximum segment size of streaming buffer.
250 */
251 TCPV6Socket(const IPV6Address &bind, tpport_t port, unsigned backlog = 5, unsigned mss = 536);
252
253 /**
254 * Create a TCP server for a named host interface and service
255 * port. We use [host/]port for specifying the optional host
256 * name and service port since ':' is a valid char for ipv6
257 * addresses.
258 *
259 * @param name of host interface and service to use.
260 * @param backlog size of connection request queue.
261 * @param mss maximum segment size of streaming buffers.
262 */
263 TCPV6Socket(const char *name, unsigned backlog = 5, unsigned mss = 536);
264
265 /**
266 * Return address and port of next connection request. This
267 * can be used instead of OnAccept() to pre-evaluate connection
268 * requests.
269 *
270 * @return host requesting a connection.
271 * @param port number of requestor.
272 */
273 inline IPV6Host getRequest(tpport_t *port = NULL) const
274 {return Socket::getIPV6Sender(port);}
275
276 /**
277 * Used to reject the next incoming connection request.
278 */
279 void reject(void);
280
281 /**
282 * Used to get local bound address.
283 */
284 inline IPV6Host getLocal(tpport_t *port = NULL) const
285 {return Socket::getIPV6Local(port);}
286
287 /**
288 * Used to wait for pending connection requests.
289 * @return true if data packets available.
290 * @param timeout in milliseconds. TIMEOUT_INF if not specified.
291 */
292 inline bool isPendingConnection(timeout_t timeout = TIMEOUT_INF) /* not const -- jfc */
293 {return Socket::isPending(Socket::pendingInput, timeout);}
294
295 /**
296 * Use base socket handler for ending this socket.
297 */
298 virtual ~TCPV6Socket();
299};
300#endif
301
302/**
303 * TCP streams are used to represent TCP client connections to a server
304 * by TCP protocol servers for accepting client connections. The TCP
305 * stream is a C++ "stream" class, and can accept streaming of data to
306 * and from other C++ objects using the << and >> operators.
307 *
308 * TCPStream itself can be formed either by connecting to a bound network
309 * address of a TCP server, or can be created when "accepting" a
310 * network connection from a TCP server.
311 *
312 * @author David Sugar <dyfet@ostel.com>
313 * @short streamable TCP socket connection.
314 */
315class __EXPORT TCPStream : protected std::streambuf, public Socket, public std::iostream
316{
317private:
318 int doallocate();
319
320 void segmentBuffering(unsigned mss);
321
322 friend TCPStream& crlf(TCPStream&);
323 friend TCPStream& lfcr(TCPStream&);
324
325 // no copy constructor...
326 TCPStream(const TCPStream &source);
327
328
329protected:
330 timeout_t timeout;
331 size_t bufsize;
332 Family family;
333 char *gbuf, *pbuf;
334
335public:
336 /**
337 * The constructor required for building other classes or to
338 * start an unconnected TCPStream for connect.
339 */
340 TCPStream(Family family = IPV4, bool throwflag = true, timeout_t to = 0);
341
342 /**
343 * Disconnect the current session and prepare for a new one.
344 */
345 void disconnect(void);
346
347 /**
348 * Get protocol segment size.
349 */
350 int getSegmentSize(void);
351
352protected:
353 /**
354 * Used to allocate the buffer space needed for iostream
355 * operations. This function is called by the constructor.
356 *
357 * @param size of stream buffers from constructor.
358 */
359 void allocate(size_t size);
360
361 /**
362 * Used to terminate the buffer space and cleanup the socket
363 * connection. This fucntion is called by the destructor.
364 */
365 void endStream(void);
366
367 /**
368 * This streambuf method is used to load the input buffer
369 * through the established tcp socket connection.
370 *
371 * @return char from get buffer, EOF if not connected.
372 */
373 int underflow();
374
375 /**
376 * This streambuf method is used for doing unbuffered reads
377 * through the establish tcp socket connection when in interactive mode.
378 * Also this method will handle proper use of buffers if not in
379 * interative mode.
380 *
381 * @return char from tcp socket connection, EOF if not connected.
382 */
383 int uflow();
384
385 /**
386 * This streambuf method is used to write the output
387 * buffer through the established tcp connection.
388 *
389 * @param ch char to push through.
390 * @return char pushed through.
391 */
392 int overflow(int ch);
393
394 /**
395 * Create a TCP stream by connecting to a TCP socket (on
396 * a remote machine).
397 *
398 * @param host address of remote TCP server.
399 * @param port number to connect.
400 * @param mss maximum segment size of streaming buffers.
401 */
402 void connect(const IPV4Host &host, tpport_t port, unsigned mss = 536);
403#ifdef CCXX_IPV6
404 void connect(const IPV6Host &host, tpport_t port, unsigned mss = 536);
405#endif
406
407 /**
408 * Connect a TCP stream to a named destination host and port
409 * number, using getaddrinfo interface if available.
410 *
411 * @param name of host and service to connect
412 * @param mss maximum segment size of stream buffer
413 */
414 void connect(const char *name, unsigned mss = 536);
415
416 /**
417 * Used in derived classes to refer to the current object via
418 * it's iostream. For example, to send a set of characters
419 * in a derived method, one might use *tcp() << "test".
420 *
421 * @return stream pointer of this object.
422 */
423 std::iostream *tcp(void)
424 {return ((std::iostream *)this);};
425
426public:
427 /**
428 * Create a TCP stream by accepting a connection from a bound
429 * TCP socket acting as a server. This performs an "accept"
430 * call.
431 *
432 * @param server socket listening
433 * @param throwflag flag to throw errors.
434 * @param timeout for all operations.
435 */
436 TCPStream(TCPSocket &server, bool throwflag = true, timeout_t timeout = 0);
437#ifdef CCXX_IPV6
438 TCPStream(TCPV6Socket &server, bool throwflag = true, timeout_t timeout = 0);
439#endif
440
441 /**
442 * Accept a connection from a TCP Server.
443 *
444 * @param server socket listening
445 */
446 void connect(TCPSocket &server);
447#ifdef CCXX_IPV6
448 void connect(TCPV6Socket &server);
449#endif
450
451 /**
452 * Create a TCP stream by connecting to a TCP socket (on
453 * a remote machine).
454 *
455 * @param host address of remote TCP server.
456 * @param port number to connect.
457 * @param mss maximum segment size of streaming buffers.
458 * @param throwflag flag to throw errors.
459 * @param timeout for all operations.
460 */
461 TCPStream(const IPV4Host &host, tpport_t port, unsigned mss = 536, bool throwflag = true, timeout_t timeout = 0);
462#ifdef CCXX_IPV6
463 TCPStream(const IPV6Host &host, tpport_t port, unsigned mss = 536, bool throwflag = true, timeout_t timeout = 0);
464#endif
465
466 /**
467 * Construct a named TCP Socket connected to a remote machine.
468 *
469 * @param name of remote service.
470 * @param family of protocol.
471 * @param mss maximum segment size of streaming buffers.
472 * @param throwflag flag to throw errors.
473 * @param timer for timeout for all operations.
474 */
475 TCPStream(const char *name, Family family = IPV4, unsigned mss = 536, bool throwflag = false, timeout_t timer = 0);
476
477 /**
478 * Set the I/O operation timeout for socket I/O operations.
479 *
480 * @param timer to change timeout.
481 */
482 inline void setTimeout(timeout_t timer)
483 {timeout = timer;};
484
485
486 /**
487 * Flush and empty all buffers, and then remove the allocated
488 * buffers.
489 */
490 virtual ~TCPStream();
491
492 /**
493 * Flushes the stream input and output buffers, writes
494 * pending output.
495 *
496 * @return 0 on success.
497 */
498 int sync(void);
499
500 /**
501 * Print content into a socket.
502 *
503 * @return count of bytes sent.
504 * @param format string
505 */
506 size_t printf(const char *format, ...);
507
508 /**
509 * Get the status of pending stream data. This can be used to
510 * examine if input or output is waiting, or if an error or
511 * disconnect has occured on the stream. If a read buffer
512 * contains data then input is ready and if write buffer
513 * contains data it is first flushed and then checked.
514 */
515 bool isPending(Pending pend, timeout_t timeout = TIMEOUT_INF);
516
517 /**
518 * Examine contents of next waiting packet.
519 *
520 * @param buf pointer to packet buffer for contents.
521 * @param len of packet buffer.
522 * @return number of bytes examined.
523 */
524 inline ssize_t peek(void *buf, size_t len)
525 {return ::recv(so, (char *)buf, len, MSG_PEEK);};
526
527 /**
528 * Return the size of the current stream buffering used.
529 *
530 * @return size of stream buffers.
531 */
532 inline size_t getBufferSize(void) const
533 {return bufsize;};
534};
535
536/**
537 * The TCP session is used to primarily to represent a client connection
538 * that can be managed on a seperate thread. The TCP session also supports
539 * a non-blocking connection scheme which prevents blocking during the
540 * constructor and moving the process of completing a connection into the
541 * thread that executes for the session.
542 *
543 * @author David Sugar <dyfet@ostel.com>
544 * @short Threaded streamable socket with non-blocking constructor.
545 */
546class __EXPORT TCPSession : public Thread, public TCPStream
547{
548private:
549 TCPSession(const TCPSession &rhs); // not defined
550protected:
551 /**
552 * Normally called during the thread Initial() method by default,
553 * this will wait for the socket connection to complete when
554 * connecting to a remote socket. One might wish to use
555 * setCompletion() to change the socket back to blocking I/O
556 * calls after the connection completes. To implement the
557 * session one must create a derived class which implements
558 * run().
559 *
560 * @return 0 if successful, -1 if timed out.
561 * @param timeout to wait for completion in milliseconds.
562 */
563 int waitConnection(timeout_t timeout = TIMEOUT_INF);
564
565 /**
566 * The initial method is used to esablish a connection when
567 * delayed completion is used. This assures the constructor
568 * terminates without having to wait for a connection request
569 * to complete.
570 */
571 void initial(void);
572
573public:
574 /**
575 * Create a TCP socket that will be connected to a remote TCP
576 * server and that will execute under it's own thread.
577 *
578 * @param host internet address of remote TCP server.
579 * @param port number of remote server.
580 * @param size of streaming buffer.
581 * @param pri execution priority relative to parent.
582 * @param stack allocation needed on some platforms.
583 */
584 TCPSession(const IPV4Host &host,
585 tpport_t port, size_t size = 536, int pri = 0, size_t stack = 0);
586#ifdef CCXX_IPV6
587 TCPSession(const IPV6Host &host,
588 tpport_t port, size_t size = 536, int pri = 0, size_t stack = 0);
589#endif
590
591 /**
592 * Create a TCP socket from a bound TCP server by accepting a pending
593 * connection from that server and execute a thread for the accepted
594 * connection.
595 *
596 * @param server tcp socket to accept a connection from.
597 * @param pri execution priority relative to parent.
598 * @param stack allocation needed on some platforms.
599 */
600 TCPSession(TCPSocket &server, int pri = 0, size_t stack = 0);
601#ifdef CCXX_IPV6
602 TCPSession(TCPV6Socket &server, int pri = 0, size_t stack = 0);
603#endif
604
605 /**
606 * Make sure destruction happens through a virtual...
607 */
608 virtual ~TCPSession();
609};
610
611END_NAMESPACE
612
613#endif