/[resiprocate]/main/sip/resiprocate/TcpBaseTransport.cxx
ViewVC logotype

Contents of /main/sip/resiprocate/TcpBaseTransport.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4599 - (show annotations) (download)
Wed May 11 23:10:19 2005 UTC (14 years, 7 months ago) by derek
File size: 10876 byte(s)
set svn:eol-style to LF
1 #if defined(HAVE_CONFIG_H)
2 #include "resiprocate/config.hxx"
3 #endif
4
5 #include <memory>
6 #include "resiprocate/os/compat.hxx"
7 #include "resiprocate/os/Data.hxx"
8 #include "resiprocate/os/DnsUtil.hxx"
9 #include "resiprocate/os/Socket.hxx"
10 #include "resiprocate/os/Logger.hxx"
11 #include "resiprocate/TcpBaseTransport.hxx"
12
13 #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
14
15 using namespace std;
16 using namespace resip;
17
18 const size_t TcpBaseTransport::MaxWriteSize = 4096;
19 const size_t TcpBaseTransport::MaxReadSize = 4096;
20
21 TcpBaseTransport::TcpBaseTransport(Fifo<TransactionMessage>& fifo, int portNum, IpVersion version,
22 const Data& pinterface)
23 : InternalTransport(fifo, portNum, version, pinterface)
24 {
25 mFd = InternalTransport::socket(TCP, version);
26 //DebugLog (<< "Opening TCP " << mFd << " : " << this);
27
28 #if !defined(WIN32)
29 int on = 1;
30 if ( ::setsockopt ( mFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) )
31 {
32 int e = getErrno();
33 InfoLog (<< "Couldn't set sockoptions SO_REUSEPORT | SO_REUSEADDR: " << strerror(e));
34 error(e);
35 throw Exception("Failed setsockopt", __FILE__,__LINE__);
36 }
37 #endif
38
39 bind();
40 makeSocketNonBlocking(mFd);
41
42 // do the listen, seting the maximum queue size for compeletly established
43 // sockets -- on linux, tcp_max_syn_backlog should be used for the incomplete
44 // queue size(see man listen)
45 int e = listen(mFd,64 );
46
47 if (e != 0 )
48 {
49 int e = getErrno();
50 InfoLog (<< "Failed listen " << strerror(e));
51 error(e);
52 // !cj! deal with errors
53 throw Transport::Exception("Address already in use", __FILE__,__LINE__);
54 }
55 }
56
57
58 TcpBaseTransport::~TcpBaseTransport()
59 {
60 //DebugLog (<< "Shutting down TCP Transport " << this << " " << mFd << " " << mInterface << ":" << port());
61
62 // !jf! this is not right. should drain the sends before
63 while (mTxFifo.messageAvailable())
64 {
65 SendData* data = mTxFifo.getNext();
66 InfoLog (<< "Throwing away queued data for " << data->destination);
67
68 fail(data->transactionId);
69 delete data;
70 }
71 DebugLog (<< "Shutting down " << mTuple);
72 ThreadIf::shutdown();
73 join();
74 //mSendRoundRobin.clear(); // clear before we delete the connections
75 }
76
77 void
78 TcpBaseTransport::buildFdSet( FdSet& fdset)
79 {
80 mConnectionManager.buildFdSet(fdset);
81 fdset.setRead(mFd); // for the transport itself
82 }
83
84 void
85 TcpBaseTransport::processListen(FdSet& fdset)
86 {
87 if (fdset.readyToRead(mFd))
88 {
89 Tuple tuple(mTuple);
90 struct sockaddr& peer = tuple.getMutableSockaddr();
91 socklen_t peerLen = tuple.length();
92 Socket sock = accept( mFd, &peer, &peerLen);
93 if ( sock == SOCKET_ERROR )
94 {
95 int e = getErrno();
96 switch (e)
97 {
98 case EWOULDBLOCK:
99 // !jf! this can not be ready in some cases
100 return;
101 default:
102 Transport::error(e);
103 }
104 return;
105 }
106 makeSocketNonBlocking(sock);
107
108 tuple.transport = this;
109 DebugLog (<< "Received TCP connection from: " << tuple << " as fd=" << sock);
110 createConnection(tuple, sock, true);
111 }
112 }
113
114 void
115 TcpBaseTransport::processSomeWrites(FdSet& fdset)
116 {
117 // !jf! may want to do a roundrobin later
118 Connection* curr = mConnectionManager.getNextWrite();
119 if (curr && fdset.readyToWrite(curr->getSocket()))
120 {
121 //DebugLog (<< "TcpBaseTransport::processSomeWrites() " << curr->getSocket());
122 curr->performWrite();
123 }
124 else if (curr && fdset.hasException(curr->getSocket()))
125 {
126 int errNum = 0;
127 int errNumSize = sizeof(errNum);
128 getsockopt(curr->getSocket(),SOL_SOCKET,SO_ERROR,(char *)&errNum,(socklen_t *)&errNumSize);
129 InfoLog (<< "Exception writing to socket " << curr->getSocket() << " code: " << errNum << "; closing connection");
130 delete curr;
131 }
132 }
133
134 void
135 TcpBaseTransport::processSomeReads(FdSet& fdset)
136 {
137 Connection* currConnection = mConnectionManager.getNextRead(fdset);
138 if (currConnection)
139 {
140 if ( fdset.readyToRead(currConnection->getSocket()) ||
141 currConnection->hasDataToRead() )
142 {
143 DebugLog (<< "TcpBaseTransport::processSomeReads() " << *currConnection);
144 fdset.clear(currConnection->getSocket());
145
146 int bytesRead = currConnection->read(mStateMachineFifo);
147 DebugLog (<< "TcpBaseTransport::processSomeReads() "
148 << *currConnection << " read=" << bytesRead);
149 if (bytesRead < 0)
150 {
151 DebugLog (<< "Closing connection bytesRead=" << bytesRead);
152 delete currConnection;
153 }
154 }
155 else if (fdset.hasException(currConnection->getSocket()))
156 {
157 int errNum = 0;
158 int errNumSize = sizeof(errNum);
159 getsockopt(currConnection->getSocket(),SOL_SOCKET,SO_ERROR,(char *)&errNum,(socklen_t *)&errNumSize);
160 InfoLog (<< "Exception reading from socket " << currConnection->getSocket() << " code: " << errNum << "; closing connection");
161 delete currConnection;
162 }
163 }
164 }
165
166
167 void
168 TcpBaseTransport::processAllWriteRequests( FdSet& fdset )
169 {
170 while (mTxFifo.messageAvailable())
171 {
172 SendData* data = mTxFifo.getNext();
173 DebugLog (<< "Processing write for " << data->destination);
174
175 // this will check by connectionId first, then by address
176 Connection* conn = mConnectionManager.findConnection(data->destination);
177 if ( conn )
178 {
179 assert( conn->transport() );
180 }
181
182 //DebugLog (<< "TcpBaseTransport::processAllWriteRequests() using " << conn);
183
184 // There is no connection yet, so make a client connection
185 if (conn == 0)
186 {
187 // attempt to open
188 Socket sock = InternalTransport::socket( TCP, ipVersion());
189 fdset.clear(sock);
190
191 if ( sock == INVALID_SOCKET ) // no socket found - try to free one up and try again
192 {
193 int e = getErrno();
194 InfoLog (<< "Failed to create a socket " << strerror(e));
195 error(e);
196 mConnectionManager.gc(ConnectionManager::MinLastUsed); // free one up
197
198 sock = InternalTransport::socket( TCP, ipVersion());
199 if ( sock == INVALID_SOCKET )
200 {
201 int e = getErrno();
202 WarningLog( << "Error in finding free filedescriptor to use. " << strerror(e));
203 error(e);
204 fail(data->transactionId);
205 delete data;
206 return;
207 }
208 }
209
210 assert(sock != INVALID_SOCKET);
211 const sockaddr& servaddr = data->destination.getSockaddr();
212
213 DebugLog (<<"Opening new connection to " << data->destination);
214 makeSocketNonBlocking(sock);
215 int e = connect( sock, &servaddr, data->destination.length() );
216
217 // See Chapter 15.3 of Stevens, Unix Network Programming Vol. 1 2nd Edition
218 if (e == INVALID_SOCKET)
219 {
220 int err = getErrno();
221
222 switch (err)
223 {
224 case EINPROGRESS:
225 case EWOULDBLOCK:
226 break;
227 default:
228 {
229 // !jf! this has failed
230 InfoLog( << "Error on TCP connect to " << data->destination << ": " << strerror(err));
231 error(e);
232 fdset.clear(sock);
233 close(sock);
234 fail(data->transactionId);
235 delete data;
236 return;
237 }
238 }
239 }
240
241 // This will add the connection to the manager
242 conn = createConnection(data->destination, sock, false);
243 assert(conn);
244 assert( conn->transport() );
245
246 data->destination.transport = this;
247 data->destination.connectionId = conn->getId(); // !jf!
248 }
249
250 if (conn == 0)
251 {
252 DebugLog (<< "Failed to create/get connection: " << data->destination);
253 fail(data->transactionId);
254 delete data;
255 }
256 else // have a connection
257 {
258 assert( conn->transport() );
259
260 conn->requestWrite(data);
261 }
262 }
263 }
264
265 void
266 TcpBaseTransport::process(FdSet& fdSet)
267 {
268 processAllWriteRequests(fdSet);
269 if(fdSet.numReady > 0)
270 {
271 processSomeWrites(fdSet);
272 processSomeReads(fdSet);
273 processListen(fdSet);
274 }
275 }
276
277
278 /* ====================================================================
279 * The Vovida Software License, Version 1.0
280 *
281 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
282 *
283 * Redistribution and use in source and binary forms, with or without
284 * modification, are permitted provided that the following conditions
285 * are met:
286 *
287 * 1. Redistributions of source code must retain the above copyright
288 * notice, this list of conditions and the following disclaimer.
289 *
290 * 2. Redistributions in binary form must reproduce the above copyright
291 * notice, this list of conditions and the following disclaimer in
292 * the documentation and/or other materials provided with the
293 * distribution.
294 *
295 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
296 * and "Vovida Open Communication Application Library (VOCAL)" must
297 * not be used to endorse or promote products derived from this
298 * software without prior written permission. For written
299 * permission, please contact vocal@vovida.org.
300 *
301 * 4. Products derived from this software may not be called "VOCAL", nor
302 * may "VOCAL" appear in their name, without prior written
303 * permission of Vovida Networks, Inc.
304 *
305 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
306 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
307 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
308 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
309 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
310 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
311 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
312 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
313 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
314 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
315 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
316 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
317 * DAMAGE.
318 *
319 * ====================================================================
320 *
321 * This software consists of voluntary contributions made by Vovida
322 * Networks, Inc. and many individuals on behalf of Vovida Networks,
323 * Inc. For more information on Vovida Networks, Inc., please see
324 * <http://www.vovida.org/>.
325 *
326 */
327
328

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27