1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
|
// $Id: README.OpenSS7 80826 2008-03-04 14:51:23Z wotte $
This document describes the OpenSS7 API in detail.
Introduction
=============
OpenSS7 defines two types of services, UDP style and TCP style. How OpenSS7
distinguishes the two styles is by the way in which the data is presented to
the application. In OpenSS7, data is presented as byte streams or datagrams.
The stream style is considered the TCP style socket, and the datagram is
considered the UDP style socket. The UDP style socket does not represent a one
to many mapping of file descriptors to associations as the IETF compatible
sockets does.
Instead of adding new system calls, OpenSS7 decided to modify some of the
existing system calls to play nicely with multi-homing. So, to bind to
multiple addresses, you pass in an array of struct sockaddr* structures and the
total length in bytes of the array. Also, when accepting connections from a
peer, you would pass in a pointer to an array of struct sockaddr* and the
length of the array in bytes.
Building ACE/TAO with support for OpenSS7 SCTP
==============================================
- apply OpenSS7's SCTP patch (see OpenSS7's readme for details)
- compile kernel with the following kernel variables (.config file)
+ CONFIG_SCTP=y
+ CONFIG_SCTP_TCP_COMPATIBLE=y
+ CONFIG_SCTP_HMAC_SHA1=y
+ CONFIG_SCTP_HMAC_MD5=y
+ CONFIG_SCTP_ADLER_32=y
+ CONFIG_SCTP_CRC_32C=y
- install header file (sctp.h) into /usr/local/include/sctp.h
- make ACE/TAO with "sctp=openss7" -- ie. "make sctp=openss7"
Common Calls
============
There are a few common calls which have the same semantics no matter which
interface you are using (UDP style or TCP style). So, the usual calls used in
a client are:
1) socket()
2) bind()
3) setsockopt()
4) connect()
5) send/recv()
6) close()
while the usual calls for a server are as follows:
1) socket()
2) bind()
3) setsockopt()
4) listen()
5) accept()
6) close()
The previous example mimics the way in which the TCP protocol is used.
There are some exceptions to the above sequence which we will get into a little
later. So, let's talk about the system calls above.
Socket()
--------
The socket() call creates a file descriptor for the application to use to
communicate with the SCTP stack. The signature of socket() is as follows:
int socket(int network, int service, int proto)
Where:
network - AF_INET or AF_INET6 (AF_INET6 is not currently supported)
service - SOCK_SEQPACKET which gives us the UDP style interface
SOCK_STREAM which gives us the TCP style interface
proto - IPPROTO_SCTP which is the SCTP protocol number(132)
Bind()
------
The bind() call is used to attach the socket descriptor to the given array of
addresses. bind() may only be called once. The address structures sent in as
arguments to bind must have the same port number. That is, you may have
multiple addresses, but only 1 port number. The signature of bind() is as
follows:
int bind(int fd, struct sockaddr* addrs, socklen_t addrs_len)
Where:
fd - A SCTP socket descriptor
addrs - An array of struct sockaddr* which have the same port number
addrs_len - The total length in bytes of the addrs array
If an address structure is sent in with the address of INADDR_ANY, then SCTP
will bind to all the addresses on the host and either pick an ephemeral port or
use the one specified in the address structure.
Setsockopt()
------------
The setsockopt() call is used to adjust many different parameters to the SCTP
protocol. Please see the sctp(7) man page for more details.
Connect()
---------
The connect() call can be used to initialize a connection with a peer SCTP
machine. A connection can be initialized in 2 ways. The first is this
call(connect()). The second way is to allow implicit initialization when the
application calls sendmsg or sendto with the address of the remote host
specified. To allow data to be piggybacked with the COOKIE_ECHO chunk, you
must use the second initialization technique. The signature of connect is as
follows:
int connect(int fd, struct sockaddr* r_addr, socklen_t r_addr_len)
Where:
fd - An SCTP socket descriptor
r_addr - A single address structure with the address of the remote host
r_addr_len - Length in bytes of the the address structure
Note that only one address is sent into the connect call. The SCTP protocol
will negotiate the valid IP addresses to use with multi-homing.
Listen()
--------
The listen() call prepares the SCTP socket to accept new associations. The
signature is as follows:
int listen(int fd, int backlog)
Where:
fd - An SCTP socket descriptor
backlog - The maximum number of unaccepted connections
Accept()
--------
The accept() call allows the application to explicitly accept an incoming
association initialization attempt. accept() returns a new file descriptor
which can be used to send data to the client. accept() has a slightly
different semantic which allows it to take an array of address structures.
This gives the application the chance to get a specified number of addresses
from the peer on initialization. The signature of accept() is as follows:
int accept(int fd, struct sockaddr* r_addr, socklen_t *r_addr_len)
Where:
fd - A SCTP socket descriptor
r_addr - An array of address structures which will be filled with the
addresses of the remote host
r_addr_len - The length of the array of address structures passed in.
accept() will only put as many addresses in the address array as is specified
by the r_addr_len argument.
Close()
-------
Start the association shutdown sequence. The signature is as follows:
int close(int fd)
Where:
fd - A SCTP socket descriptor
Data Interfaces
===============
This section describes the sending and receiving of data on an SCTP socket.
This is where the differences between the TCP style and UDP style sockets
shows. SCTP uses the standard pairs of calls:
1) send()/recv()
2) sendmsg()/recvmsg()
3) sendto()/readfrom()
4) write()/read()
5) writev()/readv()
When the SCTP socket is opened as a UDP style socket, data is presented to the
application as datagrams. This means that calls to the receive class of system
calls returns only datagrams. For example, assume a sender sends 2 100 byte
datagrams. Now assume that the receiver calls one of the receive routines with
a max buffer size of 120 bytes. Assuming no errors are encountered, only 100
bytes are returned to the receiver (only 1 datagram), leaving the last 20 bytes
empty in the receivers buffer. When the last of a datagram is read, the
MSG_EOR flag is returned, and if the datagram is too big to fit into the
specified buffer, the MSG_TRUNC flag is returned.
With TCP styles sockets, the data is presented to the application as a stream
of bytes (like TCP). For example, assume the sender sends 2 100 byte
datagrams. Now assume that the receiver calls one of the receive routines with
a max buffer size of 120. Assuming no errors are encountered, 120 bytes are
returned (100 from the first datagram and 20 from the next datagram), leaving
80 bytes in the second datagram. MSG_EOR and MSG_TRUNC are never returned.
Send()/Recv()
-------------
The send/recv interface is one of the easiest ways of sending data back and
forth between peers. When send/recv is called, data is sent/read from the
default stream. The signature of send/recv is as follows:
int send(int fd, void *data, size_t d_len, int flags)
Where:
fd - A SCTP socket descriptor
data - Data to be sent to the peer
d_len - The length of the data in bytes
flags - Possible flags to be sent to be passed to the SCTP stack
(see send(3))
Sendmsg()/Recvmsg()
-------------------
The sendmsg/recvmsg interface is the most powerful and hard to use interface
in the SCTP stack. This interface allows the specification of which stream to
send data out or receive data from. It also allows the sending of data with a
specified protocol payload identifier. The signature is as follows:
int sendmsg(int fd, struct msghdr *msg, int flags)
Where:
fd - A SCTP socket descriptor
msg - A struct msghdr structure which holds miscellaneous information
flags - Possible flags to be passed to the SCTP stack
(see sendmsg(3))
The msg argument holds the data to be sent to the peer. It also can take an
address to send the data to. So, for example, if you had an association with 2
addresses for the peer and the default path used the first address, and you
wanted to send data to the other address, you could specify that address in the
msg structure. If this address field is NULL, then data is sent out the
default address.
This interface also allows other functions by using the ancillary data field
in the msg structure. By using the ancillary data field, you may send data out
a different stream by using the SCTP_SID control message. This type of control
message would take an integer representing the stream to send data out as it's
data. Another option is to use the SCTP_PPI control message which allows the
setting of the protocol payload identifier to the specified integer argument.
Both of these options only set their values for the current data being sent out.
Sendto()/Recvfrom()
-------------------
The sendto/recvfrom interface allows the specification of which remote address
to send data. The signature of sendto/recvfrom is as follows:
int sendto(int fd, void *data, size_t d_len, int flags,
struct sockaddr* r_addr, socklen_t r_addr_len)
Where:
fd - A SCTP socket descriptor
data - Data to send to peer
d_len - Length of the data to be sent
flags - Possible flags to be passed to the SCTP stack
r_addr - Address of peer to send data to
r_addr_len - Length of peer address
Write()/Read()
--------------
This interface is the simplest way of sending data to a peer. When this
interface is used, data is sent/received through the default stream (as set by
SCTP_SID). The signature is as follows:
int write(int fd, void *data, size_t d_len)
Where:
fd - A SCTP socket descriptor
data - Data to be sent to peer
d_len - Length of data
Writev()/Readv()
----------------
This interface allows the sending of multiple buffers of data in one system
call. This call places all the buffers into one SCTP data chunk. The signature is as follows:
int writev(int fd, struct iovec *iov, int ct)
Where:
fd - A SCTP socket descriptor
iov - An array of iovec structures. The order they are in the array is the
order they are placed in the data chunk
ct - The number of iovec structures to send
--
|