blob: c9e467a8fc0ed9559356b925bc89fd17b24e747d [file] [log] [blame]
James Kuszmaul4cb043c2021-01-17 11:25:51 -08001/*-
2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * a) Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * b) Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the distribution.
15 *
16 * c) Neither the name of Cisco Systems, Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#if defined(__Userspace__)
34#include <sys/types.h>
35#if !defined (__Userspace_os_Windows)
36#include <sys/wait.h>
37#include <unistd.h>
38#include <pthread.h>
39#endif
40#if defined(__Userspace_os_NaCl)
41#include <sys/select.h>
42#endif
43#include <stdlib.h>
44#include <string.h>
45#include <stdio.h>
46#include <errno.h>
47#include <netinet/sctp_sysctl.h>
48#include <netinet/sctp_pcb.h>
49#else
50#include <netinet/sctp_os.h>
51#include <netinet/sctp_callout.h>
52#include <netinet/sctp_pcb.h>
53#endif
54
55/*
56 * Callout/Timer routines for OS that doesn't have them
57 */
58#if defined(__APPLE__) || defined(__Userspace__)
59static int ticks = 0;
60#else
61extern int ticks;
62#endif
63
64int sctp_get_tick_count(void) {
65 int ret;
66
67 SCTP_TIMERQ_LOCK();
68 ret = ticks;
69 SCTP_TIMERQ_UNLOCK();
70 return ret;
71}
72
73/*
74 * SCTP_TIMERQ_LOCK protects:
75 * - SCTP_BASE_INFO(callqueue)
76 * - sctp_os_timer_next: next timer to check
77 */
78static sctp_os_timer_t *sctp_os_timer_next = NULL;
79
80void
81sctp_os_timer_init(sctp_os_timer_t *c)
82{
83 bzero(c, sizeof(*c));
84}
85
86void
87sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *),
88 void *arg)
89{
90 /* paranoia */
91 if ((c == NULL) || (ftn == NULL))
92 return;
93
94 SCTP_TIMERQ_LOCK();
95 /* check to see if we're rescheduling a timer */
96 if (c->c_flags & SCTP_CALLOUT_PENDING) {
97 if (c == sctp_os_timer_next) {
98 sctp_os_timer_next = TAILQ_NEXT(c, tqe);
99 }
100 TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
101 /*
102 * part of the normal "stop a pending callout" process
103 * is to clear the CALLOUT_ACTIVE and CALLOUT_PENDING
104 * flags. We don't bother since we are setting these
105 * below and we still hold the lock.
106 */
107 }
108
109 /*
110 * We could unlock/splx here and lock/spl at the TAILQ_INSERT_TAIL,
111 * but there's no point since doing this setup doesn't take much time.
112 */
113 if (to_ticks <= 0)
114 to_ticks = 1;
115
116 c->c_arg = arg;
117 c->c_flags = (SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING);
118 c->c_func = ftn;
119 c->c_time = ticks + to_ticks;
120 TAILQ_INSERT_TAIL(&SCTP_BASE_INFO(callqueue), c, tqe);
121 SCTP_TIMERQ_UNLOCK();
122}
123
124int
125sctp_os_timer_stop(sctp_os_timer_t *c)
126{
127 SCTP_TIMERQ_LOCK();
128 /*
129 * Don't attempt to delete a callout that's not on the queue.
130 */
131 if (!(c->c_flags & SCTP_CALLOUT_PENDING)) {
132 c->c_flags &= ~SCTP_CALLOUT_ACTIVE;
133 SCTP_TIMERQ_UNLOCK();
134 return (0);
135 }
136 c->c_flags &= ~(SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING);
137 if (c == sctp_os_timer_next) {
138 sctp_os_timer_next = TAILQ_NEXT(c, tqe);
139 }
140 TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
141 SCTP_TIMERQ_UNLOCK();
142 return (1);
143}
144
145void
146sctp_handle_tick(unsigned int delta)
147{
148 sctp_os_timer_t *c;
149 void (*c_func)(void *);
150 void *c_arg;
151
152 SCTP_TIMERQ_LOCK();
153 /* update our tick count */
154 ticks += delta;
155 c = TAILQ_FIRST(&SCTP_BASE_INFO(callqueue));
156 while (c) {
157 if (c->c_time <= ticks) {
158 sctp_os_timer_next = TAILQ_NEXT(c, tqe);
159 TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
160 c_func = c->c_func;
161 c_arg = c->c_arg;
162 c->c_flags &= ~SCTP_CALLOUT_PENDING;
163 SCTP_TIMERQ_UNLOCK();
164 c_func(c_arg);
165 SCTP_TIMERQ_LOCK();
166 c = sctp_os_timer_next;
167 } else {
168 c = TAILQ_NEXT(c, tqe);
169 }
170 }
171 sctp_os_timer_next = NULL;
172 SCTP_TIMERQ_UNLOCK();
173}
174
175#if defined(__APPLE__)
176void
177sctp_timeout(void *arg SCTP_UNUSED)
178{
179 sctp_handle_tick(SCTP_BASE_VAR(sctp_main_timer_ticks));
180 sctp_start_main_timer();
181}
182#endif
183
184#if defined(__Userspace__)
185#define TIMEOUT_INTERVAL 10
186
187void *
188user_sctp_timer_iterate(void *arg)
189{
190 sctp_userspace_set_threadname("SCTP timer");
191 for (;;) {
192#if defined (__Userspace_os_Windows)
193 Sleep(TIMEOUT_INTERVAL);
194#else
195 struct timeval timeout;
196
197 timeout.tv_sec = 0;
198 timeout.tv_usec = 1000 * TIMEOUT_INTERVAL;
199 select(0, NULL, NULL, NULL, &timeout);
200#endif
201 if (SCTP_BASE_VAR(timer_thread_should_exit)) {
202 break;
203 }
204 sctp_handle_tick(MSEC_TO_TICKS(TIMEOUT_INTERVAL));
205 }
206 return (NULL);
207}
208
209void
210sctp_start_timer(void)
211{
212 /*
213 * No need to do SCTP_TIMERQ_LOCK_INIT();
214 * here, it is being done in sctp_pcb_init()
215 */
216 int rc;
217
218 rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(timer_thread), user_sctp_timer_iterate);
219 if (rc) {
220 SCTP_PRINTF("ERROR; return code from sctp_thread_create() is %d\n", rc);
221 }
222}
223
224#endif