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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 991 - (show annotations) (download)
Tue Dec 31 06:10:38 2002 UTC (17 years, 1 month ago) by fluffy
File size: 12909 byte(s)
*** empty log message ***

1
2 #ifndef WIN32
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <iostream>
6 #include <netinet/in.h>
7 #include <stdlib.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <unistd.h>
11 #include <arpa/inet.h>
12 #endif
13
14 #include <memory>
15 #include "sip2/util/Data.hxx"
16 #include "sip2/util/Socket.hxx"
17 #include "sip2/util/Logger.hxx"
18 #include "sip2/util/compat.hxx"
19 #include "sip2/sipstack/TlsTransport.hxx"
20 #include "sip2/sipstack/SipMessage.hxx"
21 #include "sip2/sipstack/Preparse.hxx"
22 #include "sip2/sipstack/Security.hxx"
23
24 #define VOCAL_SUBSYSTEM Subsystem::TRANSPORT
25
26 using namespace std;
27 using namespace Vocal2;
28
29 const size_t TlsTransport::MaxWriteSize = 4096;
30 const size_t TlsTransport::MaxReadSize = 4096;
31
32
33 TlsTransport::TlsTransport(const Data& sendhost, int portNum,
34 const Data& nic, Fifo<Message>& fifo,Security* security) :
35 Transport(sendhost, portNum, nic , fifo)
36 {
37 mSendPos = mSendRoundRobin.end();
38 mFd = socket(PF_INET, SOCK_STREAM, 0);
39 mSecurity = security;
40 assert( mSecurity );
41
42 if ( mFd == INVALID_SOCKET )
43 {
44 InfoLog (<< "Failed to open socket: " << portNum);
45 }
46
47 #ifndef WIN32
48 int on = 1;
49 if ( ::setsockopt ( mFd, SOL_SOCKET, SO_REUSEADDR, // | SO_REUSEPORT,
50 (void*)(&on), sizeof ( on )) )
51 {
52 int err = errno;
53 InfoLog (<< "Couldn't set sockoptions SO_REUSEPORT | SO_REUSEADDR: "
54 << strerror(err));
55 throw Exception("Failed setsockopt", __FILE__,__LINE__);
56 }
57 #endif
58
59 //makeSocketNonBlocking(mFd);
60
61 sockaddr_in addr;
62 addr.sin_family = AF_INET;
63 addr.sin_addr.s_addr = htonl(INADDR_ANY); // !jf!--change when nic specfied
64 addr.sin_port = htons(portNum);
65
66 if ( bind( mFd, (struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR )
67 {
68 int err = errno;
69 if ( err == EADDRINUSE )
70 {
71 ErrLog (<< "Port " << portNum << " already in use");
72 }
73 else
74 {
75 ErrLog (<< "Could not bind to port: " << portNum);
76 }
77
78 throw Exception("Address already in use", __FILE__,__LINE__);
79 }
80
81 makeSocketNonBlocking(mFd);
82
83 // do the listen, seting the maximum queue size for compeletly established
84 // sockets -- on linux, tcp_max_syn_backlog should be used for the incomplete
85 // queue size(see man listen)
86 int e = listen(mFd,64 );
87
88 if (e != 0 )
89 {
90 //int err = errno;
91 // !cj! deal with errors
92 assert(0);
93 }
94 }
95
96
97 TlsTransport::~TlsTransport()
98 {
99 //::shutdown(mFd, SHUT_RDWR);
100 closesocket(mFd);
101 }
102
103
104 void
105 TlsTransport::buildFdSet( FdSet& fdset)
106 {
107 for (ConnectionMap::Map::iterator it = mConnectionMap.mConnections.begin();
108 it != mConnectionMap.mConnections.end(); it++)
109 {
110 fdset.setRead(it->second->getSocket());
111 fdset.setWrite(it->second->getSocket());
112 }
113 fdset.setRead(mFd);
114
115 }
116
117
118 void
119 TlsTransport::processListen(FdSet& fdset)
120 {
121 if (fdset.readyToRead(mFd))
122 {
123 struct sockaddr_in peer;
124
125 socklen_t peerLen=sizeof(peer);
126 Socket sock = accept( mFd, (struct sockaddr*)&peer,&peerLen);
127 if ( sock == -1 )
128 {
129 int err = errno;
130 DebugLog( << "Error on accept: " << strerror(err));
131 return;
132 }
133
134 TlsConnection* tls = new TlsConnection( mSecurity, sock, /*server*/ true );
135 assert(tls);
136
137 makeSocketNonBlocking(sock);
138
139 Transport::Tuple who;
140 who.ipv4 = peer.sin_addr;
141 who.port = ntohs(peer.sin_port);
142 who.transportType = Transport::TLS;
143 who.transport = this;
144
145 Connection* con = mConnectionMap.add(who, sock);
146 assert( con );
147 con->mTlsConnection = tls;
148
149 DebugLog( << "Added server connection " << int(con) );
150 }
151 }
152
153
154 bool
155 TlsTransport::processRead(Connection* c)
156 {
157 std::pair<char* const, size_t> writePair = c->getWriteBuffer();
158 size_t bytesToRead = writePair.second;
159 if ( bytesToRead > TlsTransport::MaxReadSize)
160 {
161 bytesToRead = TlsTransport::MaxReadSize;
162 }
163
164 DebugLog( << "Read from connection " << int(c) );
165
166 assert( c->mTlsConnection );
167 int bytesRead = c->mTlsConnection->read( writePair.first, bytesToRead);
168 if (bytesRead <= 0)
169 {
170 int err = errno;
171 DebugLog(<< "bytesRead: " << bytesRead);
172 DebugLog(<< "TlsTransport::processRead failed for " << *c
173 << " " << strerror(err));
174 return false;
175 }
176 if (c->process(bytesRead, mStateMachineFifo))
177 {
178 mConnectionMap.touch(c);
179 return true;
180 }
181 else
182 {
183 DebugLog (<< "TlsTransport::processRead failed due to bad message " << *c );
184 return false;
185 }
186 }
187
188
189 void
190 TlsTransport::processAllReads(FdSet& fdset)
191 {
192 if (!mConnectionMap.mConnections.empty())
193 {
194 for (Connection* c = mConnectionMap.mPostOldest.mYounger;
195 c != &mConnectionMap.mPreYoungest; c = c->mYounger)
196 {
197 // !jf! - TODO - likely need to call the tlsConnection-.isReady stuff
198 if (fdset.readyToRead(c->getSocket()))
199 {
200 if (processRead(c))
201 {
202 return;
203 }
204 else
205 {
206 DebugLog(<< "TlsTransport::processAllReads -- closing: " << *c);
207 mConnectionMap.close(c->mWho);
208 return;
209 }
210 }
211 }
212 }
213 }
214
215
216 void
217 TlsTransport::processAllWrites( FdSet& fdset )
218 {
219 if (mTxFifo.messageAvailable())
220 {
221 SendData* data = mTxFifo.getNext();
222 Connection* conn = mConnectionMap.get(data->destination);
223
224 if (conn == 0)
225 {
226 // attempt to open
227 Socket sock = socket( AF_INET, SOCK_STREAM, 0 );
228
229 if ( sock == -1 ) // no socket found - try to free one up and try again
230 {
231 // !dlb! does the file descriptor become available immediately?
232 mConnectionMap.gc(ConnectionMap::MinLastUsed); // free one up
233 sock = socket( AF_INET, SOCK_STREAM, 0 ); // try again
234 }
235
236 if ( sock == -1 )
237 {
238 DebugLog( << "Error in TLS finding free socket to use" );
239 }
240 else
241 {
242 struct sockaddr_in servaddr;
243 memset( &servaddr, sizeof(servaddr), 0 );
244 servaddr.sin_family = AF_INET;
245 servaddr.sin_port = htons( data->destination.port);
246 servaddr.sin_addr = data->destination.ipv4;
247
248 int e = connect( sock, (struct sockaddr *)&servaddr, sizeof(servaddr) );
249 if ( e == -1 )
250 {
251 int err = errno;
252 DebugLog( << "Error on TLS connect to " << data->destination << ": " << strerror(err));
253 }
254 else
255 {
256 // succeeded, add the connection
257 TlsConnection* tls = new TlsConnection( mSecurity, sock, /*server*/ false );
258 assert(tls);
259
260 mConnectionMap.add( data->destination, sock);
261
262 conn = mConnectionMap.get(data->destination);
263 assert( conn );
264
265 conn->mTlsConnection = tls;
266
267 makeSocketNonBlocking(sock);
268
269 DebugLog( << "Added TLS client connection " << int(conn) );
270 }
271 }
272 }
273
274 if (conn == 0)
275 {
276 DebugLog (<< "Failed to create/get connection: " << data->destination);
277 fail(data->transactionId);
278 delete data;
279 return;
280 }
281
282 if (conn->mOutstandingSends.empty())
283 {
284 DebugLog (<< "Adding " << *conn << " to send roundrobin");
285 mSendRoundRobin.push_back(conn);
286 conn->mSendPos = 0;
287 }
288
289 conn->mOutstandingSends.push_back(data);
290 }
291
292 sendFromRoundRobin(fdset);
293 }
294
295
296 void
297 TlsTransport::sendFromRoundRobin(FdSet& fdset)
298 {
299 if (!mSendRoundRobin.empty())
300 {
301 ConnectionList::iterator rrPos = mSendPos;
302 do
303 {
304 if (mSendPos == mSendRoundRobin.end())
305 {
306 mSendPos = mSendRoundRobin.begin();
307 }
308 if (fdset.readyToWrite((*mSendPos)->getSocket()))
309 {
310 if (processWrite(*mSendPos))
311 {
312 if ((*mSendPos)->mOutstandingSends.empty())
313 {
314 DebugLog (<< "Finished send, removing " << **mSendPos << " from roundrobin");
315 mSendPos = mSendRoundRobin.erase(mSendPos);
316 }
317 else
318 {
319 mSendPos++;
320 }
321 return;
322 }
323 else
324 {
325 DebugLog (<< "Failed send, removing " << **mSendPos << " from roundrobin");
326 DebugLog(<< "TlsTransport::processAllWrites -- closing: " << **mSendPos);
327 mConnectionMap.close((*mSendPos)->mWho);
328 mSendPos = mSendRoundRobin.erase(mSendPos);
329 return;
330 }
331 }
332 else
333 {
334 mSendPos++;
335 }
336 } while(mSendPos != rrPos && !mSendRoundRobin.empty());
337 }
338 }
339
340
341 bool
342 TlsTransport::processWrite(Connection* c)
343 {
344 assert(c);
345
346 assert(!c->mOutstandingSends.empty());
347 SendData* data = c->mOutstandingSends.front();
348
349 size_t bytesToWrite = data->data.size() - c->mSendPos;
350 if ( bytesToWrite > TlsTransport::MaxWriteSize)
351 {
352 bytesToWrite = TlsTransport::MaxWriteSize;
353 }
354
355 DebugLog( << "Write to connection " << int(c) );
356
357 assert( c->mTlsConnection );
358 int bytesWritten = c->mTlsConnection->write( data->data.data() + c->mSendPos, bytesToWrite);
359 int err = errno;
360
361 if (bytesWritten <= 0)
362 {
363 DebugLog (<< "Failed write to " << *c << " :" << strerror(err));
364 fail(data->transactionId);
365 return false;
366 }
367 else if ((size_t)bytesWritten < data->data.size() - c->mSendPos)
368 {
369 DebugLog (<< "##Wrote " << bytesWritten << " to " << *c);
370 c->mSendPos += bytesWritten;
371 }
372 else
373 {
374 DebugLog (<< "##Finished write " << bytesWritten << " to " << *c);
375 DebugLog (<< "Sent: " << data->data);
376 c->mOutstandingSends.pop_front();
377 DebugLog (<< "mOutstandingSends.size() " << c->mOutstandingSends.size());
378 c->mSendPos = 0;
379 ok(data->transactionId);
380 delete data;
381 }
382 mConnectionMap.touch(c);
383 return true;
384 }
385
386
387 void
388 TlsTransport::process(FdSet& fdSet)
389 {
390 if ( mTxFifo.messageAvailable() )
391 {
392 DebugLog(<<"TLSTransport mTxFifo:size: " << mTxFifo.size());
393 }
394 processAllWrites(fdSet);
395 processListen(fdSet);
396 processAllReads(fdSet);
397 //DebugLog(<< "Finished TlsTransport::process");
398 }
399
400
401 /* ====================================================================
402 * The Vovida Software License, Version 1.0
403 *
404 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
405 *
406 * Redistribution and use in source and binary forms, with or without
407 * modification, are permitted provided that the following conditions
408 * are met:
409 *
410 * 1. Redistributions of source code must retain the above copyright
411 * notice, this list of conditions and the following disclaimer.
412 *
413 * 2. Redistributions in binary form must reproduce the above copyright
414 * notice, this list of conditions and the following disclaimer in
415 * the documentation and/or other materials provided with the
416 * distribution.
417 *
418 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
419 * and "Vovida Open Communication Application Library (VOCAL)" must
420 * not be used to endorse or promote products derived from this
421 * software without prior written permission. For written
422 * permission, please contact vocal@vovida.org.
423 *
424 * 4. Products derived from this software may not be called "VOCAL", nor
425 * may "VOCAL" appear in their name, without prior written
426 * permission of Vovida Networks, Inc.
427 *
428 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
429 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
430 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
431 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
432 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
433 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
434 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
435 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
436 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
437 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
438 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
439 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
440 * DAMAGE.
441 *
442 * ====================================================================
443 *
444 * This software consists of voluntary contributions made by Vovida
445 * Networks, Inc. and many individuals on behalf of Vovida Networks,
446 * Inc. For more information on Vovida Networks, Inc., please see
447 * <http://www.vovida.org/>.
448 *
449 */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27