simple-socket library 1.5.0
Loading...
Searching...
No Matches
SCTPSocket.cpp
1#include "SCTPSocket.h"
2#include "SockAddress.h"
3#include "TempFailure.h"
4
5#include <poll.h>
6
7using namespace NET;
8
9namespace {
10
11struct sctp_status getStatus( int socket)
12{
13 struct sctp_status status;
14 socklen_t size = sizeof(status);
15 if( ::getsockopt( socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
16 throw SocketException("SCTPSocket::getsockopt failed");
17 return status;
18}
19
20} // namespace
21
22SCTPSocket::SCTPSocket( uint16_t numOutStreams /* = 10 */,
23 uint16_t maxInStreams /* = 65535 */,
24 uint16_t maxAttempts /* = 4 */,
25 uint16_t maxInitTimeout /* = 0 */)
26: InternetSocket( IPv4, SOCK_STREAM, IPPROTO_SCTP)
27, m_family( IPv4)
28{
29 setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
30}
31
32SCTPSocket::SCTPSocket( Handle&& handle)
33: InternetSocket( handle.release() )
34, m_family( IPv4)
35{}
36
37int SCTPSocket::bind( const std::vector<std::string>& localAddresses, unsigned short localPort /* = 0 */)
38{
39 std::vector<sockaddr_in> dest;
40 dest.reserve(localAddresses.size());
41
42 for( const auto& address : localAddresses)
43 {
44 SockAddress addr( AddressFamily::IPv4, address, localPort);
45 sockaddr_in native{};
46 std::memcpy( &native, addr.data(), sizeof(native));
47 dest.push_back(native);
48 }
49
50 int ret = sctp_bindx( m_socket, reinterpret_cast<sockaddr*>(dest.data()), static_cast<int>(dest.size()), SCTP_BINDX_ADD_ADDR);
51 if(ret < 0)
52 throw SocketException("Set of local address and port failed (sctp_bindx)");
53 return ret;
54}
55
56int SCTPSocket::connect( const std::vector<std::string>& foreignAddresses, unsigned short foreignPort /* = 0 */)
57{
58 std::vector<sockaddr_in> dest;
59 dest.reserve(foreignAddresses.size());
60
61 for( const auto& address : foreignAddresses)
62 {
63 SockAddress addr( AddressFamily::IPv4, address, foreignPort);
64 sockaddr_in native{};
65 std::memcpy( &native, addr.data(), sizeof(native));
66 dest.push_back(native);
67 }
68
69 // TODO maybe save connection id for later use
70 int ret = sctp_connectx( m_socket, reinterpret_cast<sockaddr*>(dest.data()), static_cast<int>(dest.size()), 0);
71 if(ret < 0)
72 throw SocketException("Connect failed (sctp_connectx)");
73
74 m_peerDisconnected = false;
75 return ret;
76}
77
78int SCTPSocket::state() const
79{
80 return getStatus(m_socket).sstat_state;
81}
82
83int SCTPSocket::notAckedData() const
84{
85 return getStatus(m_socket).sstat_unackdata;
86}
87
88int SCTPSocket::pendingData() const
89{
90 return getStatus(m_socket).sstat_penddata;
91}
92
93unsigned SCTPSocket::inStreams() const
94{
95 return getStatus(m_socket).sstat_instrms;
96}
97
98unsigned SCTPSocket::outStreams() const
99{
100 return getStatus(m_socket).sstat_outstrms;
101}
102
103unsigned SCTPSocket::fragmentationPoint() const
104{
105 return getStatus(m_socket).sstat_fragmentation_point;
106}
107
108std::string SCTPSocket::primaryAddress() const
109{
110 return std::string(); // TODO
111}
112
113int SCTPSocket::send( const void* data, size_t length, uint16_t stream, unsigned ttl /* = 0 */, unsigned context /* = 0 */,
114 unsigned ppid /* = 0 */, abortFlag abort /* = KEEPALIVE */, switchAddressFlag switchAddr /* = KEEP_PRIMARY */)
115{
116 int ret = sctp_sendmsg( m_socket, data, length, nullptr, 0, ppid, abort + switchAddr, stream, ttl, context);
117 if( ret < 0)
118 throw SocketException("SCTPSocket::send failed (sctp_sendmsg)");
119 else if (static_cast<size_t>(ret) < length)
120 throw SocketException("SCTP sent a fragemented packet!");
121 return ret;
122}
123
124int SCTPSocket::sendUnordered( const void* data, size_t length, uint16_t stream, unsigned ttl /* = 0 */, unsigned context /* = 0 */,
125 unsigned ppid /* = 0 */, abortFlag abort /* = KEEPALIVE */,
126 switchAddressFlag switchAddr /* = KEEP_PRIMARY */)
127{
128 int ret = sctp_sendmsg( m_socket, data, length, nullptr, 0, ppid, abort + switchAddr + SCTP_UNORDERED, stream, ttl, context);
129 if( ret < 0)
130 throw SocketException("SCTPSocket::send failed (sctp_sendmsg)");
131 else if (static_cast<size_t>(ret) < length)
132 throw SocketException("SCTP sent a fragemented packet!");
133 return ret;
134}
135
136int SCTPSocket::receive( void* data, size_t maxLen, uint16_t& stream)
137{
138 struct sctp_sndrcvinfo info;
139 int ret;
140 if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) < 0)
141 throw SocketException("SCTPSocket::receive failed (sctp_recvmsg)");
142 stream = info.sinfo_stream;
143 return ret;
144}
145
146int SCTPSocket::receive( void* data, size_t maxLen, uint16_t& stream, receiveFlag& flag)
147{
148 struct sctp_sndrcvinfo info;
149 int ret;
150 if( (ret = sctp_recvmsg( m_socket, data, maxLen, 0, 0, &info, 0)) < 0)
151 throw SocketException("SCTPSocket::receive failed (sctp_recvmsg)");
152 stream = info.sinfo_stream;
153 flag = static_cast<receiveFlag>(info.sinfo_flags);
154 return ret;
155}
156
157int SCTPSocket::timedReceive( void* data, size_t maxLen, uint16_t& stream, int timeout)
158{
159 struct pollfd poll;
160 poll.fd = m_socket;
161 poll.events = POLLIN | POLLPRI | POLLRDHUP;
162
163 int ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
164
165 if( ret == 0) return 0;
166 if( ret < 0) throw SocketException("SCTPSocket::timedReceive failed (poll)");
167
168 if( poll.revents & POLLRDHUP || poll.revents & POLLHUP)
169 m_peerDisconnected = true;
170
171 if( poll.revents & POLLIN || poll.revents & POLLPRI)
172 return receive( data, maxLen, stream);
173
174 if( poll.revents & (POLLERR | POLLNVAL))
175 throw SocketException("SCTPSocket::timedReceive failed (poll)");
176
177 return 0;
178}
179
180int SCTPSocket::timedReceive( void* data, size_t maxLen, uint16_t& stream, receiveFlag& flag, int timeout)
181{
182 struct pollfd poll;
183 poll.fd = m_socket;
184 poll.events = POLLIN | POLLPRI | POLLRDHUP;
185
186 int ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
187
188 if( ret == 0) return 0;
189 if( ret < 0) throw SocketException("SCTPSocket::timedReceive failed (poll)");
190
191 if( poll.revents & POLLRDHUP || poll.revents & POLLHUP)
192 m_peerDisconnected = true;
193
194 if( poll.revents & POLLIN || poll.revents & POLLPRI)
195 return receive( data, maxLen, stream, flag);
196
197 if( poll.revents & (POLLERR | POLLNVAL))
198 throw SocketException("SCTPSocket::timedReceive failed (poll)");
199
200 return 0;
201}
202
204{
205 int ret = SimpleSocket::accept();
206 return Handle(ret);
207}
208
209SCTPSocket::Handle SCTPSocket::timedAccept( int timeout) const
210{
211 int ret = SimpleSocket::timedAccept(timeout);
212 return Handle(ret);
213}
214
215void SCTPSocket::setInitValues( uint16_t numOutStreams, uint16_t maxInStreams, uint16_t maxAttempts, uint16_t maxInitTimeout)
216{
217 struct sctp_initmsg init;
218 init.sinit_num_ostreams = numOutStreams;
219 init.sinit_max_instreams = maxInStreams;
220 init.sinit_max_attempts = maxAttempts;
221 init.sinit_max_init_timeo = maxInitTimeout;
222
223 if( ::setsockopt( m_socket, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init)) < 0)
224 throw SocketException("SCTPSocket construction failed (setsockopt)");
225}
Internet socket class.
InternetSocket(int sockfd)
create socket from a SocketHandle returned by an accept() call
SocketHandle< SCTPSocket > Handle
Handle for a new socket returned by accept().
Definition SCTPSocket.h:18
int accept() const
allows stream sockets to accept connections into Handles
int timedAccept(int timeout) const
allows stream sockets timed accept