blob: f23be8c6d171cbc1bcbaf7fe55aa853d84e3bacf [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 2010 David Sugar, Tycho Softworks.
2//
3// This file is part of GNU uCommon C++.
4//
5// GNU uCommon C++ is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published
7// by the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// GNU uCommon C++ is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
17
18#include <ucommon-config.h>
19#include <ucommon/export.h>
20#include <ucommon/protocols.h>
21#include <ucommon/socket.h>
22#include <ucommon/timers.h>
23#include <ucommon/buffer.h>
24#include <ucommon/string.h>
25#include <ucommon/shell.h>
26
27using namespace UCOMMON_NAMESPACE;
28
29TCPBuffer::TCPBuffer() :
30BufferProtocol()
31{
32 so = INVALID_SOCKET;
33}
34
35TCPBuffer::TCPBuffer(const char *host, const char *service, size_t size) :
36BufferProtocol()
37{
38 so = INVALID_SOCKET;
39 open(host, service, size);
40}
41
42TCPBuffer::TCPBuffer(const TCPServer *server, size_t size) :
43BufferProtocol()
44{
45 so = INVALID_SOCKET;
46 open(server, size);
47}
48
49TCPBuffer::~TCPBuffer()
50{
51 TCPBuffer::close();
52}
53
54void TCPBuffer::open(const char *host, const char *service, size_t size)
55{
56 struct addrinfo *list = Socket::query(host, service, SOCK_STREAM, 0);
57 if(!list)
58 return;
59
60 so = Socket::create(list, SOCK_STREAM, 0);
61 Socket::release(list);
62 if(so == INVALID_SOCKET)
63 return;
64
65 _buffer(size);
66}
67
68void TCPBuffer::open(const TCPServer *server, size_t size)
69{
70 close();
71 so = server->accept();
72 if(so == INVALID_SOCKET)
73 return;
74
75 _buffer(size);
76}
77
78void TCPBuffer::close(void)
79{
80 if(so == INVALID_SOCKET)
81 return;
82
83 BufferProtocol::release();
84 Socket::release(so);
85 so = INVALID_SOCKET;
86}
87
88void TCPBuffer::_buffer(size_t size)
89{
90 unsigned iobuf = 0;
91 unsigned mss = size;
92 unsigned max = 0;
93
94#ifdef TCP_MAXSEG
95 socklen_t alen = sizeof(max);
96#endif
97
98 if(size < 80) {
99 allocate(size);
100 return;
101 }
102
103#ifdef TCP_MAXSEG
104 if(mss)
105 setsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&max, sizeof(max));
106 getsockopt(so, IPPROTO_TCP, TCP_MAXSEG, (char *)&max, &alen);
107#endif
108
109 if(max && max < mss)
110 mss = max;
111
112 if(!mss) {
113 if(max)
114 mss = max;
115 else
116 mss = 536;
117 goto alloc;
118 }
119
120 if(mss < 80)
121 mss = 80;
122
123 if(mss * 7 < 64000u)
124 iobuf = mss * 7;
125 else if(size * 6 < 64000u)
126 iobuf = mss * 6;
127 else
128 iobuf = mss * 5;
129
130 Socket::sendsize(so, iobuf);
131 Socket::recvsize(so, iobuf);
132
133 if(mss < 512)
134 Socket::sendwait(so, mss * 4);
135
136alloc:
137 allocate(size);
138}
139
140int TCPBuffer::_err(void) const
141{
142 return ioerr;
143}
144
145void TCPBuffer::_clear(void)
146{
147 ioerr = 0;
148}
149
150bool TCPBuffer::_blocking(void)
151{
152 if(iowait)
153 return true;
154
155 return false;
156}
157
158size_t TCPBuffer::_push(const char *address, size_t len)
159{
160 if(ioerr)
161 return 0;
162
163 ssize_t result = writeto(address, len);
164 if(result < 0)
165 result = 0;
166
167 return (size_t)result;
168}
169
170size_t TCPBuffer::_pull(char *address, size_t len)
171{
172 ssize_t result;
173
174 result = readfrom(address, len);
175
176 if(result < 0)
177 result = 0;
178 return (size_t)result;
179}
180
181bool TCPBuffer::_pending(void)
182{
183 if(input_pending())
184 return true;
185
186 if(is_input() && iowait && iowait != Timer::inf)
187 return Socket::wait(so, iowait);
188
189 return Socket::wait(so, 0);
190}