simple-socket library 1.2.0
SCTPSocket.cpp
Go to the documentation of this file.
1#include "SCTPSocket.h"
2#include "TempFailure.h"
3
4#include <vector>
5#include <netinet/in.h>
6#include <poll.h>
7
8using namespace NET;
9
10SCTPSocket::SCTPSocket( uint16_t numOutStreams /* = 10 */,
11 uint16_t maxInStreams /* = 65535 */,
12 uint16_t maxAttempts /* = 4 */,
13 uint16_t maxInitTimeout /* = 0 */)
14: InternetSocket( STREAM, IPPROTO_SCTP)
15{
16 setInitValues( numOutStreams, maxInStreams, maxAttempts, maxInitTimeout);
17}
18
20: InternetSocket( handle.release() )
21{}
22
23int SCTPSocket::bind( const std::vector<std::string>& localAddresses, unsigned short localPort /* = 0 */)
24{
25 size_t size = localAddresses.size();
26 std::vector<sockaddr_in> dest(size);
27
28 for( size_t i = 0; i < size; ++i)
29 fillAddress( localAddresses[i], localPort, dest[i]);
30
31 int ret = sctp_bindx( m_socket, reinterpret_cast<sockaddr*>(dest.data()), static_cast<int>(size), SCTP_BINDX_ADD_ADDR);
32 if(ret < 0)
33 throw SocketException("Set of local address and port failed (sctp_bindx)");
34 return ret;
35}
36
37int SCTPSocket::connect( const std::vector<std::string>& foreignAddresses, unsigned short foreignPort /* = 0 */)
38{
39 size_t size = foreignAddresses.size();
40 std::vector<sockaddr_in> dest(size);
41
42 for( size_t i = 0; i < size; ++i)
43 fillAddress( foreignAddresses[i], foreignPort, dest[i]);
44
45 // TODO maybe save connection id for later use
46 int ret = sctp_connectx( m_socket, reinterpret_cast<sockaddr*>(dest.data()), static_cast<int>(size), 0);
47 if(ret < 0)
48 throw SocketException("Connect failed (sctp_connectx)");
49
50 m_peerDisconnected = false;
51 return ret;
52}
53
55{
56 struct sctp_status status;
57 socklen_t size = sizeof(status);
58 if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
59 throw SocketException("SCTPSocket::state failed (getsockopt)");
60 return status.sstat_state;
61}
62
64{
65 struct sctp_status status;
66 socklen_t size = sizeof(status);
67 if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
68 throw SocketException("SCTPSocket::notAckedData failed (getsockopt)");
69 return status.sstat_unackdata;
70}
71
73{
74 struct sctp_status status;
75 socklen_t size = sizeof(status);
76 if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
77 throw SocketException("SCTPSocket::pendingData failed (getsockopt)");
78 return status.sstat_penddata;
79}
80
81unsigned SCTPSocket::inStreams() const
82{
83 struct sctp_status status;
84 socklen_t size = sizeof(status);
85 if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
86 throw SocketException("SCTPSocket::inStreams failed (getsockopt)");
87 return status.sstat_instrms;
88}
89
90unsigned SCTPSocket::outStreams() const
91{
92 struct sctp_status status;
93 socklen_t size = sizeof(status);
94 if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
95 throw SocketException("SCTPSocket::outStreams failed (getsockopt)");
96 return status.sstat_outstrms;
97}
98
100{
101 struct sctp_status status;
102 socklen_t size = sizeof(status);
103 if( getsockopt( m_socket, IPPROTO_SCTP, SCTP_STATUS, &status, &size) < 0)
104 throw SocketException("SCTPSocket::fragmentationPoint failed (getsockopt)");
105 return status.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)
169 m_peerDisconnected = true;
170
171 if( poll.revents & POLLIN || poll.revents & POLLPRI)
172 return receive( data, maxLen, stream);
173
174 return 0;
175}
176
177int SCTPSocket::timedReceive( void* data, size_t maxLen, uint16_t& stream, receiveFlag& flag, int timeout)
178{
179 struct pollfd poll;
180 poll.fd = m_socket;
181 poll.events = POLLIN | POLLPRI | POLLRDHUP;
182
183 int ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
184
185 if( ret == 0) return 0;
186 if( ret < 0) throw SocketException("SCTPSocket::timedReceive failed (poll)");
187
188 if( poll.revents & POLLRDHUP)
189 m_peerDisconnected = true;
190
191 if( poll.revents & POLLIN || poll.revents & POLLPRI)
192 return receive( data, maxLen, stream, flag);
193
194 return 0;
195}
196
197void SCTPSocket::listen( int backlog /* = 5 */)
198{
199 int ret = ::listen( m_socket, backlog);
200 if( ret < 0)
201 throw SocketException("listen failed, most likely another socket is already listening on the same port");
202}
203
205{
206 int ret = ::accept( m_socket, 0, 0);
207 if( ret < 0)
208 throw SocketException("SCTPSocket::accept failed (accept)");
209 return Handle(ret);
210}
211
213{
214 struct pollfd poll;
215 poll.fd = m_socket;
216 poll.events = POLLIN;
217
218 int ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
219
220 if( ret == 0) return Handle();
221 if( ret < 0) throw SocketException("SCTPSocket::timedAccept failed (poll)");
222
223 ret = ::accept( m_socket, 0, 0);
224 if( ret < 0)
225 throw SocketException("SCTPSocket::timedAccept failed (accept)");
226 return Handle(ret);
227}
228
229void SCTPSocket::setInitValues( uint16_t numOutStreams, uint16_t maxInStreams, uint16_t maxAttempts, uint16_t maxInitTimeout)
230{
231 struct sctp_initmsg init;
232 init.sinit_num_ostreams = numOutStreams;
233 init.sinit_max_instreams = maxInStreams;
234 init.sinit_max_attempts = maxAttempts;
235 init.sinit_max_init_timeo = maxInitTimeout;
236
237 int ret = setsockopt( m_socket, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init));
238 if( ret < 0)
239 throw SocketException("SCTPSocket construction failed (setsockopt)");
240}
#define TEMP_FAILURE_RETRY(expression)
Definition TempFailure.h:8
Definition CANFrame.h:7
InternetSocket(int sockfd)
create socket from a SocketHandle returned by an accept() call
static void fillAddress(std::string_view address, unsigned short port, sockaddr_in &addr)
unsigned outStreams() const
int notAckedData() const
int sendUnordered(const void *data, size_t length, uint16_t stream, unsigned ttl=0, unsigned context=0, unsigned ppid=0, abortFlag abort=KEEPALIVE, switchAddressFlag switchAddr=KEEP_PRIMARY)
SCTPSocket(uint16_t numOutStreams=10, uint16_t maxInStreams=65535, uint16_t maxAttempts=4, uint16_t maxInitTimeout=0)
unsigned fragmentationPoint() const
void setInitValues(uint16_t ostr, uint16_t istr, uint16_t att, uint16_t time)
Handle accept() const
int connect(const std::vector< std::string > &foreignAddresses, unsigned short foreignPort=0)
int state() const
unsigned inStreams() const
Handle timedAccept(int timeout) const
int pendingData() const
SocketHandle< SCTPSocket > Handle
Handle for a new socket returned by accept.
Definition SCTPSocket.h:20
int receive(void *data, size_t maxLen, uint16_t &stream)
void listen(int backlog=5)
int send(const void *data, size_t length, uint16_t stream, unsigned ttl=0, unsigned context=0, unsigned ppid=0, abortFlag abort=KEEPALIVE, switchAddressFlag switchAddr=KEEP_PRIMARY)
int timedReceive(void *data, size_t maxLen, uint16_t &stream, int timeout)
int bind(const std::vector< std::string > &localAddresses, unsigned short localPort=0)
std::string primaryAddress() const
Signals a problem with the execution of a socket call.