simple-socket library 1.1.5

SCTPSocket.cpp

Go to the documentation of this file.
00001 #include "SCTPSocket.h"
00002 #include "TempFailure.h"
00003 
00004 #include <vector>
00005 #include <netinet/in.h>
00006 #include <poll.h>
00007 
00008 using namespace NET;
00009 
00010 SCTPSocket::SCTPSocket( unsigned numOutStreams /* = 10 */,
00011                         unsigned maxInStreams /* = 65535 */,
00012                         unsigned maxAttempts /* = 4 */,
00013                         unsigned maxInitTimeout /* = 0 */)
00014 : InternetSocket( STREAM, IPPROTO_SCTP)
00015 {
00016     setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
00017 }
00018 
00019 SCTPSocket::SCTPSocket( Handle handle)
00020 : InternetSocket( handle.release() )
00021 {}
00022 
00023 int SCTPSocket::bind( const std::vector<std::string>& localAddresses, unsigned short localPort /* = 0 */)
00024 {
00025     size_t size = localAddresses.size();
00026     std::vector<sockaddr_in> dest(size);
00027 
00028     for( size_t i = 0; i < size; ++i)
00029         fillAddress( localAddresses[i], localPort, dest[i]);
00030 
00031     int ret = sctp_bindx( m_socket, reinterpret_cast<sockaddr*>(dest.data()), size, SCTP_BINDX_ADD_ADDR);
00032     if(ret < 0)
00033         throw SocketException("Set of local address and port failed (sctp_bindx)");
00034     return ret;
00035 }
00036 
00037 int SCTPSocket::connect( const std::vector<std::string>& foreignAddresses, unsigned short foreignPort /* = 0 */)
00038 {
00039     size_t size = foreignAddresses.size();
00040     std::vector<sockaddr_in> dest(size);
00041 
00042     for( size_t i = 0; i < size; ++i)
00043         fillAddress( foreignAddresses[i], foreignPort, dest[i]);
00044 
00045     // TODO maybe save connection id for later use
00046     int ret = sctp_connectx( m_socket, reinterpret_cast<sockaddr*>(dest.data()), size, 0);
00047     if(ret < 0)
00048         throw SocketException("Connect failed (sctp_connectx)");
00049 
00050     m_peerDisconnected = false;
00051     return ret;
00052 }
00053 
00054 int SCTPSocket::state() const
00055 {
00056     struct sctp_status status;
00057     socklen_t size = sizeof(status);
00058     if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
00059         throw SocketException("SCTPSocket::state failed (getsockopt)");
00060     return status.sstat_state;
00061 }
00062 
00063 int SCTPSocket::notAckedData() const
00064 {
00065     struct sctp_status status;
00066     socklen_t size = sizeof(status);
00067     if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
00068         throw SocketException("SCTPSocket::notAckedData failed (getsockopt)");
00069     return status.sstat_unackdata;
00070 }
00071 
00072 int SCTPSocket::pendingData() const
00073 {
00074     struct sctp_status status;
00075     socklen_t size = sizeof(status);
00076     if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
00077         throw SocketException("SCTPSocket::pendingData failed (getsockopt)");
00078     return status.sstat_penddata;
00079 }
00080 
00081 unsigned SCTPSocket::inStreams() const
00082 {
00083     struct sctp_status status;
00084     socklen_t size = sizeof(status);
00085     if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
00086         throw SocketException("SCTPSocket::inStreams failed (getsockopt)");
00087     return status.sstat_instrms;
00088 }
00089 
00090 unsigned SCTPSocket::outStreams() const
00091 {
00092     struct sctp_status status;
00093     socklen_t size = sizeof(status);
00094     if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
00095         throw SocketException("SCTPSocket::outStreams failed (getsockopt)");
00096     return status.sstat_outstrms;
00097 }
00098 
00099 unsigned SCTPSocket::fragmentationPoint() const
00100 {
00101     struct sctp_status status;
00102     socklen_t size = sizeof(status);
00103     if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
00104         throw SocketException("SCTPSocket::fragmentationPoint failed (getsockopt)");
00105     return status.sstat_fragmentation_point;
00106 }
00107 
00108 std::string SCTPSocket::primaryAddress() const
00109 {
00110     return std::string(); // TODO
00111 }
00112 
00113 int SCTPSocket::send( const void* data, int length, unsigned stream, unsigned ttl /* = 0 */, unsigned context /* = 0 */,
00114                       unsigned ppid /* = 0 */, abortFlag abort /* = KEEPALIVE */, switchAddressFlag switchAddr /* = KEEP_PRIMARY */)
00115 {
00116     int ret = sctp_sendmsg( m_socket, data, length, NULL, 0, ppid, abort + switchAddr, stream, ttl, context);
00117     if( ret < 0)
00118         throw SocketException("SCTPSocket::send failed (sctp_sendmsg)");
00119     else if (ret < length)
00120         throw SocketException("SCTP sent a fragemented packet!");
00121     return ret;
00122 }
00123 
00124 int SCTPSocket::sendUnordered( const void* data, int length, unsigned stream, unsigned ttl /* = 0 */, unsigned context /* = 0 */,
00125                                unsigned ppid /* = 0 */, abortFlag abort /* = KEEPALIVE */,
00126                                switchAddressFlag switchAddr /* = KEEP_PRIMARY */)
00127 {
00128     int ret = sctp_sendmsg( m_socket, data, length, NULL, 0, ppid, abort + switchAddr + SCTP_UNORDERED, stream, ttl, context);
00129     if( ret < 0)
00130         throw SocketException("SCTPSocket::send failed (sctp_sendmsg)");
00131     else if (ret < length)
00132         throw SocketException("SCTP sent a fragemented packet!");
00133     return ret;
00134 }
00135 
00136 int SCTPSocket::receive( void* data, int maxLen, unsigned& stream)
00137 {
00138     struct sctp_sndrcvinfo info;
00139     int ret;
00140     if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) < 0)
00141         throw SocketException("SCTPSocket::receive failed (sctp_recvmsg)");
00142     stream = info.sinfo_stream;
00143     return ret;
00144 }
00145 
00146 int SCTPSocket::receive( void* data, int maxLen, unsigned& stream, receiveFlag& flag)
00147 {
00148     struct sctp_sndrcvinfo info;
00149     int ret;
00150     if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) < 0)
00151         throw SocketException("SCTPSocket::receive failed (sctp_recvmsg)");
00152     stream = info.sinfo_stream;
00153     flag = static_cast<receiveFlag>(info.sinfo_flags);
00154     return ret;
00155 }
00156 
00157 int SCTPSocket::timedReceive( void* data, int maxLen, unsigned& stream, unsigned timeout)
00158 {
00159     struct pollfd poll;
00160     poll.fd = m_socket;
00161     poll.events = POLLIN | POLLPRI | POLLRDHUP;
00162 
00163     int ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
00164 
00165     if( ret == 0) return 0;
00166     if( ret < 0) throw SocketException("SCTPSocket::timedReceive failed (poll)");
00167 
00168     if( poll.revents & POLLRDHUP)
00169         m_peerDisconnected = true;
00170 
00171     if( poll.revents & POLLIN || poll.revents & POLLPRI)
00172         return receive( data, maxLen, stream);
00173 
00174     return 0;
00175 }
00176 
00177 int SCTPSocket::timedReceive( void* data, int maxLen, unsigned& stream, receiveFlag& flag, unsigned timeout)
00178 {
00179     struct pollfd poll;
00180     poll.fd = m_socket;
00181     poll.events = POLLIN | POLLPRI | POLLRDHUP;
00182 
00183     int ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
00184 
00185     if( ret == 0) return 0;
00186     if( ret < 0) throw SocketException("SCTPSocket::timedReceive failed (poll)");
00187 
00188     if( poll.revents & POLLRDHUP)
00189         m_peerDisconnected = true;
00190 
00191     if( poll.revents & POLLIN || poll.revents & POLLPRI)
00192         return receive( data, maxLen, stream, flag);
00193 
00194     return 0;
00195 }
00196 
00197 void SCTPSocket::listen( int backlog /* = 5 */)
00198 {
00199     int ret = ::listen( m_socket, backlog);
00200     if( ret < 0)
00201         throw SocketException("listen failed, most likely another socket is already listening on the same port");
00202 }
00203 
00204 SCTPSocket::Handle SCTPSocket::accept() const
00205 {
00206     int ret = ::accept( m_socket, 0, 0);
00207     if( ret < 0)
00208         throw SocketException("SCTPSocket::accept failed (accept)");
00209     return Handle(ret);
00210 }
00211 
00212 SCTPSocket::Handle SCTPSocket::timedAccept( unsigned timeout) const
00213 {
00214     struct pollfd poll;
00215     poll.fd = m_socket;
00216     poll.events = POLLIN;
00217 
00218     int ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
00219 
00220     if( ret == 0) return Handle();
00221     if( ret < 0) throw SocketException("SCTPSocket::timedAccept failed (poll)");
00222 
00223     ret = ::accept( m_socket, 0, 0);
00224     if( ret < 0)
00225         throw SocketException("SCTPSocket::timedAccept failed (accept)");
00226     return Handle(ret);
00227 }
00228 
00229 void SCTPSocket::setInitValues( unsigned numOutStreams, unsigned maxInStreams, unsigned maxAttempts, unsigned maxInitTimeout)
00230 {
00231     struct sctp_initmsg init;
00232     init.sinit_num_ostreams = numOutStreams;
00233     init.sinit_max_instreams = maxInStreams;
00234     init.sinit_max_attempts = maxAttempts;
00235     init.sinit_max_init_timeo = maxInitTimeout;
00236 
00237     int ret = setsockopt( m_socket, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init));
00238     if( ret < 0)
00239         throw SocketException("SCTPSocket construction failed (setsockopt)");
00240 }