1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2006 Nokia Corporation.
5  *
6  * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24 
25 /**@CFILE tport_type_sctp.c Transport using SCTP.
26  *
27  * See tport.docs for more detailed description of tport interface.
28  *
29  * @RFC4168.
30  *
31  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
32  * @author Martti Mela <Martti.Mela@nokia.com>
33  *
34  * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
35  * @date Original Created: Thu Jul 20 12:54:32 2000 ppessi
36  */
37 
38 #include "config.h"
39 
40 #if HAVE_SCTP
41 
42 #include "tport_internal.h"
43 
44 #if HAVE_NETINET_SCTP_H
45 #include <netinet/sctp.h>
46 #endif
47 
48 #include <stdlib.h>
49 #include <time.h>
50 #include <assert.h>
51 #include <errno.h>
52 #include <limits.h>
53 #include <string.h>
54 
55 /* ---------------------------------------------------------------------- */
56 /* SCTP */
57 
58 #undef MAX_STREAMS
59 #define MAX_STREAMS MAX_STREAMS
60 
61 /* Missing socket symbols */
62 #ifndef SOL_SCTP
63 #define SOL_SCTP IPPROTO_SCTP
64 #endif
65 
66 enum { MAX_STREAMS = 1 };
67 typedef struct tport_sctp_t
68 {
69   tport_t sctp_base[1];
70 
71   msg_t *sctp_recv[MAX_STREAMS];
72   struct sctp_send {
73     msg_t *ss_msg;
74     msg_iovec_t *ss_unsent;	/**< Pointer to first unsent iovec */
75     unsigned     ss_unsentlen;  /**< Number of unsent iovecs */
76     msg_iovec_t *ss_iov;	/**< Iovecs allocated for sending */
77     unsigned     ss_iovlen;	/**< Number of allocated iovecs */
78   } sctp_send[MAX_STREAMS];
79 } tport_sctp_t;
80 
81 #define TP_SCTP_MSG_MAX (65536)
82 
83 static int tport_sctp_init_primary(tport_primary_t *,
84 				   tp_name_t tpn[1],
85 				   su_addrinfo_t *, tagi_t const *,
86 				   char const **return_culprit);
87 static int tport_sctp_init_client(tport_primary_t *,
88 				  tp_name_t tpn[1],
89 				  su_addrinfo_t *, tagi_t const *,
90 				  char const **return_culprit);
91 static int tport_sctp_init_secondary(tport_t *self, int socket, int accepted,
92 				     char const **return_reason);
93 static int tport_sctp_init_socket(tport_primary_t *pri,
94 				  int socket,
95 				  char const **return_reason);
96 static int tport_recv_sctp(tport_t *self);
97 static ssize_t tport_send_sctp(tport_t const *self, msg_t *msg,
98 			       msg_iovec_t iov[], size_t iovused);
99 
100 static int tport_sctp_next_timer(tport_t *self, su_time_t *, char const **);
101 static void tport_sctp_timer(tport_t *self, su_time_t);
102 
103 tport_vtable_t const tport_sctp_client_vtable =
104 {
105   /* vtp_name 		     */ "sctp",
106   /* vtp_public              */ tport_type_client,
107   /* vtp_pri_size            */ sizeof (tport_primary_t),
108   /* vtp_init_primary        */ tport_sctp_init_client,
109   /* vtp_deinit_primary      */ NULL,
110   /* vtp_wakeup_pri          */ tport_accept,
111   /* vtp_connect             */ NULL,
112   /* vtp_secondary_size      */ sizeof (tport_t),
113   /* vtp_init_secondary      */ tport_sctp_init_secondary,
114   /* vtp_deinit_secondary    */ NULL,
115   /* vtp_shutdown            */ NULL,
116   /* vtp_set_events          */ NULL,
117   /* vtp_wakeup              */ NULL,
118   /* vtp_recv                */ tport_recv_sctp,
119   /* vtp_send                */ tport_send_sctp,
120   /* vtp_deliver             */ NULL,
121   /* vtp_prepare             */ NULL,
122   /* vtp_keepalive           */ NULL,
123   /* vtp_stun_response       */ NULL,
124   /* vtp_next_secondary_timer*/ tport_sctp_next_timer,
125   /* vtp_secondary_timer     */ tport_sctp_timer,
126 };
127 
128 tport_vtable_t const tport_sctp_vtable =
129 {
130   /* vtp_name 		     */ "sctp",
131   /* vtp_public              */ tport_type_local,
132   /* vtp_pri_size            */ sizeof (tport_primary_t),
133   /* vtp_init_primary        */ tport_sctp_init_primary,
134   /* vtp_deinit_primary      */ NULL,
135   /* vtp_wakeup_pri          */ tport_accept,
136   /* vtp_connect             */ NULL,
137   /* vtp_secondary_size      */ sizeof (tport_t),
138   /* vtp_init_secondary      */ tport_sctp_init_secondary,
139   /* vtp_deinit_secondary    */ NULL,
140   /* vtp_shutdown            */ NULL,
141   /* vtp_set_events          */ NULL,
142   /* vtp_wakeup              */ NULL,
143   /* vtp_recv                */ tport_recv_sctp,
144   /* vtp_send                */ tport_send_sctp,
145   /* vtp_deliver             */ NULL,
146   /* vtp_prepare             */ NULL,
147   /* vtp_keepalive           */ NULL,
148   /* vtp_stun_response       */ NULL,
149   /* vtp_next_secondary_timer*/ tport_sctp_next_timer,
150   /* vtp_secondary_timer     */ tport_sctp_timer,
151 };
152 
tport_sctp_init_primary(tport_primary_t * pri,tp_name_t tpn[1],su_addrinfo_t * ai,tagi_t const * tags,char const ** return_culprit)153 static int tport_sctp_init_primary(tport_primary_t *pri,
154 				   tp_name_t tpn[1],
155 				   su_addrinfo_t *ai,
156 				   tagi_t const *tags,
157 				   char const **return_culprit)
158 {
159   int socket;
160 
161   if (pri->pri_params->tpp_mtu > TP_SCTP_MSG_MAX)
162     pri->pri_params->tpp_mtu = TP_SCTP_MSG_MAX;
163 
164   socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
165 
166   if (socket == INVALID_SOCKET)
167     return *return_culprit = "socket", -1;
168 
169   if (tport_sctp_init_socket(pri, socket, return_culprit) < 0)
170     return -1;
171 
172   return tport_stream_init_primary(pri, socket, tpn, ai, tags, return_culprit);
173 }
174 
tport_sctp_init_client(tport_primary_t * pri,tp_name_t tpn[1],su_addrinfo_t * ai,tagi_t const * tags,char const ** return_culprit)175 static int tport_sctp_init_client(tport_primary_t *pri,
176 				  tp_name_t tpn[1],
177 				  su_addrinfo_t *ai,
178 				  tagi_t const *tags,
179 				  char const **return_culprit)
180 {
181   if (pri->pri_params->tpp_mtu > TP_SCTP_MSG_MAX)
182     pri->pri_params->tpp_mtu = TP_SCTP_MSG_MAX;
183 
184   return tport_tcp_init_client(pri, tpn, ai, tags, return_culprit);
185 }
186 
tport_sctp_init_secondary(tport_t * self,int socket,int accepted,char const ** return_reason)187 static int tport_sctp_init_secondary(tport_t *self, int socket, int accepted,
188 				     char const **return_reason)
189 {
190   self->tp_has_connection = 1;
191 
192   if (accepted) {
193     /* Accepted socket inherit the init information from listen socket */
194     return 0;
195   }
196   else {
197     return tport_sctp_init_socket(self->tp_pri, socket, return_reason);
198   }
199 }
200 
201 /** Initialize a SCTP socket */
tport_sctp_init_socket(tport_primary_t * pri,int socket,char const ** return_reason)202 static int tport_sctp_init_socket(tport_primary_t *pri,
203 				  int socket,
204 				  char const **return_reason)
205 {
206   struct sctp_initmsg initmsg = { 0 };
207 
208   initmsg.sinit_num_ostreams = MAX_STREAMS;
209   initmsg.sinit_max_instreams = MAX_STREAMS;
210 
211   if (setsockopt(socket, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof initmsg) < 0)
212     return *return_reason = "SCTP_INITMSG", -1;
213 
214   return 0;
215 }
216 
217 /** Receive data available on the socket.
218  *
219  * @retval -1 error
220  * @retval 0  end-of-stream
221  * @retval 1  normal receive
222  * @retval 2  incomplete recv, recv again
223  */
224 static
tport_recv_sctp(tport_t * self)225 int tport_recv_sctp(tport_t *self)
226 {
227   msg_t *msg;
228   ssize_t N, veclen;
229   msg_iovec_t iovec[2] = {{ 0 }};
230 
231   char sctp_buf[TP_SCTP_MSG_MAX];
232 
233   iovec[0].mv_base = sctp_buf;
234   iovec[0].mv_len = sizeof(sctp_buf);
235 
236   N = su_vrecv(self->tp_socket, iovec, 1, 0, NULL, NULL);
237   if (N == SOCKET_ERROR) {
238     return su_is_blocking(su_errno()) ? 1 : -1;
239   }
240 
241   if (N == 0) {
242     if (self->tp_msg)
243       msg_recv_commit(self->tp_msg, 0, 1);
244     return 0;    /* End of stream */
245   }
246 
247   tport_recv_bytes(self, N, N);
248 
249   veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
250   if (veclen < 0)
251     return -1;
252 
253   assert(veclen == 1); assert(iovec[0].mv_len == N);
254   msg = self->tp_msg;
255 
256   msg_set_address(msg, self->tp_addr, self->tp_addrlen);
257 
258   memcpy(iovec[0].mv_base, sctp_buf, iovec[0].mv_len);
259 
260   if (self->tp_master->mr_dump_file)
261     tport_dump_iovec(self, msg, N, iovec, veclen, "recv", "from");
262 
263  if (self->tp_master->mr_capt_sock)
264      tport_capt_msg(self, msg, N, iovec, veclen, "recv");
265 
266   msg_recv_commit(msg, N, 0);  /* Mark buffer as used */
267 
268   return 2;
269 }
270 
tport_send_sctp(tport_t const * self,msg_t * msg,msg_iovec_t iov[],size_t iovused)271 static ssize_t tport_send_sctp(tport_t const *self, msg_t *msg,
272 			       msg_iovec_t iov[], size_t iovused)
273 {
274 
275 
276   return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, NULL, 0);
277 }
278 
279 /** Calculate tick timer if send is pending. */
tport_next_sctp_send_tick(tport_t * self,su_time_t * return_target,char const ** return_why)280 int tport_next_sctp_send_tick(tport_t *self,
281 			    su_time_t *return_target,
282 			    char const **return_why)
283 {
284   unsigned timeout = 100;  /* Retry 10 times a second... */
285 
286   if (tport_has_queued(self)) {
287     su_time_t ntime = su_time_add(self->tp_ktime, timeout);
288     if (su_time_cmp(ntime, *return_target) < 0)
289       *return_target = ntime, *return_why = "send tick";
290   }
291 
292   return 0;
293 }
294 
295 /** Tick timer if send is pending */
tport_sctp_send_tick_timer(tport_t * self,su_time_t now)296 void tport_sctp_send_tick_timer(tport_t *self, su_time_t now)
297 {
298   unsigned timeout = 100;
299 
300   /* Send timeout */
301   if (tport_has_queued(self) &&
302       su_time_cmp(su_time_add(self->tp_ktime, timeout), now) < 0) {
303     uint64_t bytes = self->tp_stats.sent_bytes;
304     su_time_t stime = self->tp_stime;
305 
306     tport_send_queue(self);
307 
308     if (self->tp_stats.sent_bytes == bytes)
309       self->tp_stime = stime;	/* Restore send timestamp */
310   }
311 }
312 
313 /** Calculate next timer for SCTP. */
tport_sctp_next_timer(tport_t * self,su_time_t * return_target,char const ** return_why)314 int tport_sctp_next_timer(tport_t *self,
315 			 su_time_t *return_target,
316 			 char const **return_why)
317 {
318   return
319     tport_next_recv_timeout(self, return_target, return_why) |
320     tport_next_sctp_send_tick(self, return_target, return_why);
321 }
322 
323 /** SCTP timer. */
tport_sctp_timer(tport_t * self,su_time_t now)324 void tport_sctp_timer(tport_t *self, su_time_t now)
325 {
326   tport_sctp_send_tick_timer(self, now);
327   tport_recv_timeout_timer(self, now);
328   tport_base_timer(self, now);
329 }
330 
331 #else
332 /* ISO c99 forbids empty source file */
333 void *sofia_tport_type_sctp_dummy;
334 #endif
335