Logo
~Sockets~
~Examples~
~Contact~


TcpSocket Class Reference
[Basic sockets]

Socket implementation for TCP. More...

#include <TcpSocket.h>

Inheritance diagram for TcpSocket:
Collaboration diagram for TcpSocket:

List of all members.


Public Member Functions

 TcpSocket (ISocketHandler &)
 Constructor with standard values on input/output buffers.
 TcpSocket (ISocketHandler &h, size_t isize, size_t osize)
 Constructor with custom values for i/o buffer.
 ~TcpSocket ()
bool Open (ipaddr_t ip, port_t port, bool skip_socks=false)
 Open a connection to a remote server.
bool Open (SocketAddress &, bool skip_socks=false)
bool Open (SocketAddress &, SocketAddress &bind_address, bool skip_socks=false)
bool Open (const std::string &host, port_t port)
 Open connection.
void OnConnectTimeout ()
 Connect timeout callback.
int Close ()
 Close file descriptor - internal use only.
void Send (const std::string &s, int f=0)
 Send a string.
void Sendf (const char *format,...)
 Send string using printf formatting.
void SendBuf (const char *buf, size_t len, int f=0)
 Send buffer of bytes.
virtual void OnRawData (const char *buf, size_t len)
 This callback is executed after a successful read from the socket.
virtual void OnWriteComplete ()
 Called when output buffer has been sent.
size_t GetInputLength ()
 Number of bytes in input buffer.
size_t GetOutputLength ()
 Number of bytes in output buffer.
void OnLine (const std::string &line)
 Callback fires when a socket in line protocol has read one full line.
uint64_t GetBytesReceived (bool clear=false)
 Get counter of number of bytes received.
uint64_t GetBytesSent (bool clear=false)
 Get counter of number of bytes sent.
void OnSocks4Connect ()
 Socks4 specific callback.
void OnSocks4ConnectFailed ()
 Socks4 specific callback.
bool OnSocks4Read ()
 Socks4 specific callback.
void OnResolved (int id, ipaddr_t a, port_t port)
 Callback executed when resolver thread has finished a resolve request.
void OnSSLConnect ()
 Callback for 'New' ssl support - replaces SSLSocket.
void OnSSLAccept ()
 Callback for 'New' ssl support - replaces SSLSocket.
virtual void InitSSLClient ()
 This method must be implemented to initialize the ssl context for an outgoing connection.
virtual void InitSSLServer ()
 This method must be implemented to initialize the ssl context for an incoming connection.
void SetReconnect (bool=true)
 Flag that says a broken connection will try to reconnect.
bool Reconnect ()
 Check reconnect on lost connection flag status.
void SetIsReconnect (bool x=true)
 Flag to determine if a reconnect is in progress.
bool IsReconnect ()
 Socket is reconnecting.
void DisableInputBuffer (bool=true)
void OnOptions (int, int, int, SOCKET)
 Called when a client socket is created, to set socket options.
void SetLineProtocol (bool=true)
 Called after OnRead if socket is in line protocol mode.
bool SetTcpNodelay (bool=true)
virtual int Protocol ()
 Returns IPPROTO_TCP or IPPROTO_SCTP.
void SetTransferLimit (size_t sz)
 Trigger limit for callback OnTransferLimit.
virtual void OnTransferLimit ()
 This callback fires when the output buffer drops below the value set by SetTransferLimit.

Protected Types

typedef std::list< OUTPUT * > output_l

Protected Member Functions

 TcpSocket (const TcpSocket &)
void OnRead ()
 Called when there is something to be read from the file descriptor.
void OnRead (char *buf, size_t n)
void OnWrite ()
 Called when there is room for another write on the file descriptor.
void InitializeContext (const std::string &context, SSL_METHOD *meth_in=NULL)
 SSL; Initialize ssl context for a client socket.
void InitializeContext (const std::string &context, const std::string &keyfile, const std::string &password, SSL_METHOD *meth_in=NULL)
 SSL; Initialize ssl context for a server socket.
void InitializeContext (const std::string &context, const std::string &certfile, const std::string &keyfile, const std::string &password, SSL_METHOD *meth_in=NULL)
 SSL; Initialize ssl context for a server socket.
virtual SSL_CTX * GetSslContext ()
 SSL; Get pointer to ssl context structure.
virtual SSL * GetSsl ()
 SSL; Get pointer to ssl structure.
bool SSLNegotiate ()
 ssl; still negotiating connection.
const std::string & GetPassword ()
 SSL; Get ssl password.

Static Protected Member Functions

static int SSL_password_cb (char *buf, int num, int rwflag, void *userdata)
 SSL; Password callback method.

Protected Attributes

CircularBuffer ibuf
 Circular input buffer.

Private Member Functions

TcpSocketoperator= (const TcpSocket &)
int TryWrite (const char *buf, size_t len)
 the actual send()
void Buffer (const char *buf, size_t len)
 add data to output buffer top

Private Attributes

bool m_b_input_buffer_disabled
uint64_t m_bytes_sent
uint64_t m_bytes_received
bool m_skip_c
 Skip second char of CRLF or LFCR sequence in OnRead.
char m_c
 First char in CRLF or LFCR sequence.
std::string m_line
 Current line in line protocol mode.
char * m_buf
 temporary read buffer
output_l m_obuf
 output buffer
OUTPUTm_obuf_top
 output buffer on top
size_t m_transfer_limit
size_t m_output_length
SSL_CTX * m_ssl_ctx
 ssl context
SSL * m_ssl
 ssl 'socket'
BIO * m_sbio
 ssl bio
std::string m_password
 ssl password
int m_socks4_state
 socks4 support
char m_socks4_vn
 socks4 support, temporary variable
char m_socks4_cd
 socks4 support, temporary variable
unsigned short m_socks4_dstport
 socks4 support
unsigned long m_socks4_dstip
 socks4 support
int m_resolver_id
 Resolver id (if any) for current Open call.
bool m_b_reconnect
 Reconnect on lost connection flag.
bool m_b_is_reconnect
 Trying to reconnect.

Static Private Attributes

static SSLInitializer m_ssl_init
static Mutex m_server_ssl_mutex
static std::map< std::string,
SSL_CTX * > 
m_client_contexts
static std::map< std::string,
SSL_CTX * > 
m_server_contexts

Classes

class  CircularBuffer
 Buffer class containing one read/write circular buffer. More...
struct  OUTPUT
 Output buffer struct. More...

Detailed Description

Socket implementation for TCP.

Definition at line 60 of file TcpSocket.h.


Member Typedef Documentation

typedef std::list<OUTPUT *> TcpSocket::output_l [protected]

Definition at line 119 of file TcpSocket.h.


Constructor & Destructor Documentation

TcpSocket::TcpSocket ( ISocketHandler h  ) 

Constructor with standard values on input/output buffers.

Definition at line 80 of file TcpSocket.cpp.

00080                                       : StreamSocket(h)
00081 ,ibuf(TCP_BUFSIZE_READ)
00082 ,m_b_input_buffer_disabled(false)
00083 ,m_bytes_sent(0)
00084 ,m_bytes_received(0)
00085 ,m_skip_c(false)
00086 #ifdef SOCKETS_DYNAMIC_TEMP
00087 ,m_buf(new char[TCP_BUFSIZE_READ + 1])
00088 #endif
00089 ,m_obuf_top(NULL)
00090 ,m_transfer_limit(0)
00091 ,m_output_length(0)
00092 #ifdef HAVE_OPENSSL
00093 ,m_ssl_ctx(NULL)
00094 ,m_ssl(NULL)
00095 ,m_sbio(NULL)
00096 #endif
00097 #ifdef ENABLE_SOCKS4
00098 ,m_socks4_state(0)
00099 #endif
00100 #ifdef ENABLE_RESOLVER
00101 ,m_resolver_id(0)
00102 #endif
00103 #ifdef ENABLE_RECONNECT
00104 ,m_b_reconnect(false)
00105 ,m_b_is_reconnect(false)
00106 #endif
00107 {
00108 }

TcpSocket::TcpSocket ( ISocketHandler h,
size_t  isize,
size_t  osize 
)

Constructor with custom values for i/o buffer.

Parameters:
h ISocketHandler reference
isize Input buffer size
osize Output buffer size

Definition at line 117 of file TcpSocket.cpp.

00117                                                                 : StreamSocket(h)
00118 ,ibuf(isize)
00119 ,m_b_input_buffer_disabled(false)
00120 ,m_bytes_sent(0)
00121 ,m_bytes_received(0)
00122 ,m_skip_c(false)
00123 #ifdef SOCKETS_DYNAMIC_TEMP
00124 ,m_buf(new char[TCP_BUFSIZE_READ + 1])
00125 #endif
00126 ,m_obuf_top(NULL)
00127 ,m_transfer_limit(0)
00128 ,m_output_length(0)
00129 #ifdef HAVE_OPENSSL
00130 ,m_ssl_ctx(NULL)
00131 ,m_ssl(NULL)
00132 ,m_sbio(NULL)
00133 #endif
00134 #ifdef ENABLE_SOCKS4
00135 ,m_socks4_state(0)
00136 #endif
00137 #ifdef ENABLE_RESOLVER
00138 ,m_resolver_id(0)
00139 #endif
00140 #ifdef ENABLE_RECONNECT
00141 ,m_b_reconnect(false)
00142 ,m_b_is_reconnect(false)
00143 #endif
00144 {
00145 }

TcpSocket::~TcpSocket (  ) 

Definition at line 151 of file TcpSocket.cpp.

References m_buf, m_obuf, and m_ssl.

00152 {
00153 #ifdef SOCKETS_DYNAMIC_TEMP
00154         delete[] m_buf;
00155 #endif
00156         // %! empty m_obuf
00157         while (m_obuf.size())
00158         {
00159                 output_l::iterator it = m_obuf.begin();
00160                 OUTPUT *p = *it;
00161                 delete p;
00162                 m_obuf.erase(it);
00163         }
00164 #ifdef HAVE_OPENSSL
00165         if (m_ssl)
00166         {
00167                 SSL_free(m_ssl);
00168         }
00169 #endif
00170 }

TcpSocket::TcpSocket ( const TcpSocket s  )  [protected]

Definition at line 903 of file TcpSocket.cpp.

00904 :StreamSocket(s)
00905 ,ibuf(0)
00906 {
00907 }


Member Function Documentation

bool TcpSocket::Open ( ipaddr_t  ip,
port_t  port,
bool  skip_socks = false 
)

Open a connection to a remote server.

If you want your socket to connect to a server, always call Open before Add'ing a socket to the sockethandler. If not, the connection attempt will not be monitored by the socket handler...

Parameters:
ip IP address
port Port number
skip_socks Do not use socks4 even if configured

Definition at line 173 of file TcpSocket.cpp.

Referenced by HttpGetSocket::HttpGetSocket(), OnResolved(), Open(), HttpPutSocket::Open(), and HttpPostSocket::Open().

00174 {
00175         Ipv4Address ad(ip, port);
00176         Ipv4Address local;
00177         return Open(ad, local, skip_socks);
00178 }

bool TcpSocket::Open ( SocketAddress ad,
bool  skip_socks = false 
)

Definition at line 192 of file TcpSocket.cpp.

References Open().

00193 {
00194         Ipv4Address bind_ad("0.0.0.0", 0);
00195         return Open(ad, bind_ad, skip_socks);
00196 }

bool TcpSocket::Open ( SocketAddress ad,
SocketAddress bind_address,
bool  skip_socks = false 
)

Connecting();

Definition at line 199 of file TcpSocket.cpp.

References Socket::Attach(), closesocket, Socket::CopyConnection(), Socket::CreateSocket(), Errno, ISocketHandler::FindConnection(), SocketAddress::GetFamily(), SocketAddress::GetPort(), Socket::GetSocks4Host(), Socket::GetSocks4Port(), Socket::Handler(), INVALID_SOCKET, SocketAddress::IsValid(), Utility::l2ip(), Utility::l2string(), LOG_LEVEL_FATAL, LOG_LEVEL_INFO, ISocketHandler::LogError(), Open(), Reconnect(), StreamSocket::SetCallOnConnect(), Socket::SetClientRemoteAddress(), Socket::SetCloseAndDelete(), StreamSocket::SetConnecting(), Socket::SetIsClient(), Socket::SetNonblocking(), Socket::SetRemoteAddress(), Socket::SetSocks4(), Socket::Socks4(), and StrError.

00200 {
00201         if (!ad.IsValid())
00202         {
00203                 Handler().LogError(this, "Open", 0, "Invalid SocketAddress", LOG_LEVEL_FATAL);
00204                 SetCloseAndDelete();
00205                 return false;
00206         }
00207         if (Handler().GetCount() >= FD_SETSIZE)
00208         {
00209                 Handler().LogError(this, "Open", 0, "no space left in fd_set", LOG_LEVEL_FATAL);
00210                 SetCloseAndDelete();
00211                 return false;
00212         }
00213         SetConnecting(false);
00214 #ifdef ENABLE_SOCKS4
00215         SetSocks4(false);
00216 #endif
00217         // check for pooling
00218 #ifdef ENABLE_POOL
00219         if (Handler().PoolEnabled())
00220         {
00221                 ISocketHandler::PoolSocket *pools = Handler().FindConnection(SOCK_STREAM, "tcp", ad);
00222                 if (pools)
00223                 {
00224                         CopyConnection( pools );
00225                         delete pools;
00226 
00227                         SetIsClient();
00228                         SetCallOnConnect(); // ISocketHandler must call OnConnect
00229                         Handler().LogError(this, "SetCallOnConnect", 0, "Found pooled connection", LOG_LEVEL_INFO);
00230                         return true;
00231                 }
00232         }
00233 #endif
00234         // if not, create new connection
00235         SOCKET s = CreateSocket(ad.GetFamily(), SOCK_STREAM, "tcp");
00236         if (s == INVALID_SOCKET)
00237         {
00238                 return false;
00239         }
00240         // socket must be nonblocking for async connect
00241         if (!SetNonblocking(true, s))
00242         {
00243                 SetCloseAndDelete();
00244                 closesocket(s);
00245                 return false;
00246         }
00247 #ifdef ENABLE_POOL
00248         SetIsClient(); // client because we connect
00249 #endif
00250         SetClientRemoteAddress(ad);
00251         int n = 0;
00252         if (bind_ad.GetPort() != 0)
00253         {
00254                 bind(s, bind_ad, bind_ad);
00255         }
00256 #ifdef ENABLE_SOCKS4
00257         if (!skip_socks && GetSocks4Host() && GetSocks4Port())
00258         {
00259                 Ipv4Address sa(GetSocks4Host(), GetSocks4Port());
00260                 {
00261                         std::string sockshost;
00262                         Utility::l2ip(GetSocks4Host(), sockshost);
00263                         Handler().LogError(this, "Open", 0, "Connecting to socks4 server @ " + sockshost + ":" +
00264                                 Utility::l2string(GetSocks4Port()), LOG_LEVEL_INFO);
00265                 }
00266                 SetSocks4();
00267                 n = connect(s, sa, sa);
00268                 SetRemoteAddress(sa);
00269         }
00270         else
00271 #endif
00272         {
00273                 n = connect(s, ad, ad);
00274                 SetRemoteAddress(ad);
00275         }
00276         if (n == -1)
00277         {
00278                 // check error code that means a connect is in progress
00279 #ifdef _WIN32
00280                 if (Errno == WSAEWOULDBLOCK)
00281 #else
00282                 if (Errno == EINPROGRESS)
00283 #endif
00284                 {
00285                         Attach(s);
00286                         SetConnecting( true ); // this flag will control fd_set's
00287                 }
00288                 else
00289 #ifdef ENABLE_SOCKS4
00290                 if (Socks4() && Handler().Socks4TryDirect() ) // retry
00291                 {
00292                         closesocket(s);
00293                         return Open(ad, true);
00294                 }
00295                 else
00296 #endif
00297 #ifdef ENABLE_RECONNECT
00298                 if (Reconnect())
00299                 {
00300                         Handler().LogError(this, "connect: failed, reconnect pending", Errno, StrError(Errno), LOG_LEVEL_INFO);
00301                         Attach(s);
00302                         SetConnecting( true ); // this flag will control fd_set's
00303                 }
00304                 else
00305 #endif
00306                 {
00307                         Handler().LogError(this, "connect: failed", Errno, StrError(Errno), LOG_LEVEL_FATAL);
00308                         SetCloseAndDelete();
00309                         closesocket(s);
00310                         return false;
00311                 }
00312         }
00313         else
00314         {
00315                 Attach(s);
00316                 SetCallOnConnect(); // ISocketHandler must call OnConnect
00317         }
00318 
00319         // 'true' means connected or connecting(not yet connected)
00320         // 'false' means something failed
00321         return true; 
00322 }

bool TcpSocket::Open ( const std::string &  host,
port_t  port 
)

Open connection.

Parameters:
host Hostname
port Port number

Definition at line 325 of file TcpSocket.cpp.

References Socket::Handler(), Utility::isipv4(), Utility::isipv6(), m_resolver_id, Open(), Socket::Resolve(), Socket::SetCloseAndDelete(), and Utility::u2ip().

00326 {
00327 #ifdef ENABLE_IPV6
00328 #ifdef IPPROTO_IPV6
00329         if (IsIpv6())
00330         {
00331 #ifdef ENABLE_RESOLVER
00332                 if (!Handler().ResolverEnabled() || Utility::isipv6(host) )
00333                 {
00334 #endif
00335                         in6_addr a;
00336                         if (!Utility::u2ip(host, a))
00337                         {
00338                                 SetCloseAndDelete();
00339                                 return false;
00340                         }
00341                         Ipv6Address ad(a, port);
00342                         Ipv6Address local;
00343                         return Open(ad, local);
00344 #ifdef ENABLE_RESOLVER
00345                 }
00346                 m_resolver_id = Resolve6(host, port);
00347                 return true;
00348 #endif
00349         }
00350 #endif
00351 #endif
00352 #ifdef ENABLE_RESOLVER
00353         if (!Handler().ResolverEnabled() || Utility::isipv4(host) )
00354         {
00355 #endif
00356                 ipaddr_t l;
00357                 if (!Utility::u2ip(host,l))
00358                 {
00359                         SetCloseAndDelete();
00360                         return false;
00361                 }
00362                 Ipv4Address ad(l, port);
00363                 Ipv4Address local;
00364                 return Open(ad, local);
00365 #ifdef ENABLE_RESOLVER
00366         }
00367         // resolve using async resolver thread
00368         m_resolver_id = Resolve(host, port);
00369         return true;
00370 #endif
00371 }

void TcpSocket::OnConnectTimeout (  )  [virtual]

Connect timeout callback.

Todo:
state reason why connect failed

Todo:
state reason why connect failed

Reimplemented from Socket.

Definition at line 1645 of file TcpSocket.cpp.

References StreamSocket::GetConnectionRetries(), StreamSocket::GetConnectionRetry(), Socket::Handler(), StreamSocket::IncreaseConnectionRetries(), LOG_LEVEL_FATAL, ISocketHandler::LogError(), Socket::OnConnectFailed(), Socket::OnConnectRetry(), OnSocks4ConnectFailed(), Socket::SetCloseAndDelete(), StreamSocket::SetConnecting(), StreamSocket::SetRetryClientConnect(), and Socket::Socks4().

01646 {
01647         Handler().LogError(this, "connect", -1, "connect timeout", LOG_LEVEL_FATAL);
01648 #ifdef ENABLE_SOCKS4
01649         if (Socks4())
01650         {
01651                 OnSocks4ConnectFailed();
01652                 // retry direct connection
01653         }
01654         else
01655 #endif
01656         if (GetConnectionRetry() == -1 ||
01657                 (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
01658         {
01659                 IncreaseConnectionRetries();
01660                 // ask socket via OnConnectRetry callback if we should continue trying
01661                 if (OnConnectRetry())
01662                 {
01663                         SetRetryClientConnect();
01664                 }
01665                 else
01666                 {
01667                         SetCloseAndDelete( true );
01669                         OnConnectFailed();
01670                 }
01671         }
01672         else
01673         {
01674                 SetCloseAndDelete(true);
01676                 OnConnectFailed();
01677         }
01678         //
01679         SetConnecting(false);
01680 }

int TcpSocket::Close (  )  [virtual]

Close file descriptor - internal use only.

See also:
SetCloseAndDelete

Reimplemented from Socket.

Definition at line 1337 of file TcpSocket.cpp.

References Socket::Close(), Errno, StreamSocket::GetShutdown(), Socket::GetSocket(), Socket::Handler(), INVALID_SOCKET, Socket::IsConnected(), Socket::IsSSL(), LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, ISocketHandler::LogError(), Socket::Lost(), m_ssl, Socket::SetNonblocking(), and StrError.

01338 {
01339         if (GetSocket() == INVALID_SOCKET) // this could happen
01340         {
01341                 Handler().LogError(this, "Socket::Close", 0, "file descriptor invalid", LOG_LEVEL_WARNING);
01342                 return 0;
01343         }
01344         int n;
01345         SetNonblocking(true);
01346         if (!Lost() && IsConnected() && !(GetShutdown() & SHUT_WR))
01347         {
01348                 if (shutdown(GetSocket(), SHUT_WR) == -1)
01349                 {
01350                         // failed...
01351                         Handler().LogError(this, "shutdown", Errno, StrError(Errno), LOG_LEVEL_ERROR);
01352                 }
01353         }
01354         //
01355         char tmp[1000];
01356         if (!Lost() && (n = recv(GetSocket(),tmp,1000,0)) >= 0)
01357         {
01358                 if (n)
01359                 {
01360                         Handler().LogError(this, "read() after shutdown", n, "bytes read", LOG_LEVEL_WARNING);
01361                 }
01362         }
01363 #ifdef HAVE_OPENSSL
01364         if (IsSSL() && m_ssl)
01365                 SSL_shutdown(m_ssl);
01366         if (m_ssl)
01367         {
01368                 SSL_free(m_ssl);
01369                 m_ssl = NULL;
01370         }
01371 #endif
01372         return Socket::Close();
01373 }

void TcpSocket::Send ( const std::string &  s,
int  f = 0 
) [virtual]

void TcpSocket::Sendf ( const char *  format,
  ... 
)

Send string using printf formatting.

Definition at line 1024 of file TcpSocket.cpp.

References Send().

Referenced by HttpDebugSocket::OnFirst().

01025 {
01026         va_list ap;
01027         va_start(ap, format);
01028         char slask[5000]; // vsprintf / vsnprintf temporary
01029 #ifdef _WIN32
01030         vsprintf(slask, format, ap);
01031 #else
01032         vsnprintf(slask, 5000, format, ap);
01033 #endif
01034         va_end(ap);
01035         Send( slask );
01036 }

void TcpSocket::SendBuf ( const char *  buf,
size_t  len,
int  f = 0 
) [virtual]

Send buffer of bytes.

Parameters:
buf Buffer pointer
len Length of data
f Dummy flags -- not used

Reimplemented from Socket.

Definition at line 844 of file TcpSocket.cpp.

References Buffer(), Socket::CloseAndDelete(), StreamSocket::Connecting(), ISocketHandler::Get(), Socket::GetSocket(), Socket::Handler(), INVALID_SOCKET, Socket::IsConnected(), LOG_LEVEL_INFO, ISocketHandler::LogError(), m_obuf, m_obuf_top, StreamSocket::Ready(), Socket::Set(), and TryWrite().

Referenced by HttpPostSocket::DoMultipartPost(), HttpPutSocket::OnConnect(), HttpDebugSocket::OnData(), OnSocks4Connect(), HttpBaseSocket::OnTransferLimit(), Ajp13Socket::OnTransferLimit(), Ajp13Socket::ReceiveBody(), Ajp13Socket::Respond(), Send(), and HttpdSocket::Send64().

00845 {
00846         if (!Ready() && !Connecting())
00847         {
00848                 Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-ready socket" ); // warning
00849                 if (GetSocket() == INVALID_SOCKET)
00850                         Handler().LogError(this, "SendBuf", 0, " * GetSocket() == INVALID_SOCKET", LOG_LEVEL_INFO);
00851                 if (Connecting())
00852                         Handler().LogError(this, "SendBuf", 0, " * Connecting()", LOG_LEVEL_INFO);
00853                 if (CloseAndDelete())
00854                         Handler().LogError(this, "SendBuf", 0, " * CloseAndDelete()", LOG_LEVEL_INFO);
00855                 return;
00856         }
00857         if (!IsConnected())
00858         {
00859                 Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-connected socket, will be sent on connect" ); // warning
00860                 Buffer(buf, len);
00861                 return;
00862         }
00863         if (m_obuf_top)
00864         {
00865                 Buffer(buf, len);
00866                 return;
00867         }
00868         int n = TryWrite(buf, len);
00869         if (n >= 0 && n < (int)len)
00870         {
00871                 Buffer(buf + n, len - n);
00872         }
00873         // if ( data in buffer || !IsConnected )
00874         // {
00875         //   add to buffer
00876         // }
00877         // else