Logo
~Sockets~
~Examples~
~Contact~


SctpSocket.cpp

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2007  Anders Hedstrom
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 */
00023 #include "SctpSocket.h"
00024 #ifdef USE_SCTP
00025 #include "Utility.h"
00026 #include "ISocketHandler.h"
00027 #include <errno.h>
00028 #include "Ipv4Address.h"
00029 #include "Ipv6Address.h"
00030 
00031 
00032 #ifdef SOCKETS_NAMESPACE
00033 namespace SOCKETS_NAMESPACE
00034 {
00035 #endif
00036 
00037 
00038 SctpSocket::SctpSocket(ISocketHandler& h,int type) : StreamSocket(h)
00039 ,m_type(type)
00040 ,m_buf(new char[SCTP_BUFSIZE_READ])
00041 {
00042         if (type != SOCK_STREAM && type != SOCK_SEQPACKET)
00043         {
00044         }
00045 }
00046 
00047 
00048 SctpSocket::~SctpSocket()
00049 {
00050         delete[] m_buf;
00051 }
00052 
00053 
00054 int SctpSocket::Bind(const std::string& a,port_t p)
00055 {
00056 #ifdef ENABLE_IPV6
00057 #ifdef IPPROTO_IPV6
00058         if (IsIpv6())
00059         {
00060                 Ipv6Address ad(a, p);
00061                 return Bind(ad);
00062         }
00063 #endif
00064 #endif
00065         Ipv4Address ad(a, p);
00066         return Bind(ad);
00067 }
00068 
00069 
00070 int SctpSocket::Bind(SocketAddress& ad)
00071 {
00072         if (!ad.IsValid())
00073         {
00074                 Handler().LogError(this, "SctpSocket", -1, "invalid address", LOG_LEVEL_ERROR);
00075                 return -1;
00076         }
00077         if (GetSocket() == INVALID_SOCKET)
00078         {
00079                 Attach(CreateSocket(ad.GetFamily(), m_type, "sctp"));
00080         }
00081         if (GetSocket() != INVALID_SOCKET)
00082         {
00083                 int n = bind(GetSocket(), ad, ad);
00084                 if (n == -1)
00085                 {
00086                         Handler().LogError(this, "SctpSocket", -1, "bind() failed", LOG_LEVEL_ERROR);
00087                 }
00088                 return n;
00089         }
00090         return -1;
00091 }
00092 
00093 
00094 int SctpSocket::AddAddress(const std::string& a,port_t p)
00095 {
00096 #ifdef ENABLE_IPV6
00097 #ifdef IPPROTO_IPV6
00098         if (IsIpv6())
00099         {
00100                 Ipv6Address ad(a, p);
00101                 return AddAddress(ad);
00102         }
00103 #endif
00104 #endif
00105         Ipv4Address ad(a, p);
00106         return AddAddress(ad);
00107 }
00108 
00109 
00110 int SctpSocket::AddAddress(SocketAddress& ad)
00111 {
00112         if (!ad.IsValid())
00113         {
00114                 Handler().LogError(this, "SctpSocket", -1, "invalid address", LOG_LEVEL_ERROR);
00115                 return -1;
00116         }
00117         if (GetSocket() == INVALID_SOCKET)
00118         {
00119                 Handler().LogError(this, "SctpSocket", -1, "AddAddress called with invalid file descriptor", LOG_LEVEL_ERROR);
00120                 return -1;
00121         }
00122         int n = sctp_bindx(GetSocket(), ad, ad, SCTP_BINDX_ADD_ADDR);
00123         if (n == -1)
00124         {
00125                 Handler().LogError(this, "SctpSocket", -1, "sctp_bindx() failed", LOG_LEVEL_ERROR);
00126         }
00127         return n;
00128 }
00129 
00130 
00131 int SctpSocket::RemoveAddress(const std::string& a,port_t p)
00132 {
00133 #ifdef ENABLE_IPV6
00134 #ifdef IPPROTO_IPV6
00135         if (IsIpv6())
00136         {
00137                 Ipv6Address ad(a, p);
00138                 return RemoveAddress(ad);
00139         }
00140 #endif
00141 #endif
00142         Ipv4Address ad(a, p);
00143         return RemoveAddress(ad);
00144 }
00145 
00146 
00147 int SctpSocket::RemoveAddress(SocketAddress& ad)
00148 {
00149         if (!ad.IsValid())
00150         {
00151                 Handler().LogError(this, "SctpSocket", -1, "invalid address", LOG_LEVEL_ERROR);
00152                 return -1;
00153         }
00154         if (GetSocket() == INVALID_SOCKET)
00155         {
00156                 Handler().LogError(this, "SctpSocket", -1, "RemoveAddress called with invalid file descriptor", LOG_LEVEL_ERROR);
00157                 return -1;
00158         }
00159         int n = sctp_bindx(GetSocket(), ad, ad, SCTP_BINDX_REM_ADDR);
00160         if (n == -1)
00161         {
00162                 Handler().LogError(this, "SctpSocket", -1, "sctp_bindx() failed", LOG_LEVEL_ERROR);
00163         }
00164         return n;
00165 }
00166 
00167 
00168 int SctpSocket::Open(const std::string& a,port_t p)
00169 {
00170 #ifdef ENABLE_IPV6
00171 #ifdef IPPROTO_IPV6
00172         if (IsIpv6())
00173         {
00174                 Ipv6Address ad(a, p);
00175                 return Open(ad);
00176         }
00177 #endif
00178 #endif
00179         Ipv4Address ad(a, p);
00180         return Open(ad);
00181 }
00182 
00183 
00184 int SctpSocket::Open(SocketAddress& ad)
00185 {
00186         if (!ad.IsValid())
00187         {
00188                 Handler().LogError(this, "SctpSocket", -1, "invalid address", LOG_LEVEL_ERROR);
00189                 return -1;
00190         }
00191         if (GetSocket() == INVALID_SOCKET)
00192         {
00193                 Attach(CreateSocket(ad.GetFamily(), m_type, "sctp"));
00194         }
00195         if (GetSocket() != INVALID_SOCKET)
00196         {
00197                 if (!SetNonblocking(true))
00198                 {
00199                         return -1;
00200                 }
00201                 int n = connect(GetSocket(), ad, ad);
00202                 if (n == -1)
00203                 {
00204                         // check error code that means a connect is in progress
00205 #ifdef _WIN32
00206                         if (Errno == WSAEWOULDBLOCK)
00207 #else
00208                         if (Errno == EINPROGRESS)
00209 #endif
00210                         {
00211                                 Handler().LogError(this, "connect: connection pending", Errno, StrError(Errno), LOG_LEVEL_INFO);
00212                                 SetConnecting( true ); // this flag will control fd_set's
00213                         }
00214                         else
00215                         {
00216                                 Handler().LogError(this, "SctpSocket", -1, "connect() failed", LOG_LEVEL_ERROR);
00217                         }
00218                 }
00219                 return n;
00220         }
00221         return -1;
00222 }
00223 
00224 
00225 #ifndef SOLARIS
00226 int SctpSocket::AddConnection(const std::string& a,port_t p)
00227 {
00228 #ifdef ENABLE_IPV6
00229 #ifdef IPPROTO_IPV6
00230         if (IsIpv6())
00231         {
00232                 Ipv6Address ad(a, p);
00233                 return AddConnection(ad);
00234         }
00235 #endif
00236 #endif
00237         Ipv4Address ad(a, p);
00238         return AddConnection(ad);
00239 }
00240 
00241 
00242 int SctpSocket::AddConnection(SocketAddress& ad)
00243 {
00244         if (!ad.IsValid())
00245         {
00246                 Handler().LogError(this, "SctpSocket", -1, "invalid address", LOG_LEVEL_ERROR);
00247                 return -1;
00248         }
00249         if (GetSocket() == INVALID_SOCKET)
00250         {
00251                 Handler().LogError(this, "SctpSocket", -1, "AddConnection called with invalid file descriptor", LOG_LEVEL_ERROR);
00252                 return -1;
00253         }
00254         int n = sctp_connectx(GetSocket(), ad, ad);
00255         if (n == -1)
00256         {
00257                 Handler().LogError(this, "SctpSocket", -1, "sctp_connectx() failed", LOG_LEVEL_ERROR);
00258         }
00259         else
00260         {
00261                 SetConnecting();
00262         }
00263         return n;
00264 }
00265 #endif
00266 
00267 
00268 int SctpSocket::getpaddrs(sctp_assoc_t id,std::list<std::string>& vec)
00269 {
00270         struct sockaddr *p = NULL;
00271         int n = sctp_getpaddrs(GetSocket(), id, &p);
00272         if (!n || n == -1)
00273         {
00274                 Handler().LogError(this, "SctpSocket", -1, "sctp_getpaddrs failed", LOG_LEVEL_WARNING);
00275                 return n;
00276         }
00277         for (int i = 0; i < n; i++)
00278         {
00279                 vec.push_back(Utility::Sa2String(&p[i]));
00280         }
00281         sctp_freepaddrs(p);
00282         return n;
00283 }
00284 
00285 
00286 int SctpSocket::getladdrs(sctp_assoc_t id,std::list<std::string>& vec)
00287 {
00288         struct sockaddr *p = NULL;
00289         int n = sctp_getladdrs(GetSocket(), id, &p);
00290         if (!n || n == -1)
00291         {
00292                 Handler().LogError(this, "SctpSocket", -1, "sctp_getladdrs failed", LOG_LEVEL_WARNING);
00293                 return n;
00294         }
00295         for (int i = 0; i < n; i++)
00296         {
00297                 vec.push_back(Utility::Sa2String(&p[i]));
00298         }
00299         sctp_freeladdrs(p);
00300         return n;
00301 }
00302 
00303 
00304 int SctpSocket::PeelOff(sctp_assoc_t id)
00305 {
00306         int n = sctp_peeloff(GetSocket(), id);
00307         if (n == -1)
00308         {
00309                 Handler().LogError(this, "SctpSocket", -1, "PeelOff failed", LOG_LEVEL_WARNING);
00310                 return -1;
00311         }
00312         Socket *p = Create();
00313         p -> Attach(n);
00314         p -> SetDeleteByHandler();
00315         Handler().Add(p);
00316         return n;
00317 }
00318 
00319 
00320 void SctpSocket::OnRead()
00321 {
00322 /*
00323         int sctp_recvmsg(int sd, void * msg, size_t * len,
00324                 struct sockaddr * from, socklen_t * fromlen,
00325                 struct sctp_sndrcvinfo * sinfo, int * msg_flags);
00326 
00327         DESCRIPTION
00328         sctp_recvmsg  is  a  wrapper library function that can be used to receive a message from a socket while using the advanced
00329         features of SCTP.  sd is the socket descriptor on which the message pointed to by msg of length len is received.
00330 
00331         If from is not NULL, the source address of the message is filled in. The argument fromlen  is  a  value-result  parameter.
00332         initialized  to  the  size  of the buffer associated with from , and modified on return to indicate the actual size of the
00333         address stored.
00334 
00335         sinfo is a pointer to a sctp_sndrcvinfo structure to be filled upon receipt of the message.  msg_flags is a pointer  to  a
00336         integer that is filled with any message flags like MSG_NOTIFICATION or MSG_EOR.
00337 
00338 */
00339         struct sockaddr sa;
00340         socklen_t sa_len = 0;
00341         struct sctp_sndrcvinfo sinfo;
00342         int flags = 0;
00343         int n = sctp_recvmsg(GetSocket(), m_buf, SCTP_BUFSIZE_READ, &sa, &sa_len, &sinfo, &flags);
00344         if (n == -1)
00345         {
00346                 Handler().LogError(this, "SctpSocket", Errno, StrError(Errno), LOG_LEVEL_FATAL);
00347                 SetCloseAndDelete();
00348         }
00349         else
00350         {
00351                 OnReceiveMessage(m_buf, n, &sa, sa_len, &sinfo, flags);
00352         }
00353 }
00354 
00355 
00356 void SctpSocket::OnReceiveMessage(const char *buf,size_t sz,struct sockaddr *sa,socklen_t sa_len,struct sctp_sndrcvinfo *sinfo,int msg_flags)
00357 {
00358 }
00359 
00360 
00361 void SctpSocket::OnWrite()
00362 {
00363         if (Connecting())
00364         {
00365                 int err = SoError();
00366 
00367                 // don't reset connecting flag on error here, we want the OnConnectFailed timeout later on
00369                 if (!err) // ok
00370                 {
00371                         Set(!IsDisableRead(), false);
00372                         SetConnecting(false);
00373                         SetCallOnConnect();
00374                         return;
00375                 }
00376                 Handler().LogError(this, "sctp: connect failed", err, StrError(err), LOG_LEVEL_FATAL);
00377                 Set(false, false); // no more monitoring because connection failed
00378 
00379                 // failed
00380 #ifdef ENABLE_SOCKS4
00381                 if (Socks4())
00382                 {
00383                         OnSocks4ConnectFailed();
00384                         return;
00385                 }
00386 #endif
00387                 if (GetConnectionRetry() == -1 ||
00388                         (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
00389                 {
00390                         // even though the connection failed at once, only retry after
00391                         // the connection timeout.
00392                         // should we even try to connect again, when CheckConnect returns
00393                         // false it's because of a connection error - not a timeout...
00394                         return;
00395                 }
00396                 SetConnecting(false);
00397                 SetCloseAndDelete( true );
00399                 OnConnectFailed();
00400                 return;
00401         }
00402 }
00403 
00404 
00405 void SctpSocket::OnConnectTimeout()
00406 {
00407         Handler().LogError(this, "connect", -1, "connect timeout", LOG_LEVEL_FATAL);
00408 #ifdef ENABLE_SOCKS4
00409         if (Socks4())
00410         {
00411                 OnSocks4ConnectFailed();
00412                 // retry direct connection
00413         }
00414         else
00415 #endif
00416         if (GetConnectionRetry() == -1 ||
00417                 (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
00418         {
00419                 IncreaseConnectionRetries();
00420                 // ask socket via OnConnectRetry callback if we should continue trying
00421                 if (OnConnectRetry())
00422                 {
00423                         SetRetryClientConnect();
00424                 }
00425                 else
00426                 {
00427                         SetCloseAndDelete( true );
00429                         OnConnectFailed();
00430                 }
00431         }
00432         else
00433         {
00434                 SetCloseAndDelete(true);
00436                 OnConnectFailed();
00437         }
00438         //
00439         SetConnecting(false);
00440 }
00441 
00442 
00443 #ifdef _WIN32
00444 void SctpSocket::OnException()
00445 {
00446         if (Connecting())
00447         {
00448 #ifdef ENABLE_SOCKS4
00449                 if (Socks4())
00450                         OnSocks4ConnectFailed();
00451                 else
00452 #endif
00453                 if (GetConnectionRetry() == -1 ||
00454                         (GetConnectionRetry() &&
00455                          GetConnectionRetries() < GetConnectionRetry() ))
00456                 {
00457                         // even though the connection failed at once, only retry after
00458                         // the connection timeout
00459                         // should we even try to connect again, when CheckConnect returns
00460                         // false it's because of a connection error - not a timeout...
00461                 }
00462                 else
00463                 {
00464                         SetConnecting(false); // tnx snibbe
00465                         SetCloseAndDelete();
00466                         OnConnectFailed();
00467                 }
00468                 return;
00469         }
00470         // %! exception doesn't always mean something bad happened, this code should be reworked
00471         // errno valid here?
00472         int err = SoError();
00473         Handler().LogError(this, "exception on select", err, StrError(err), LOG_LEVEL_FATAL);
00474         SetCloseAndDelete();
00475 }
00476 #endif // _WIN32
00477 
00478 
00479 int SctpSocket::Protocol()
00480 {
00481         return IPPROTO_SCTP;
00482 }
00483 
00484 
00485 #ifdef SOCKETS_NAMESPACE
00486 } // namespace SOCKETS_NAMESPACE
00487 #endif
00488 
00489 
00490 #endif // USE_SCTP
Page, code, and content Copyright (C) 2007 by Anders Hedström
Generated for C++ Sockets by  doxygen 1.4.4