rbsrt 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +752 -0
- data/Rakefile +29 -0
- data/bin/rbsrt-client +113 -0
- data/bin/rbsrt-server +68 -0
- data/bin/rbsrt-sockets +82 -0
- data/ext/rbsrt/extconf.rb +37 -0
- data/ext/rbsrt/rbsrt.c +2270 -0
- data/ext/rbsrt/rbsrt.h +265 -0
- data/ext/rbsrt/rbstats.c +960 -0
- data/ext/rbsrt/rbstats.h +24 -0
- data/lib/rbsrt/rbsrt.bundle +0 -0
- data/lib/rbsrt/streamid_components.rb +113 -0
- data/lib/rbsrt/version.rb +3 -0
- data/lib/rbsrt.rb +5 -0
- data/rbsrt.gemspec +22 -0
- data/test/rbsrt/poll_test.rb +153 -0
- data/test/rbsrt/stats_test.rb +546 -0
- data/test/rbsrt/streamid_components_test.rb +281 -0
- metadata +83 -0
data/ext/rbsrt/rbsrt.c
ADDED
@@ -0,0 +1,2270 @@
|
|
1
|
+
/*
|
2
|
+
* Ruby SRT - Ruby binding for Secure, Reliable, Transport
|
3
|
+
* Copyright (c) 2019 Klaas Speller, Recce.
|
4
|
+
*
|
5
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
6
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
7
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
8
|
+
*
|
9
|
+
*/
|
10
|
+
|
11
|
+
/**
|
12
|
+
* A Ruby wrapper for SRT (Secure Reliable Transport)
|
13
|
+
*
|
14
|
+
* @author: Klaas Speller <klaas@recce.nl>
|
15
|
+
*/
|
16
|
+
|
17
|
+
// MARK: - Includes
|
18
|
+
|
19
|
+
// MARK: - System
|
20
|
+
|
21
|
+
#include <stdio.h>
|
22
|
+
#include <stdlib.h>
|
23
|
+
#include <unistd.h>
|
24
|
+
#include <errno.h>
|
25
|
+
#include <string.h>
|
26
|
+
#include <sys/types.h>
|
27
|
+
#include <sys/socket.h>
|
28
|
+
#include <netinet/in.h>
|
29
|
+
#include <netdb.h>
|
30
|
+
#include <arpa/inet.h>
|
31
|
+
#include <sys/wait.h>
|
32
|
+
#include <signal.h>
|
33
|
+
#include <stdint.h>
|
34
|
+
|
35
|
+
#include <stdatomic.h>
|
36
|
+
|
37
|
+
|
38
|
+
// MARK: Ruby
|
39
|
+
|
40
|
+
#include <ruby/ruby.h>
|
41
|
+
#include <ruby/util.h>
|
42
|
+
#include <ruby/intern.h>
|
43
|
+
#include <ruby/thread.h>
|
44
|
+
#include <ruby/thread_native.h>
|
45
|
+
#include <ruby/io.h>
|
46
|
+
#include <ruby/vm.h>
|
47
|
+
|
48
|
+
// MARK: SRT
|
49
|
+
|
50
|
+
#include <srt/srt.h>
|
51
|
+
|
52
|
+
|
53
|
+
// MARK: - API
|
54
|
+
|
55
|
+
#include "rbsrt.h"
|
56
|
+
#include "rbstats.h"
|
57
|
+
|
58
|
+
|
59
|
+
// MARK: Network
|
60
|
+
|
61
|
+
int resolve_address(struct addrinfo *res, char host[], char port[])
|
62
|
+
{
|
63
|
+
struct addrinfo hints;
|
64
|
+
|
65
|
+
memset(&hints, 0, sizeof hints);
|
66
|
+
hints.ai_family = AF_UNSPEC;
|
67
|
+
hints.ai_socktype = SOCK_DGRAM;
|
68
|
+
|
69
|
+
int status;
|
70
|
+
|
71
|
+
if ((status = getaddrinfo(host, port, &hints, &res)) != 0)
|
72
|
+
{
|
73
|
+
DEBUG_ERROR_PRINT("getaddrinfo: %s", gai_strerror(status));
|
74
|
+
|
75
|
+
return RBSRT_FAILURE;
|
76
|
+
}
|
77
|
+
|
78
|
+
return RBSRT_SUCCESS;
|
79
|
+
}
|
80
|
+
|
81
|
+
void *get_in_addr(struct sockaddr *sa)
|
82
|
+
{
|
83
|
+
if (sa->sa_family == AF_INET)
|
84
|
+
{
|
85
|
+
return &(((struct sockaddr_in*)sa)->sin_addr);
|
86
|
+
}
|
87
|
+
|
88
|
+
return &(((struct sockaddr_in6*)sa)->sin6_addr);
|
89
|
+
}
|
90
|
+
|
91
|
+
|
92
|
+
// MARK: - Ruby Classes
|
93
|
+
|
94
|
+
VALUE mSRTModule = Qnil;
|
95
|
+
VALUE mSRTSocketKlass = Qnil;
|
96
|
+
VALUE mSRTClientKlass = Qnil;
|
97
|
+
VALUE mSRTServerKlass = Qnil;
|
98
|
+
VALUE mSRTConnectionKlass = Qnil;
|
99
|
+
VALUE mSRTPollKlass = Qnil;
|
100
|
+
|
101
|
+
|
102
|
+
// MARK: - Enums
|
103
|
+
|
104
|
+
typedef enum RBSRTServerFlag
|
105
|
+
{
|
106
|
+
RBSRT_SERVER_UNINITIALIZED = 0,
|
107
|
+
RBSRT_SERVER_INITIALIZED = (1 << 0),
|
108
|
+
RBSRT_SERVER_BOUND = (1 << 1),
|
109
|
+
RBSRT_SERVER_LISTENING = (1 << 2),
|
110
|
+
RBSRT_SERVER_ACCEPTING = (1 << 3),
|
111
|
+
RBSRT_SERVER_CLOSED = (1 << 4)
|
112
|
+
} rbsrt_server_flag_t;
|
113
|
+
|
114
|
+
typedef enum RBSRTClientFlag
|
115
|
+
{
|
116
|
+
RBSRT_CLIENT_UNINITIALIZED = 0,
|
117
|
+
RBSRT_CLIENT_INITIALIZED = (1 << 0),
|
118
|
+
RBSRT_CLIENT_CONNECTED = (1 << 1),
|
119
|
+
RBSRT_CLIENT_CLOSED = (1 << 2)
|
120
|
+
} rbsrt_client_flag_t;
|
121
|
+
|
122
|
+
// MARK: Errors
|
123
|
+
|
124
|
+
VALUE rbsrt_eStandardError = Qnil;
|
125
|
+
VALUE rbstr_eUNKNOWNError = Qnil;
|
126
|
+
VALUE rbstr_eCONNSETUPError = Qnil;
|
127
|
+
VALUE rbstr_eNOSERVERError = Qnil;
|
128
|
+
VALUE rbstr_eCONNREJError = Qnil;
|
129
|
+
VALUE rbstr_eSOCKFAILError = Qnil;
|
130
|
+
VALUE rbstr_eSECFAILError = Qnil;
|
131
|
+
VALUE rbstr_eCONNFAILError = Qnil;
|
132
|
+
VALUE rbstr_eCONNLOSTError = Qnil;
|
133
|
+
VALUE rbstr_eNOCONNError = Qnil;
|
134
|
+
VALUE rbstr_eRESOURCEError = Qnil;
|
135
|
+
VALUE rbstr_eTHREADError = Qnil;
|
136
|
+
VALUE rbstr_eNOBUFError = Qnil;
|
137
|
+
VALUE rbstr_eFILEError = Qnil;
|
138
|
+
VALUE rbstr_eINVRDOFFError = Qnil;
|
139
|
+
VALUE rbstr_eRDPERMError = Qnil;
|
140
|
+
VALUE rbstr_eINVWROFFError = Qnil;
|
141
|
+
VALUE rbstr_eWRPERMError = Qnil;
|
142
|
+
VALUE rbstr_eINVOPError = Qnil;
|
143
|
+
VALUE rbstr_eBOUNDSOCKError = Qnil;
|
144
|
+
VALUE rbstr_eCONNSOCKError = Qnil;
|
145
|
+
VALUE rbstr_eINVPARAMError = Qnil;
|
146
|
+
VALUE rbstr_eINVSOCKError = Qnil;
|
147
|
+
VALUE rbstr_eUNBOUNDSOCKError = Qnil;
|
148
|
+
VALUE rbstr_eNOLISTENError = Qnil;
|
149
|
+
VALUE rbstr_eRDVNOSERVError = Qnil;
|
150
|
+
VALUE rbstr_eRDVUNBOUNDError = Qnil;
|
151
|
+
VALUE rbstr_eINVALMSGAPIError = Qnil;
|
152
|
+
VALUE rbstr_eINVALBUFFERAPIError = Qnil;
|
153
|
+
VALUE rbstr_eDUPLISTENError = Qnil;
|
154
|
+
VALUE rbstr_eLARGEMSGError = Qnil;
|
155
|
+
VALUE rbstr_eINVPOLLIDError = Qnil;
|
156
|
+
VALUE rbstr_eASYNCFAILError = Qnil;
|
157
|
+
VALUE rbstr_eASYNCSNDError = Qnil;
|
158
|
+
VALUE rbstr_eASYNCRCVError = Qnil;
|
159
|
+
VALUE rbstr_eTIMEOUTError = Qnil;
|
160
|
+
VALUE rbstr_eCONGESTError = Qnil;
|
161
|
+
VALUE rbstr_ePEERERRError = Qnil;
|
162
|
+
|
163
|
+
|
164
|
+
VALUE rbsrt_error_get_code(VALUE self)
|
165
|
+
{
|
166
|
+
VALUE klazz = rb_class_of(self);
|
167
|
+
|
168
|
+
return rb_const_get(klazz, rb_intern("Code"));
|
169
|
+
}
|
170
|
+
|
171
|
+
VALUE rbstr_error_with_srt_error_code(SRT_ERRNO error_code)
|
172
|
+
{
|
173
|
+
VALUE error;
|
174
|
+
|
175
|
+
switch(error_code)
|
176
|
+
{
|
177
|
+
case SRT_EUNKNOWN:
|
178
|
+
error = rbstr_eUNKNOWNError;
|
179
|
+
break;
|
180
|
+
|
181
|
+
case SRT_ECONNSETUP:
|
182
|
+
error = rbstr_eCONNSETUPError;
|
183
|
+
break;
|
184
|
+
|
185
|
+
case SRT_ENOSERVER:
|
186
|
+
error = rbstr_eNOSERVERError;
|
187
|
+
break;
|
188
|
+
|
189
|
+
case SRT_ECONNREJ:
|
190
|
+
error = rbstr_eCONNREJError;
|
191
|
+
break;
|
192
|
+
|
193
|
+
case SRT_ESOCKFAIL:
|
194
|
+
error = rbstr_eSOCKFAILError;
|
195
|
+
break;
|
196
|
+
|
197
|
+
case SRT_ESECFAIL:
|
198
|
+
error = rbstr_eSECFAILError;
|
199
|
+
break;
|
200
|
+
|
201
|
+
case SRT_ECONNFAIL:
|
202
|
+
error = rbstr_eCONNFAILError;
|
203
|
+
break;
|
204
|
+
|
205
|
+
case SRT_ECONNLOST:
|
206
|
+
error = rbstr_eCONNLOSTError;
|
207
|
+
break;
|
208
|
+
|
209
|
+
case SRT_ENOCONN:
|
210
|
+
error = rbstr_eNOCONNError;
|
211
|
+
break;
|
212
|
+
|
213
|
+
case SRT_ERESOURCE:
|
214
|
+
error = rbstr_eRESOURCEError;
|
215
|
+
break;
|
216
|
+
|
217
|
+
case SRT_ETHREAD:
|
218
|
+
error = rbstr_eTHREADError;
|
219
|
+
break;
|
220
|
+
|
221
|
+
case SRT_ENOBUF:
|
222
|
+
error = rbstr_eNOBUFError;
|
223
|
+
break;
|
224
|
+
|
225
|
+
case SRT_EFILE:
|
226
|
+
error = rbstr_eFILEError;
|
227
|
+
break;
|
228
|
+
|
229
|
+
case SRT_EINVRDOFF:
|
230
|
+
error = rbstr_eINVRDOFFError;
|
231
|
+
break;
|
232
|
+
|
233
|
+
case SRT_ERDPERM:
|
234
|
+
error = rbstr_eRDPERMError;
|
235
|
+
break;
|
236
|
+
|
237
|
+
case SRT_EINVWROFF:
|
238
|
+
error = rbstr_eINVWROFFError;
|
239
|
+
break;
|
240
|
+
|
241
|
+
case SRT_EWRPERM:
|
242
|
+
error = rbstr_eWRPERMError;
|
243
|
+
break;
|
244
|
+
|
245
|
+
case SRT_EINVOP:
|
246
|
+
error = rbstr_eINVOPError;
|
247
|
+
break;
|
248
|
+
|
249
|
+
case SRT_EBOUNDSOCK:
|
250
|
+
error = rbstr_eBOUNDSOCKError;
|
251
|
+
break;
|
252
|
+
|
253
|
+
case SRT_ECONNSOCK:
|
254
|
+
error = rbstr_eCONNSOCKError;
|
255
|
+
break;
|
256
|
+
|
257
|
+
case SRT_EINVPARAM:
|
258
|
+
error = rbstr_eINVPARAMError;
|
259
|
+
break;
|
260
|
+
|
261
|
+
case SRT_EINVSOCK:
|
262
|
+
error = rbstr_eINVSOCKError;
|
263
|
+
break;
|
264
|
+
|
265
|
+
case SRT_EUNBOUNDSOCK:
|
266
|
+
error = rbstr_eUNBOUNDSOCKError;
|
267
|
+
break;
|
268
|
+
|
269
|
+
case SRT_ENOLISTEN:
|
270
|
+
error = rbstr_eNOLISTENError;
|
271
|
+
break;
|
272
|
+
|
273
|
+
case SRT_ERDVNOSERV:
|
274
|
+
error = rbstr_eRDVNOSERVError;
|
275
|
+
break;
|
276
|
+
|
277
|
+
case SRT_ERDVUNBOUND:
|
278
|
+
error = rbstr_eRDVUNBOUNDError;
|
279
|
+
break;
|
280
|
+
|
281
|
+
case SRT_EINVALMSGAPI:
|
282
|
+
error = rbstr_eINVALMSGAPIError;
|
283
|
+
break;
|
284
|
+
|
285
|
+
case SRT_EINVALBUFFERAPI:
|
286
|
+
error = rbstr_eINVALBUFFERAPIError;
|
287
|
+
break;
|
288
|
+
|
289
|
+
case SRT_EDUPLISTEN:
|
290
|
+
error = rbstr_eDUPLISTENError;
|
291
|
+
break;
|
292
|
+
|
293
|
+
case SRT_ELARGEMSG:
|
294
|
+
error = rbstr_eLARGEMSGError;
|
295
|
+
break;
|
296
|
+
|
297
|
+
case SRT_EINVPOLLID:
|
298
|
+
error = rbstr_eINVPOLLIDError;
|
299
|
+
break;
|
300
|
+
|
301
|
+
case SRT_EASYNCFAIL:
|
302
|
+
error = rbstr_eASYNCFAILError;
|
303
|
+
break;
|
304
|
+
|
305
|
+
case SRT_EASYNCSND:
|
306
|
+
error = rbstr_eASYNCSNDError;
|
307
|
+
break;
|
308
|
+
|
309
|
+
case SRT_EASYNCRCV:
|
310
|
+
error = rbstr_eASYNCRCVError;
|
311
|
+
break;
|
312
|
+
|
313
|
+
case SRT_ETIMEOUT:
|
314
|
+
error = rbstr_eTIMEOUTError;
|
315
|
+
break;
|
316
|
+
|
317
|
+
case SRT_ECONGEST:
|
318
|
+
error = rbstr_eCONGESTError;
|
319
|
+
break;
|
320
|
+
|
321
|
+
case SRT_EPEERERR:
|
322
|
+
error = rbstr_ePEERERRError;
|
323
|
+
break;
|
324
|
+
|
325
|
+
default:
|
326
|
+
error = rbsrt_eStandardError;
|
327
|
+
break;
|
328
|
+
}
|
329
|
+
|
330
|
+
return error;
|
331
|
+
}
|
332
|
+
|
333
|
+
_Noreturn void rbsrt_raise_last_srt_error()
|
334
|
+
{
|
335
|
+
int sys_errno = 0;
|
336
|
+
int error_code = srt_getlasterror(&sys_errno);
|
337
|
+
VALUE last_error = rbstr_error_with_srt_error_code(error_code);
|
338
|
+
|
339
|
+
rb_raise(last_error, "%s", srt_getlasterror_str());
|
340
|
+
}
|
341
|
+
|
342
|
+
void rbsrt_init_errors()
|
343
|
+
{
|
344
|
+
rbsrt_eStandardError = rb_define_class_under(mSRTModule, "Error", rb_eStandardError);
|
345
|
+
|
346
|
+
rb_define_method(rbsrt_eStandardError, "code", rbsrt_error_get_code, 0);
|
347
|
+
|
348
|
+
|
349
|
+
// Error Types
|
350
|
+
|
351
|
+
rbstr_eUNKNOWNError = rb_define_class_under(rb_eStandardError, "UNKNOWN", rbsrt_eStandardError);
|
352
|
+
rbstr_eCONNSETUPError = rb_define_class_under(rb_eStandardError, "CONNSETUP", rbsrt_eStandardError);
|
353
|
+
rbstr_eNOSERVERError = rb_define_class_under(rb_eStandardError, "NOSERVER", rbsrt_eStandardError);
|
354
|
+
rbstr_eCONNREJError = rb_define_class_under(rb_eStandardError, "CONNREJ", rbsrt_eStandardError);
|
355
|
+
rbstr_eSOCKFAILError = rb_define_class_under(rb_eStandardError, "SOCKFAIL", rbsrt_eStandardError);
|
356
|
+
rbstr_eSECFAILError = rb_define_class_under(rb_eStandardError, "SECFAIL", rbsrt_eStandardError);
|
357
|
+
rbstr_eCONNFAILError = rb_define_class_under(rb_eStandardError, "CONNFAIL", rbsrt_eStandardError);
|
358
|
+
rbstr_eCONNLOSTError = rb_define_class_under(rb_eStandardError, "CONNLOST", rbsrt_eStandardError);
|
359
|
+
rbstr_eNOCONNError = rb_define_class_under(rb_eStandardError, "NOCONN", rbsrt_eStandardError);
|
360
|
+
rbstr_eRESOURCEError = rb_define_class_under(rb_eStandardError, "RESOURCE", rbsrt_eStandardError);
|
361
|
+
rbstr_eTHREADError = rb_define_class_under(rb_eStandardError, "THREAD", rbsrt_eStandardError);
|
362
|
+
rbstr_eNOBUFError = rb_define_class_under(rb_eStandardError, "NOBUF", rbsrt_eStandardError);
|
363
|
+
rbstr_eFILEError = rb_define_class_under(rb_eStandardError, "FILE", rbsrt_eStandardError);
|
364
|
+
rbstr_eINVRDOFFError = rb_define_class_under(rb_eStandardError, "INVRDOFF", rbsrt_eStandardError);
|
365
|
+
rbstr_eRDPERMError = rb_define_class_under(rb_eStandardError, "RDPERM", rbsrt_eStandardError);
|
366
|
+
rbstr_eINVWROFFError = rb_define_class_under(rb_eStandardError, "INVWROFF", rbsrt_eStandardError);
|
367
|
+
rbstr_eWRPERMError = rb_define_class_under(rb_eStandardError, "WRPERM", rbsrt_eStandardError);
|
368
|
+
rbstr_eINVOPError = rb_define_class_under(rb_eStandardError, "INVOP", rbsrt_eStandardError);
|
369
|
+
rbstr_eBOUNDSOCKError = rb_define_class_under(rb_eStandardError, "BOUNDSOCK", rbsrt_eStandardError);
|
370
|
+
rbstr_eCONNSOCKError = rb_define_class_under(rb_eStandardError, "CONNSOCK", rbsrt_eStandardError);
|
371
|
+
rbstr_eINVPARAMError = rb_define_class_under(rb_eStandardError, "INVPARAM", rbsrt_eStandardError);
|
372
|
+
rbstr_eINVSOCKError = rb_define_class_under(rb_eStandardError, "INVSOCK", rbsrt_eStandardError);
|
373
|
+
rbstr_eUNBOUNDSOCKError = rb_define_class_under(rb_eStandardError, "UNBOUNDSOCK", rbsrt_eStandardError);
|
374
|
+
rbstr_eNOLISTENError = rb_define_class_under(rb_eStandardError, "NOLISTEN", rbsrt_eStandardError);
|
375
|
+
rbstr_eRDVNOSERVError = rb_define_class_under(rb_eStandardError, "RDVNOSERV", rbsrt_eStandardError);
|
376
|
+
rbstr_eRDVUNBOUNDError = rb_define_class_under(rb_eStandardError, "RDVUNBOUND", rbsrt_eStandardError);
|
377
|
+
rbstr_eINVALMSGAPIError = rb_define_class_under(rb_eStandardError, "INVALMSGAPI", rbsrt_eStandardError);
|
378
|
+
rbstr_eINVALBUFFERAPIError = rb_define_class_under(rb_eStandardError, "INVALBUFFERAPI", rbsrt_eStandardError);
|
379
|
+
rbstr_eDUPLISTENError = rb_define_class_under(rb_eStandardError, "DUPLISTEN", rbsrt_eStandardError);
|
380
|
+
rbstr_eLARGEMSGError = rb_define_class_under(rb_eStandardError, "LARGEMSG", rbsrt_eStandardError);
|
381
|
+
rbstr_eINVPOLLIDError = rb_define_class_under(rb_eStandardError, "INVPOLLID", rbsrt_eStandardError);
|
382
|
+
rbstr_eASYNCFAILError = rb_define_class_under(rb_eStandardError, "ASYNCFAIL", rbsrt_eStandardError);
|
383
|
+
rbstr_eASYNCSNDError = rb_define_class_under(rb_eStandardError, "ASYNCSND", rbsrt_eStandardError);
|
384
|
+
rbstr_eASYNCRCVError = rb_define_class_under(rb_eStandardError, "ASYNCRCV", rbsrt_eStandardError);
|
385
|
+
rbstr_eTIMEOUTError = rb_define_class_under(rb_eStandardError, "TIMEOUT", rbsrt_eStandardError);
|
386
|
+
rbstr_eCONGESTError = rb_define_class_under(rb_eStandardError, "CONGEST", rbsrt_eStandardError);
|
387
|
+
rbstr_ePEERERRError = rb_define_class_under(rb_eStandardError, "PEERERR", rbsrt_eStandardError);
|
388
|
+
|
389
|
+
|
390
|
+
// Error Codes
|
391
|
+
|
392
|
+
rb_define_const(rbsrt_eStandardError, "Code", INT2FIX(0));
|
393
|
+
rb_define_const(rbstr_eUNKNOWNError, "Code", INT2FIX(SRT_EUNKNOWN));
|
394
|
+
rb_define_const(rbstr_eCONNSETUPError, "Code", INT2FIX(SRT_ECONNSETUP));
|
395
|
+
rb_define_const(rbstr_eNOSERVERError, "Code", INT2FIX(SRT_ENOSERVER));
|
396
|
+
rb_define_const(rbstr_eCONNREJError, "Code", INT2FIX(SRT_ECONNREJ));
|
397
|
+
rb_define_const(rbstr_eSOCKFAILError, "Code", INT2FIX(SRT_ESOCKFAIL));
|
398
|
+
rb_define_const(rbstr_eSECFAILError, "Code", INT2FIX(SRT_ESECFAIL));
|
399
|
+
rb_define_const(rbstr_eCONNFAILError, "Code", INT2FIX(SRT_ECONNFAIL));
|
400
|
+
rb_define_const(rbstr_eCONNLOSTError, "Code", INT2FIX(SRT_ECONNLOST));
|
401
|
+
rb_define_const(rbstr_eNOCONNError, "Code", INT2FIX(SRT_ENOCONN));
|
402
|
+
rb_define_const(rbstr_eRESOURCEError, "Code", INT2FIX(SRT_ERESOURCE));
|
403
|
+
rb_define_const(rbstr_eTHREADError, "Code", INT2FIX(SRT_ETHREAD));
|
404
|
+
rb_define_const(rbstr_eNOBUFError, "Code", INT2FIX(SRT_ENOBUF));
|
405
|
+
rb_define_const(rbstr_eFILEError, "Code", INT2FIX(SRT_EFILE));
|
406
|
+
rb_define_const(rbstr_eINVRDOFFError, "Code", INT2FIX(SRT_EINVRDOFF));
|
407
|
+
rb_define_const(rbstr_eRDPERMError, "Code", INT2FIX(SRT_ERDPERM));
|
408
|
+
rb_define_const(rbstr_eINVWROFFError, "Code", INT2FIX(SRT_EINVWROFF));
|
409
|
+
rb_define_const(rbstr_eWRPERMError, "Code", INT2FIX(SRT_EWRPERM));
|
410
|
+
rb_define_const(rbstr_eINVOPError, "Code", INT2FIX(SRT_EINVOP));
|
411
|
+
rb_define_const(rbstr_eBOUNDSOCKError, "Code", INT2FIX(SRT_EBOUNDSOCK));
|
412
|
+
rb_define_const(rbstr_eCONNSOCKError, "Code", INT2FIX(SRT_ECONNSOCK));
|
413
|
+
rb_define_const(rbstr_eINVPARAMError, "Code", INT2FIX(SRT_EINVPARAM));
|
414
|
+
rb_define_const(rbstr_eINVSOCKError, "Code", INT2FIX(SRT_EINVSOCK));
|
415
|
+
rb_define_const(rbstr_eUNBOUNDSOCKError, "Code", INT2FIX(SRT_EUNBOUNDSOCK));
|
416
|
+
rb_define_const(rbstr_eNOLISTENError, "Code", INT2FIX(SRT_ENOLISTEN));
|
417
|
+
rb_define_const(rbstr_eRDVNOSERVError, "Code", INT2FIX(SRT_ERDVNOSERV));
|
418
|
+
rb_define_const(rbstr_eRDVUNBOUNDError, "Code", INT2FIX(SRT_ERDVUNBOUND));
|
419
|
+
rb_define_const(rbstr_eINVALMSGAPIError, "Code", INT2FIX(SRT_EINVALMSGAPI));
|
420
|
+
rb_define_const(rbstr_eINVALBUFFERAPIError, "Code", INT2FIX(SRT_EINVALBUFFERAPI));
|
421
|
+
rb_define_const(rbstr_eDUPLISTENError, "Code", INT2FIX(SRT_EDUPLISTEN));
|
422
|
+
rb_define_const(rbstr_eLARGEMSGError, "Code", INT2FIX(SRT_ELARGEMSG));
|
423
|
+
rb_define_const(rbstr_eINVPOLLIDError, "Code", INT2FIX(SRT_EINVPOLLID));
|
424
|
+
rb_define_const(rbstr_eASYNCFAILError, "Code", INT2FIX(SRT_EASYNCFAIL));
|
425
|
+
rb_define_const(rbstr_eASYNCSNDError, "Code", INT2FIX(SRT_EASYNCSND));
|
426
|
+
rb_define_const(rbstr_eASYNCRCVError, "Code", INT2FIX(SRT_EASYNCRCV));
|
427
|
+
rb_define_const(rbstr_eTIMEOUTError, "Code", INT2FIX(SRT_ETIMEOUT));
|
428
|
+
rb_define_const(rbstr_eCONGESTError, "Code", INT2FIX(SRT_ECONGEST));
|
429
|
+
rb_define_const(rbstr_ePEERERRError, "Code", INT2FIX(SRT_EPEERERR));
|
430
|
+
|
431
|
+
}
|
432
|
+
|
433
|
+
|
434
|
+
// MARK: - SRT Init
|
435
|
+
|
436
|
+
VALUE rbsrt_srt_startup(void *c)
|
437
|
+
{
|
438
|
+
RBSRT_DEBUG_PRINT("srt startup");
|
439
|
+
|
440
|
+
srt_startup();
|
441
|
+
|
442
|
+
return Qnil;
|
443
|
+
}
|
444
|
+
|
445
|
+
void rbsrt_srt_cleanup(ruby_vm_t *vm)
|
446
|
+
{
|
447
|
+
RBSRT_DEBUG_PRINT("srt cleanup");
|
448
|
+
|
449
|
+
srt_cleanup();
|
450
|
+
}
|
451
|
+
|
452
|
+
// MARK: - Socket Base
|
453
|
+
|
454
|
+
// MARK: Socket State
|
455
|
+
|
456
|
+
#define RBSRT_SOCKET_STATE_READY_ID rb_intern("ready")
|
457
|
+
#define RBSRT_SOCKET_STATE_OPENED_ID rb_intern("opened")
|
458
|
+
#define RBSRT_SOCKET_STATE_LISTENING_ID rb_intern("listening")
|
459
|
+
#define RBSRT_SOCKET_STATE_CONNECTING_ID rb_intern("connecting")
|
460
|
+
#define RBSRT_SOCKET_STATE_CONNECTED_ID rb_intern("connected")
|
461
|
+
#define RBSRT_SOCKET_STATE_BROKEN_ID rb_intern("broken")
|
462
|
+
#define RBSRT_SOCKET_STATE_CLOSING_ID rb_intern("closing")
|
463
|
+
#define RBSRT_SOCKET_STATE_CLOSED_ID rb_intern("closed")
|
464
|
+
#define RBSRT_SOCKET_STATE_NONEXIST_ID rb_intern("nonexist")
|
465
|
+
|
466
|
+
#define RBSRT_SOCKET_STATE_READY_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_READY_ID)
|
467
|
+
#define RBSRT_SOCKET_STATE_OPENED_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_OPENED_ID)
|
468
|
+
#define RBSRT_SOCKET_STATE_LISTENING_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_LISTENING_ID)
|
469
|
+
#define RBSRT_SOCKET_STATE_CONNECTING_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_CONNECTING_ID)
|
470
|
+
#define RBSRT_SOCKET_STATE_CONNECTED_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_CONNECTED_ID)
|
471
|
+
#define RBSRT_SOCKET_STATE_BROKEN_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_BROKEN_ID)
|
472
|
+
#define RBSRT_SOCKET_STATE_CLOSING_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_CLOSING_ID)
|
473
|
+
#define RBSRT_SOCKET_STATE_CLOSED_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_CLOSED_ID)
|
474
|
+
#define RBSRT_SOCKET_STATE_NONEXIST_SYM RB_ID2SYM(RBSRT_SOCKET_STATE_NONEXIST_ID)
|
475
|
+
|
476
|
+
VALUE rbsrt_socket_get_socket_state(VALUE self)
|
477
|
+
{
|
478
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
479
|
+
|
480
|
+
RBSRT_DEBUG_PRINT("socket get socket state for %d", socket->socket);
|
481
|
+
|
482
|
+
SRT_SOCKSTATUS state = srt_getsockstate(socket->socket);
|
483
|
+
|
484
|
+
VALUE state_sym;
|
485
|
+
|
486
|
+
switch (state)
|
487
|
+
{
|
488
|
+
case SRTS_INIT:
|
489
|
+
state_sym = RBSRT_SOCKET_STATE_READY_SYM;
|
490
|
+
break;
|
491
|
+
|
492
|
+
case SRTS_OPENED:
|
493
|
+
state_sym = RBSRT_SOCKET_STATE_OPENED_SYM;
|
494
|
+
break;
|
495
|
+
|
496
|
+
case SRTS_LISTENING:
|
497
|
+
state_sym = RBSRT_SOCKET_STATE_LISTENING_SYM;
|
498
|
+
break;
|
499
|
+
|
500
|
+
case SRTS_CONNECTING:
|
501
|
+
state_sym = RBSRT_SOCKET_STATE_CONNECTING_SYM;
|
502
|
+
break;
|
503
|
+
|
504
|
+
case SRTS_CONNECTED:
|
505
|
+
state_sym = RBSRT_SOCKET_STATE_CONNECTED_SYM;
|
506
|
+
break;
|
507
|
+
|
508
|
+
case SRTS_BROKEN:
|
509
|
+
state_sym = RBSRT_SOCKET_STATE_BROKEN_SYM;
|
510
|
+
break;
|
511
|
+
|
512
|
+
case SRTS_CLOSING:
|
513
|
+
state_sym = RBSRT_SOCKET_STATE_CLOSING_SYM;
|
514
|
+
break;
|
515
|
+
|
516
|
+
case SRTS_CLOSED:
|
517
|
+
state_sym = RBSRT_SOCKET_STATE_CLOSED_SYM;
|
518
|
+
break;
|
519
|
+
|
520
|
+
case SRTS_NONEXIST:
|
521
|
+
state_sym = RBSRT_SOCKET_STATE_NONEXIST_SYM;
|
522
|
+
break;
|
523
|
+
|
524
|
+
default:
|
525
|
+
state_sym = Qnil;
|
526
|
+
break;
|
527
|
+
}
|
528
|
+
|
529
|
+
return state_sym;
|
530
|
+
}
|
531
|
+
|
532
|
+
VALUE rbsrt_socket_is_ready(VALUE self)
|
533
|
+
{
|
534
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
535
|
+
|
536
|
+
return srt_getsockstate(socket->socket) == SRTS_INIT ? Qtrue : Qfalse;
|
537
|
+
}
|
538
|
+
|
539
|
+
VALUE rbsrt_socket_is_opened(VALUE self)
|
540
|
+
{
|
541
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
542
|
+
|
543
|
+
return srt_getsockstate(socket->socket) == SRTS_OPENED ? Qtrue : Qfalse;
|
544
|
+
}
|
545
|
+
|
546
|
+
VALUE rbsrt_socket_is_listening(VALUE self)
|
547
|
+
{
|
548
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
549
|
+
|
550
|
+
return srt_getsockstate(socket->socket) == SRTS_LISTENING ? Qtrue : Qfalse;
|
551
|
+
}
|
552
|
+
|
553
|
+
VALUE rbsrt_socket_is_connecting(VALUE self)
|
554
|
+
{
|
555
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
556
|
+
|
557
|
+
return srt_getsockstate(socket->socket) == SRTS_CONNECTING ? Qtrue : Qfalse;
|
558
|
+
}
|
559
|
+
|
560
|
+
VALUE rbsrt_socket_is_connected(VALUE self)
|
561
|
+
{
|
562
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
563
|
+
|
564
|
+
return srt_getsockstate(socket->socket) == SRTS_CONNECTED ? Qtrue : Qfalse;
|
565
|
+
}
|
566
|
+
|
567
|
+
VALUE rbsrt_socket_is_broken(VALUE self)
|
568
|
+
{
|
569
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
570
|
+
|
571
|
+
return srt_getsockstate(socket->socket) == SRTS_BROKEN ? Qtrue : Qfalse;
|
572
|
+
}
|
573
|
+
|
574
|
+
VALUE rbsrt_socket_is_closing(VALUE self)
|
575
|
+
{
|
576
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
577
|
+
|
578
|
+
return srt_getsockstate(socket->socket) == SRTS_CLOSING ? Qtrue : Qfalse;
|
579
|
+
}
|
580
|
+
|
581
|
+
VALUE rbsrt_socket_is_closed(VALUE self)
|
582
|
+
{
|
583
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
584
|
+
|
585
|
+
return srt_getsockstate(socket->socket) == SRTS_CLOSED ? Qtrue : Qfalse;
|
586
|
+
}
|
587
|
+
|
588
|
+
VALUE rbsrt_socket_is_nonexist(VALUE self)
|
589
|
+
{
|
590
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
591
|
+
|
592
|
+
return srt_getsockstate(socket->socket) == SRTS_NONEXIST ? Qtrue : Qfalse;
|
593
|
+
}
|
594
|
+
|
595
|
+
void rbsrt_define_socket_state_api(VALUE klass)
|
596
|
+
{
|
597
|
+
rb_define_method(klass, "state", rbsrt_socket_get_socket_state, 0);
|
598
|
+
|
599
|
+
rb_define_method(klass, "ready?", rbsrt_socket_is_ready, 0);
|
600
|
+
rb_define_method(klass, "opened?", rbsrt_socket_is_opened, 0);
|
601
|
+
rb_define_method(klass, "listening?", rbsrt_socket_is_listening, 0);
|
602
|
+
rb_define_method(klass, "connecting?", rbsrt_socket_is_connecting, 0);
|
603
|
+
rb_define_method(klass, "connected?", rbsrt_socket_is_connected, 0);
|
604
|
+
rb_define_method(klass, "broken?", rbsrt_socket_is_broken, 0);
|
605
|
+
rb_define_method(klass, "closing?", rbsrt_socket_is_closing, 0);
|
606
|
+
rb_define_method(klass, "closed?", rbsrt_socket_is_closed, 0);
|
607
|
+
rb_define_method(klass, "nonexist?", rbsrt_socket_is_nonexist, 0);
|
608
|
+
}
|
609
|
+
|
610
|
+
|
611
|
+
// MARK: Connecting
|
612
|
+
|
613
|
+
VALUE rbsrt_socket_connect(VALUE self, VALUE host, VALUE port)
|
614
|
+
{
|
615
|
+
Check_Type(host, T_STRING);
|
616
|
+
Check_Type(port, T_STRING);
|
617
|
+
|
618
|
+
RBSRT_DEBUG_PRINT("socket connect: host=%s, port=%s", StringValuePtr(host), StringValuePtr(port));
|
619
|
+
|
620
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
621
|
+
|
622
|
+
VALUE retval = Qfalse;
|
623
|
+
|
624
|
+
int status;
|
625
|
+
struct addrinfo hints;
|
626
|
+
struct addrinfo *servinfo;
|
627
|
+
struct addrinfo *p;
|
628
|
+
|
629
|
+
int ipv6only = 0;
|
630
|
+
int ipv4only = 0;
|
631
|
+
|
632
|
+
|
633
|
+
memset(&hints, 0, sizeof hints);
|
634
|
+
|
635
|
+
hints.ai_family = AF_UNSPEC;
|
636
|
+
hints.ai_socktype = SOCK_DGRAM;
|
637
|
+
|
638
|
+
if ((status = getaddrinfo(StringValuePtr(host), StringValuePtr(port), &hints, &servinfo)) != 0)
|
639
|
+
{
|
640
|
+
rb_raise(rbsrt_eStandardError, "failed to get address info: %s", gai_strerror(status));
|
641
|
+
}
|
642
|
+
|
643
|
+
srt_clearlasterror();
|
644
|
+
|
645
|
+
for(p = servinfo;p != NULL; p = p->ai_next)
|
646
|
+
{
|
647
|
+
if ((p->ai_family == AF_INET && ipv6only) || (p->ai_family == AF_INET6 && ipv4only))
|
648
|
+
{
|
649
|
+
continue;
|
650
|
+
}
|
651
|
+
|
652
|
+
if (srt_connect(socket->socket, p->ai_addr, p->ai_addrlen) == SRT_ERROR)
|
653
|
+
{
|
654
|
+
RBSRT_DEBUG_PRINT("failed to connect socket: %s", srt_getlasterror_str());
|
655
|
+
|
656
|
+
continue;
|
657
|
+
}
|
658
|
+
|
659
|
+
#if RBSRT_DEBUG
|
660
|
+
char ipstr[INET6_ADDRSTRLEN];
|
661
|
+
inet_ntop(
|
662
|
+
p->ai_family,
|
663
|
+
(p->ai_family == AF_INET ? &(((struct sockaddr_in *)p->ai_addr)->sin_addr) : &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr)),
|
664
|
+
ipstr,
|
665
|
+
sizeof ipstr);
|
666
|
+
|
667
|
+
RBSRT_DEBUG_PRINT("socket connected: ip=%s", ipstr);
|
668
|
+
#endif
|
669
|
+
|
670
|
+
// connected
|
671
|
+
|
672
|
+
retval = Qtrue;
|
673
|
+
|
674
|
+
break;
|
675
|
+
}
|
676
|
+
|
677
|
+
// complete
|
678
|
+
|
679
|
+
freeaddrinfo(servinfo);
|
680
|
+
|
681
|
+
if (retval != Qtrue)
|
682
|
+
{
|
683
|
+
rbsrt_raise_last_srt_error();
|
684
|
+
}
|
685
|
+
|
686
|
+
return retval;
|
687
|
+
}
|
688
|
+
|
689
|
+
VALUE rbsrt_socket_accept(VALUE self)
|
690
|
+
{
|
691
|
+
RBSRT_DEBUG_PRINT("server accept");
|
692
|
+
|
693
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
694
|
+
|
695
|
+
struct sockaddr_storage remote_address;
|
696
|
+
int addr_size = sizeof(remote_address);
|
697
|
+
|
698
|
+
SRTSOCKET accepted_socket = srt_accept(socket->socket, (struct sockaddr *)&remote_address, &addr_size);
|
699
|
+
|
700
|
+
if (accepted_socket == SRT_ERROR)
|
701
|
+
{
|
702
|
+
rbsrt_raise_last_srt_error();
|
703
|
+
|
704
|
+
return Qnil;
|
705
|
+
}
|
706
|
+
|
707
|
+
VALUE rbclient = rb_class_new_instance(0, NULL, mSRTSocketKlass);
|
708
|
+
|
709
|
+
RBSRT_SOCKET_UNWRAP(rbclient, client);
|
710
|
+
|
711
|
+
client->socket = accepted_socket;
|
712
|
+
|
713
|
+
return rbclient;
|
714
|
+
}
|
715
|
+
|
716
|
+
VALUE rbsrt_socket_bind(VALUE self, VALUE address, VALUE port)
|
717
|
+
{
|
718
|
+
int status;
|
719
|
+
struct sockaddr_in sa;
|
720
|
+
// int livemode = SRTT_LIVE;
|
721
|
+
|
722
|
+
Check_Type(address, T_STRING);
|
723
|
+
Check_Type(port, T_STRING);
|
724
|
+
|
725
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
726
|
+
|
727
|
+
// get address info
|
728
|
+
// TODO: Handle domain names
|
729
|
+
|
730
|
+
sa.sin_family = AF_INET;
|
731
|
+
sa.sin_port = htons(atoi(StringValuePtr(port)));
|
732
|
+
|
733
|
+
if (inet_pton(AF_INET, StringValuePtr(address), &sa.sin_addr) != 1)
|
734
|
+
{
|
735
|
+
rb_raise(rb_eArgError, "bad adddress: %s", strerror(errno));
|
736
|
+
|
737
|
+
return Qfalse;
|
738
|
+
}
|
739
|
+
|
740
|
+
|
741
|
+
// bind socket
|
742
|
+
|
743
|
+
status = srt_bind(socket->socket, (struct sockaddr *)&sa, sizeof(sa));
|
744
|
+
|
745
|
+
if (status == SRT_ERROR)
|
746
|
+
{
|
747
|
+
rbsrt_raise_last_srt_error();
|
748
|
+
|
749
|
+
return Qfalse;
|
750
|
+
}
|
751
|
+
|
752
|
+
return Qtrue;
|
753
|
+
}
|
754
|
+
|
755
|
+
VALUE rbsrt_socket_listen(VALUE self, VALUE nbacklog)
|
756
|
+
{
|
757
|
+
Check_Type(nbacklog, T_FIXNUM);
|
758
|
+
|
759
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
760
|
+
|
761
|
+
int status = srt_listen(socket->socket, FIX2INT(nbacklog));
|
762
|
+
|
763
|
+
if (status == SRT_ERROR)
|
764
|
+
{
|
765
|
+
rbsrt_raise_last_srt_error();
|
766
|
+
|
767
|
+
return Qfalse;
|
768
|
+
}
|
769
|
+
|
770
|
+
return Qtrue;
|
771
|
+
}
|
772
|
+
|
773
|
+
|
774
|
+
// MARK: Creating and Configuring
|
775
|
+
|
776
|
+
VALUE rbsrt_socket_close(VALUE self)
|
777
|
+
{
|
778
|
+
RBSRT_DEBUG_PRINT("socket close");
|
779
|
+
|
780
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket)
|
781
|
+
|
782
|
+
if (srt_close(socket->socket) == SRT_ERROR)
|
783
|
+
{
|
784
|
+
rbsrt_raise_last_srt_error();
|
785
|
+
|
786
|
+
return Qfalse;
|
787
|
+
}
|
788
|
+
|
789
|
+
return Qtrue;
|
790
|
+
}
|
791
|
+
|
792
|
+
|
793
|
+
// MARK: Transmission
|
794
|
+
|
795
|
+
VALUE rbsrt_socket_sendmsg(VALUE self, VALUE message)
|
796
|
+
{
|
797
|
+
RBSRT_DEBUG_PRINT("socket sendmsg");
|
798
|
+
|
799
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket)
|
800
|
+
|
801
|
+
int message_type = rb_type(message);
|
802
|
+
const char *buf = NULL;
|
803
|
+
int buf_len = 0;
|
804
|
+
|
805
|
+
switch (message_type)
|
806
|
+
{
|
807
|
+
case T_STRING:
|
808
|
+
buf = StringValuePtr(message);
|
809
|
+
buf_len = (int)RSTRING_LEN(message);
|
810
|
+
RBSRT_DEBUG_PRINT("sendmsg: %d", buf_len);
|
811
|
+
break;
|
812
|
+
|
813
|
+
case T_OBJECT:
|
814
|
+
case T_DATA:
|
815
|
+
RBSRT_DEBUG_PRINT("sendmsg DATA");
|
816
|
+
// TODO: Support binary
|
817
|
+
rb_raise(rb_eArgError, "message must be a string");
|
818
|
+
// rdata
|
819
|
+
return FIX2INT(SRT_ERROR);
|
820
|
+
break;
|
821
|
+
|
822
|
+
default:
|
823
|
+
rb_raise(rb_eArgError, "message must a string");
|
824
|
+
|
825
|
+
return FIX2INT(SRT_ERROR);
|
826
|
+
break;
|
827
|
+
}
|
828
|
+
|
829
|
+
|
830
|
+
// send data
|
831
|
+
|
832
|
+
int packet_size;
|
833
|
+
int nbytes;
|
834
|
+
int total_nbytes = 0;
|
835
|
+
char const *buf_p = buf;
|
836
|
+
|
837
|
+
do
|
838
|
+
{
|
839
|
+
packet_size = (buf_len - total_nbytes) > RBSRT_PAYLOAD_SIZE ? RBSRT_PAYLOAD_SIZE : (buf_len - total_nbytes);
|
840
|
+
|
841
|
+
nbytes = srt_sendmsg2(socket->socket, (buf_p + total_nbytes), packet_size, NULL);
|
842
|
+
|
843
|
+
if (nbytes == SRT_ERROR)
|
844
|
+
{
|
845
|
+
DEBUG_ERROR_PRINT("sendmsg error. %s", srt_getlasterror_str());
|
846
|
+
|
847
|
+
rbsrt_raise_last_srt_error();
|
848
|
+
|
849
|
+
break;
|
850
|
+
}
|
851
|
+
|
852
|
+
RBSRT_DEBUG_PRINT("send bytes %d", nbytes);
|
853
|
+
}
|
854
|
+
while ((total_nbytes += nbytes) < buf_len);
|
855
|
+
|
856
|
+
return INT2FIX(total_nbytes);
|
857
|
+
}
|
858
|
+
|
859
|
+
VALUE rbsrt_socket_recvmsg(VALUE self)
|
860
|
+
{
|
861
|
+
RBSRT_DEBUG_PRINT("socket recvmsg");
|
862
|
+
|
863
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket)
|
864
|
+
|
865
|
+
int nbuf = RBSRT_PAYLOAD_SIZE * 2;
|
866
|
+
char buf[nbuf];
|
867
|
+
|
868
|
+
int nbytes = srt_recvmsg2(socket->socket, buf, nbuf, NULL);
|
869
|
+
|
870
|
+
if (nbytes == SRT_ERROR)
|
871
|
+
{
|
872
|
+
rbsrt_raise_last_srt_error();
|
873
|
+
|
874
|
+
return Qnil;
|
875
|
+
}
|
876
|
+
|
877
|
+
else if (nbytes == 0)
|
878
|
+
{
|
879
|
+
// TODO: Close socket
|
880
|
+
return Qnil;
|
881
|
+
}
|
882
|
+
|
883
|
+
VALUE data = rb_str_buf_new((long)nbytes);
|
884
|
+
rb_str_buf_cat(data, buf, (long)nbytes);
|
885
|
+
rb_obj_taint(data);
|
886
|
+
|
887
|
+
return data;
|
888
|
+
}
|
889
|
+
|
890
|
+
|
891
|
+
// MARK: Socket Options
|
892
|
+
|
893
|
+
VALUE rbsrt_socket_get_id(VALUE self)
|
894
|
+
{
|
895
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
896
|
+
|
897
|
+
return INT2FIX(socket->socket);
|
898
|
+
}
|
899
|
+
|
900
|
+
VALUE rbsrt_socket_set_rcvsyn(VALUE self, VALUE syn)
|
901
|
+
{
|
902
|
+
int is_syn = RTEST(syn) ? 1 : 0;
|
903
|
+
|
904
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
905
|
+
|
906
|
+
if (srt_setsockflag(socket->socket, SRTO_RCVSYN, &is_syn, sizeof(is_syn)) == SRT_ERROR)
|
907
|
+
{
|
908
|
+
rbsrt_raise_last_srt_error();
|
909
|
+
|
910
|
+
return Qfalse;
|
911
|
+
}
|
912
|
+
|
913
|
+
return Qtrue;
|
914
|
+
}
|
915
|
+
|
916
|
+
VALUE rbsrt_socket_get_rcvsyn(VALUE self)
|
917
|
+
{
|
918
|
+
int is_syn = 0;
|
919
|
+
int is_syn_size = 0;
|
920
|
+
|
921
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
922
|
+
|
923
|
+
if (srt_getsockflag(socket->socket, SRTO_RCVSYN, &is_syn, &is_syn_size) == SRT_ERROR)
|
924
|
+
{
|
925
|
+
rbsrt_raise_last_srt_error();
|
926
|
+
|
927
|
+
return Qnil;
|
928
|
+
}
|
929
|
+
|
930
|
+
return is_syn ? Qtrue : Qfalse;
|
931
|
+
}
|
932
|
+
|
933
|
+
VALUE rbsrt_socket_set_sndsyn(VALUE self, VALUE syn)
|
934
|
+
{
|
935
|
+
int is_syn = RTEST(syn) ? 1 : 0;
|
936
|
+
|
937
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
938
|
+
|
939
|
+
if (srt_setsockflag(socket->socket, SRTO_SNDSYN, &is_syn, sizeof(is_syn)) == SRT_ERROR)
|
940
|
+
{
|
941
|
+
rbsrt_raise_last_srt_error();
|
942
|
+
|
943
|
+
return Qfalse;
|
944
|
+
}
|
945
|
+
|
946
|
+
return Qtrue;
|
947
|
+
}
|
948
|
+
|
949
|
+
VALUE rbsrt_socket_get_sndsyn(VALUE self)
|
950
|
+
{
|
951
|
+
int is_syn = 0;
|
952
|
+
int is_syn_size = 0;
|
953
|
+
|
954
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
955
|
+
|
956
|
+
if (srt_getsockflag(socket->socket, SRTO_SNDSYN, &is_syn, &is_syn_size) == SRT_ERROR)
|
957
|
+
{
|
958
|
+
rbsrt_raise_last_srt_error();
|
959
|
+
|
960
|
+
return Qnil;
|
961
|
+
}
|
962
|
+
|
963
|
+
return is_syn ? Qtrue : Qfalse;
|
964
|
+
}
|
965
|
+
|
966
|
+
VALUE rbsrt_socket_set_streamid(VALUE self, VALUE streamid)
|
967
|
+
{
|
968
|
+
Check_Type(streamid, T_STRING);
|
969
|
+
|
970
|
+
long streamid_llen = rb_str_strlen(streamid);
|
971
|
+
|
972
|
+
if (streamid_llen > 512)
|
973
|
+
{
|
974
|
+
rb_raise(rbsrt_eStandardError, "streamid must be 512 characters or less");
|
975
|
+
|
976
|
+
return Qfalse;
|
977
|
+
}
|
978
|
+
|
979
|
+
int streamid_len = (int)streamid_llen;
|
980
|
+
char *streamid_p = StringValuePtr(streamid);
|
981
|
+
|
982
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
983
|
+
|
984
|
+
if (srt_setsockflag(socket->socket, SRTO_STREAMID, streamid_p, streamid_len + 1) == SRT_ERROR)
|
985
|
+
{
|
986
|
+
rbsrt_raise_last_srt_error();
|
987
|
+
|
988
|
+
return Qfalse;
|
989
|
+
}
|
990
|
+
|
991
|
+
return Qtrue;
|
992
|
+
}
|
993
|
+
|
994
|
+
VALUE rbsrt_socket_get_streamid(VALUE self)
|
995
|
+
{
|
996
|
+
char streamid[1024];
|
997
|
+
int streamid_len = sizeof(streamid);
|
998
|
+
|
999
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
1000
|
+
|
1001
|
+
if (srt_getsockflag(socket->socket, SRTO_STREAMID, &streamid, &streamid_len) == SRT_ERROR)
|
1002
|
+
{
|
1003
|
+
rbsrt_raise_last_srt_error();
|
1004
|
+
|
1005
|
+
return Qfalse;
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
if (streamid_len <= 0)
|
1009
|
+
{
|
1010
|
+
return Qnil;
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
VALUE result = rb_str_buf_new((long)streamid_len);
|
1014
|
+
rb_str_buf_cat(result, streamid, (long)streamid_len);
|
1015
|
+
rb_obj_taint(result);
|
1016
|
+
|
1017
|
+
return result;
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
VALUE rbsrt_socket_set_transtype(VALUE self, VALUE type)
|
1021
|
+
{
|
1022
|
+
RBSRT_DEBUG_PRINT("socket set transmission type");
|
1023
|
+
|
1024
|
+
// unwrap type argument
|
1025
|
+
|
1026
|
+
int type_arg_type = rb_type(type);
|
1027
|
+
int srt_transtype;
|
1028
|
+
const char *type_name = NULL;
|
1029
|
+
|
1030
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
1031
|
+
|
1032
|
+
switch (type_arg_type)
|
1033
|
+
{
|
1034
|
+
case T_STRING:
|
1035
|
+
type_name = StringValuePtr(type);
|
1036
|
+
break;
|
1037
|
+
|
1038
|
+
case T_SYMBOL:
|
1039
|
+
type_name = rb_id2name(SYM2ID(type));
|
1040
|
+
break;
|
1041
|
+
|
1042
|
+
case T_FIXNUM:
|
1043
|
+
if (FIX2INT(type) == SRTT_LIVE || FIX2INT(type) == SRTT_FILE)
|
1044
|
+
{
|
1045
|
+
srt_transtype = FIX2INT(type);
|
1046
|
+
|
1047
|
+
goto set_flag;
|
1048
|
+
}
|
1049
|
+
|
1050
|
+
else
|
1051
|
+
{
|
1052
|
+
goto invalid_argument;
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
break;
|
1056
|
+
|
1057
|
+
default:
|
1058
|
+
goto invalid_argument;
|
1059
|
+
break;
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
// set option
|
1063
|
+
|
1064
|
+
if (strncmp(type_name, "live", 5) == 0)
|
1065
|
+
{
|
1066
|
+
srt_transtype = SRTT_LIVE;
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
else if (strncmp(type_name, "file", 5) == 0)
|
1070
|
+
{
|
1071
|
+
srt_transtype = SRTT_FILE;
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
else
|
1075
|
+
{
|
1076
|
+
goto invalid_argument;
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
set_flag:
|
1080
|
+
|
1081
|
+
if (srt_setsockflag(socket->socket, SRTO_TRANSTYPE, &srt_transtype, sizeof(srt_transtype)) == SRT_ERROR)
|
1082
|
+
{
|
1083
|
+
rbsrt_raise_last_srt_error();
|
1084
|
+
|
1085
|
+
return Qfalse;
|
1086
|
+
}
|
1087
|
+
|
1088
|
+
return Qtrue;
|
1089
|
+
|
1090
|
+
invalid_argument:
|
1091
|
+
rb_raise(rb_eArgError, "transmission type must be live (:live, \"live\", %d), or file (:file, \"file\", %d)", SRTT_LIVE, SRTT_FILE);
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
|
1095
|
+
VALUE rbsrt_socket_set_tsbpdmode(VALUE self, VALUE val)
|
1096
|
+
{
|
1097
|
+
// timestamp-based Packet Delivery mode
|
1098
|
+
|
1099
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
1100
|
+
|
1101
|
+
int32_t tsbpdmode = RTEST(val) ? 1 : 0;
|
1102
|
+
int tsbpdmode_size = sizeof(tsbpdmode);
|
1103
|
+
|
1104
|
+
if (srt_setsockflag(socket->socket, SRTO_TSBPDMODE, &tsbpdmode, tsbpdmode_size) == SRT_ERROR)
|
1105
|
+
{
|
1106
|
+
rbsrt_raise_last_srt_error();
|
1107
|
+
|
1108
|
+
return Qnil;
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
return val;
|
1112
|
+
}
|
1113
|
+
|
1114
|
+
VALUE rbsrt_socket_get_tsbpdmode(VALUE self)
|
1115
|
+
{
|
1116
|
+
// timestamp-based Packet Delivery mode
|
1117
|
+
|
1118
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
1119
|
+
|
1120
|
+
int32_t tsbpdmode;
|
1121
|
+
int tsbpdmode_size;
|
1122
|
+
|
1123
|
+
if (srt_getsockflag(socket->socket, SRTO_TSBPDMODE, &tsbpdmode, &tsbpdmode_size) == SRT_ERROR)
|
1124
|
+
{
|
1125
|
+
rbsrt_raise_last_srt_error();
|
1126
|
+
|
1127
|
+
return Qnil;
|
1128
|
+
}
|
1129
|
+
|
1130
|
+
return tsbpdmode ? Qtrue : Qfalse;
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
|
1134
|
+
|
1135
|
+
#ifndef RBSRT_PASSPHRASE_MIN
|
1136
|
+
#define RBSRT_PASSPHRASE_MIN 10
|
1137
|
+
#endif
|
1138
|
+
|
1139
|
+
#ifndef RBSRT_PASSPHRASE_MAX
|
1140
|
+
#define RBSRT_PASSPHRASE_MAX 79
|
1141
|
+
#endif
|
1142
|
+
|
1143
|
+
VALUE rbsrt_socket_set_passphrase(VALUE self, VALUE passphrase)
|
1144
|
+
{
|
1145
|
+
int passphrase_type = rb_type(passphrase);
|
1146
|
+
char const *passphrase_buf;
|
1147
|
+
int passphrase_size;
|
1148
|
+
|
1149
|
+
switch (passphrase_type)
|
1150
|
+
{
|
1151
|
+
case T_NIL:
|
1152
|
+
passphrase_buf = NULL;
|
1153
|
+
passphrase_size = 0;
|
1154
|
+
break;
|
1155
|
+
|
1156
|
+
case T_STRING:
|
1157
|
+
passphrase_buf = StringValuePtr(passphrase);
|
1158
|
+
|
1159
|
+
// long passphrase_length = rb_str_length(passphrase);
|
1160
|
+
long passphrase_length = strnlen(passphrase_buf, RBSRT_PASSPHRASE_MAX * 2);
|
1161
|
+
passphrase_size = (int)passphrase_length + 1;
|
1162
|
+
|
1163
|
+
if (passphrase_buf == 0)
|
1164
|
+
{
|
1165
|
+
passphrase_buf = NULL;
|
1166
|
+
passphrase_size = 0;
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
else if (passphrase_length != 0 && (passphrase_length < RBSRT_PASSPHRASE_MIN || passphrase_length > RBSRT_PASSPHRASE_MAX))
|
1170
|
+
{
|
1171
|
+
printf("PASSPHASE: %s", passphrase_buf);
|
1172
|
+
rb_raise(rb_eArgError, "passphrase must be between %d and %d characters or empty (got %ld)", RBSRT_PASSPHRASE_MIN, RBSRT_PASSPHRASE_MAX, passphrase_length);
|
1173
|
+
|
1174
|
+
return Qfalse;
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
|
1178
|
+
break;
|
1179
|
+
|
1180
|
+
default:
|
1181
|
+
Check_Type(passphrase, T_STRING);
|
1182
|
+
return Qfalse;
|
1183
|
+
break;
|
1184
|
+
}
|
1185
|
+
|
1186
|
+
RBSRT_SOCKET_BASE_UNWRAP(self, socket);
|
1187
|
+
|
1188
|
+
if (srt_setsockflag(socket->socket, SRTO_PASSPHRASE, passphrase_buf, passphrase_size) == SRT_ERROR)
|
1189
|
+
{
|
1190
|
+
rbsrt_raise_last_srt_error();
|
1191
|
+
|
1192
|
+
return Qfalse;
|
1193
|
+
}
|
1194
|
+
|
1195
|
+
return Qtrue;
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
|
1199
|
+
// MARK: Base Socket API
|
1200
|
+
|
1201
|
+
void rbsrt_socket_base_define_base_api(VALUE klass)
|
1202
|
+
{
|
1203
|
+
rb_define_method(klass, "id", rbsrt_socket_get_id, 0);
|
1204
|
+
|
1205
|
+
rb_define_method(klass, "read_sync=", rbsrt_socket_set_rcvsyn, 1);
|
1206
|
+
rb_define_method(klass, "read_sync?", rbsrt_socket_get_rcvsyn, 0);
|
1207
|
+
rb_alias(klass, rb_intern("rcvsyn="), rb_intern("read_sync="));
|
1208
|
+
rb_alias(klass, rb_intern("rcvsyn?"), rb_intern("read_sync?"));
|
1209
|
+
|
1210
|
+
rb_define_method(klass, "passphrase=", rbsrt_socket_set_passphrase, 1);
|
1211
|
+
rb_alias(klass, rb_intern("password="), rb_intern("passphrase="));
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
void rbsrt_socket_base_define_option_api(VALUE klass)
|
1215
|
+
{
|
1216
|
+
rb_define_method(klass, "write_sync=", rbsrt_socket_set_sndsyn, 1);
|
1217
|
+
rb_define_method(klass, "write_sync?", rbsrt_socket_get_sndsyn, 0);
|
1218
|
+
rb_alias(klass, rb_intern("sndsyn="), rb_intern("write_sync="));
|
1219
|
+
rb_alias(klass, rb_intern("sndsyn?"), rb_intern("write_sync?"));
|
1220
|
+
|
1221
|
+
rb_define_method(klass, "streamid=", rbsrt_socket_set_streamid, 1);
|
1222
|
+
rb_define_method(klass, "streamid", rbsrt_socket_get_streamid, 0);
|
1223
|
+
|
1224
|
+
rb_define_method(klass, "transmission_mode=", rbsrt_socket_set_transtype, 1);
|
1225
|
+
rb_alias(klass, rb_intern("trans_mode="), rb_intern("transmission_mode="));
|
1226
|
+
rb_alias(klass, rb_intern("transtype="), rb_intern("transmission_mode="));
|
1227
|
+
|
1228
|
+
|
1229
|
+
rb_define_method(klass, "timestamp_based_packet_delivery_mode=", rbsrt_socket_set_tsbpdmode, 1);
|
1230
|
+
rb_define_method(klass, "timestamp_based_packet_delivery_mode?", rbsrt_socket_get_tsbpdmode, 0);
|
1231
|
+
rb_alias(klass, rb_intern("tsbpdmode="), rb_intern("timestamp_based_packet_delivery_mode="));
|
1232
|
+
rb_alias(klass, rb_intern("tsbpdmode?"), rb_intern("timestamp_based_packet_delivery_mode?"));
|
1233
|
+
}
|
1234
|
+
|
1235
|
+
void rbsrt_socket_base_define_basic_api(VALUE klass)
|
1236
|
+
{
|
1237
|
+
rb_define_method(klass, "close", rbsrt_socket_close, 0);
|
1238
|
+
}
|
1239
|
+
|
1240
|
+
void rbsrt_socket_base_define_connection_api(VALUE klass)
|
1241
|
+
{
|
1242
|
+
rb_define_method(klass, "connect", rbsrt_socket_connect, 2);
|
1243
|
+
}
|
1244
|
+
|
1245
|
+
void rbsrt_socket_base_define_io_api(VALUE klass)
|
1246
|
+
{
|
1247
|
+
rb_define_method(klass, "recvmsg", rbsrt_socket_recvmsg, 0);
|
1248
|
+
rb_alias(klass, rb_intern("read"), rb_intern("recvmsg"));
|
1249
|
+
|
1250
|
+
rb_define_method(klass, "sendmsg", rbsrt_socket_sendmsg, 1);
|
1251
|
+
rb_alias(klass, rb_intern("write"), rb_intern("sendmsg"));
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
|
1255
|
+
|
1256
|
+
// MARK: - SRT::Socket Class
|
1257
|
+
|
1258
|
+
size_t rbsrt_socket_dsize(const void *socket)
|
1259
|
+
{
|
1260
|
+
RBSRT_DEBUG_PRINT("dsize srt socket");
|
1261
|
+
|
1262
|
+
return sizeof(rbsrt_client_t);
|
1263
|
+
}
|
1264
|
+
|
1265
|
+
void rbsrt_socket_dmark(void *socket)
|
1266
|
+
{
|
1267
|
+
RBSRT_DEBUG_PRINT("dmark srt socket");
|
1268
|
+
}
|
1269
|
+
|
1270
|
+
|
1271
|
+
// MARK: Initializers
|
1272
|
+
|
1273
|
+
void rbsrt_socket_deallocate(rbsrt_socket_t *socket)
|
1274
|
+
{
|
1275
|
+
RBSRT_DEBUG_PRINT("deallocate srt socket");
|
1276
|
+
|
1277
|
+
srt_close(socket->socket); // TODO: Check socket state before closing
|
1278
|
+
|
1279
|
+
free(socket);
|
1280
|
+
}
|
1281
|
+
|
1282
|
+
VALUE rbsrt_socket_allocate(VALUE klass)
|
1283
|
+
{
|
1284
|
+
RBSRT_DEBUG_PRINT("allocate socket");
|
1285
|
+
|
1286
|
+
rbsrt_socket_t *socket = malloc(sizeof(rbsrt_socket_t));
|
1287
|
+
|
1288
|
+
memset(socket, 0, sizeof(rbsrt_socket_t));
|
1289
|
+
|
1290
|
+
return TypedData_Wrap_Struct(klass, &rbsrt_socket_rbtype, socket);
|
1291
|
+
}
|
1292
|
+
|
1293
|
+
VALUE rbsrt_socket_initialize(VALUE self)
|
1294
|
+
{
|
1295
|
+
RBSRT_DEBUG_PRINT("initialize socket");
|
1296
|
+
|
1297
|
+
RBSRT_SOCKET_UNWRAP(self, socket);
|
1298
|
+
|
1299
|
+
socket->socket = srt_create_socket();
|
1300
|
+
|
1301
|
+
int livemode = SRTT_LIVE;
|
1302
|
+
|
1303
|
+
srt_setsockflag(socket->socket, SRTO_TRANSTYPE, &livemode, sizeof(livemode)); // set live mode
|
1304
|
+
|
1305
|
+
return self;
|
1306
|
+
}
|
1307
|
+
|
1308
|
+
|
1309
|
+
|
1310
|
+
// MARK: - SRT::Connection Class
|
1311
|
+
|
1312
|
+
// MARK: Ruby Type Helpers
|
1313
|
+
|
1314
|
+
size_t rbsrt_connection_dsize(const void *server)
|
1315
|
+
{
|
1316
|
+
RBSRT_DEBUG_PRINT("connection dsize");
|
1317
|
+
|
1318
|
+
return sizeof(rbsrt_connection_t);
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
void rbsrt_connection_dmark(void *data)
|
1322
|
+
{
|
1323
|
+
RBSRT_DEBUG_PRINT("connection mark");
|
1324
|
+
|
1325
|
+
rbsrt_connection_t *connection = (rbsrt_connection_t *)data;
|
1326
|
+
|
1327
|
+
if (connection->at_data_block)
|
1328
|
+
{
|
1329
|
+
rb_gc_mark(connection->at_data_block);
|
1330
|
+
}
|
1331
|
+
|
1332
|
+
if (connection->at_close_block)
|
1333
|
+
{
|
1334
|
+
rb_gc_mark(connection->at_close_block);
|
1335
|
+
}
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
|
1339
|
+
// MARK: Initializers
|
1340
|
+
|
1341
|
+
VALUE rbsrt_connection_allocate(VALUE klass)
|
1342
|
+
{
|
1343
|
+
RBSRT_DEBUG_PRINT("connection allocate");
|
1344
|
+
|
1345
|
+
rbsrt_connection_t *connection = malloc(sizeof(rbsrt_connection_t));
|
1346
|
+
|
1347
|
+
memset(connection, 0, sizeof(rbsrt_connection_t));
|
1348
|
+
|
1349
|
+
return TypedData_Wrap_Struct(klass, &rbsrt_connection_rbtype, connection);
|
1350
|
+
}
|
1351
|
+
|
1352
|
+
void rbsrt_connection_deallocate(rbsrt_connection_t *connection)
|
1353
|
+
{
|
1354
|
+
RBSRT_DEBUG_PRINT("connection deallocate");
|
1355
|
+
|
1356
|
+
free(connection);
|
1357
|
+
}
|
1358
|
+
|
1359
|
+
|
1360
|
+
// MARK: API
|
1361
|
+
|
1362
|
+
VALUE rbsrt_connection_set_at_data_block(VALUE self)
|
1363
|
+
{
|
1364
|
+
RBSRT_DEBUG_PRINT("connection set data block");
|
1365
|
+
|
1366
|
+
rb_need_block();
|
1367
|
+
|
1368
|
+
RBSRT_CONNECTION_UNWRAP(self, connection);
|
1369
|
+
|
1370
|
+
connection->at_data_block = rb_block_proc();
|
1371
|
+
|
1372
|
+
return Qtrue;
|
1373
|
+
}
|
1374
|
+
|
1375
|
+
VALUE rbsrt_connection_set_at_close_block(VALUE self)
|
1376
|
+
{
|
1377
|
+
RBSRT_DEBUG_PRINT("connection set close block");
|
1378
|
+
|
1379
|
+
rb_need_block();
|
1380
|
+
|
1381
|
+
RBSRT_CONNECTION_UNWRAP(self, connection);
|
1382
|
+
|
1383
|
+
connection->at_close_block = rb_block_proc();
|
1384
|
+
|
1385
|
+
return Qtrue;
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
// MARK: - SRT::Server Class
|
1389
|
+
|
1390
|
+
// MARK: Ruby Type Helpers
|
1391
|
+
|
1392
|
+
size_t rbsrt_server_dsize(const void *server)
|
1393
|
+
{
|
1394
|
+
RBSRT_DEBUG_PRINT("server dsize");
|
1395
|
+
|
1396
|
+
return sizeof(rbsrt_server_t);
|
1397
|
+
}
|
1398
|
+
|
1399
|
+
void rbsrt_server_dmark(void *data)
|
1400
|
+
{
|
1401
|
+
RBSRT_DEBUG_PRINT("server mark");
|
1402
|
+
|
1403
|
+
rbsrt_server_t *server = (rbsrt_server_t *)data;
|
1404
|
+
|
1405
|
+
if (server->acceptor_block)
|
1406
|
+
{
|
1407
|
+
rb_gc_mark(server->acceptor_block);
|
1408
|
+
}
|
1409
|
+
}
|
1410
|
+
|
1411
|
+
|
1412
|
+
// MARK: Utils
|
1413
|
+
|
1414
|
+
#define RBSRT_SERVER_NUM_CONNECTIONS(server) (size_t)atomic_load(&server->num_connections)
|
1415
|
+
|
1416
|
+
|
1417
|
+
// MARK: SRT
|
1418
|
+
|
1419
|
+
int rbsrt_server_listen_callback(void* context, SRTSOCKET remote_socket, int hs_version, const struct sockaddr* peeraddr, const char* streamid)
|
1420
|
+
{
|
1421
|
+
// TODO: Call into ruby and allow pre-setup of the socket
|
1422
|
+
|
1423
|
+
return 1;
|
1424
|
+
}
|
1425
|
+
|
1426
|
+
|
1427
|
+
// MARK: Initializers
|
1428
|
+
|
1429
|
+
void rbsrt_server_deallocate(rbsrt_server_t *server)
|
1430
|
+
{
|
1431
|
+
RBSRT_DEBUG_PRINT("deallocate srt server");
|
1432
|
+
|
1433
|
+
SRT_SOCKSTATUS status = srt_getsockstate(server->socket);
|
1434
|
+
|
1435
|
+
if (status != SRTS_CLOSED || status != SRTS_CLOSING)
|
1436
|
+
{
|
1437
|
+
srt_close(server->socket);
|
1438
|
+
}
|
1439
|
+
|
1440
|
+
free(server);
|
1441
|
+
}
|
1442
|
+
|
1443
|
+
VALUE rbsrt_server_allocate(VALUE klass)
|
1444
|
+
{
|
1445
|
+
RBSRT_DEBUG_PRINT("server allocate");
|
1446
|
+
|
1447
|
+
rbsrt_server_t *server = malloc(sizeof(rbsrt_server_t));
|
1448
|
+
|
1449
|
+
memset(server, 0, sizeof(rbsrt_server_t));
|
1450
|
+
|
1451
|
+
return TypedData_Wrap_Struct(klass, &rbsrt_server_rbtype, server);
|
1452
|
+
}
|
1453
|
+
|
1454
|
+
VALUE rbsrt_server_initialize(VALUE self, VALUE address, VALUE port)
|
1455
|
+
{
|
1456
|
+
RBSRT_DEBUG_PRINT("server initialize");
|
1457
|
+
|
1458
|
+
rbsrt_server_t *server;
|
1459
|
+
int status;
|
1460
|
+
struct sockaddr_in sa;
|
1461
|
+
int livemode = SRTT_LIVE;
|
1462
|
+
int no = 1;
|
1463
|
+
|
1464
|
+
Check_Type(address, T_STRING);
|
1465
|
+
Check_Type(port, T_STRING);
|
1466
|
+
|
1467
|
+
TypedData_Get_Struct(self, rbsrt_server_t, &rbsrt_server_rbtype, server);
|
1468
|
+
|
1469
|
+
// Initialize struct
|
1470
|
+
|
1471
|
+
atomic_init(&server->num_connections, 0);
|
1472
|
+
|
1473
|
+
|
1474
|
+
// Ruby API
|
1475
|
+
|
1476
|
+
VALUE connections_by_socket = rb_hash_new();
|
1477
|
+
|
1478
|
+
rb_hash_clear(connections_by_socket);
|
1479
|
+
|
1480
|
+
rb_ivar_set(self, rb_intern("@connections_by_socket"), connections_by_socket);
|
1481
|
+
|
1482
|
+
|
1483
|
+
// create socket
|
1484
|
+
|
1485
|
+
server->socket = srt_create_socket();
|
1486
|
+
|
1487
|
+
if (server->socket == SRT_ERROR)
|
1488
|
+
{
|
1489
|
+
rb_raise(rb_eStandardError, "%s", srt_getlasterror_str());
|
1490
|
+
|
1491
|
+
return Qfalse;
|
1492
|
+
}
|
1493
|
+
|
1494
|
+
|
1495
|
+
// get address info
|
1496
|
+
|
1497
|
+
sa.sin_family = AF_INET;
|
1498
|
+
sa.sin_port = htons(atoi(StringValuePtr(port)));
|
1499
|
+
|
1500
|
+
if (inet_pton(AF_INET, StringValuePtr(address), &sa.sin_addr) != 1)
|
1501
|
+
{
|
1502
|
+
rb_raise(rb_eArgError, "bad adddress: %s", strerror(errno));
|
1503
|
+
|
1504
|
+
return Qfalse;
|
1505
|
+
}
|
1506
|
+
|
1507
|
+
|
1508
|
+
// set up socket
|
1509
|
+
|
1510
|
+
srt_setsockflag(server->socket, SRTO_TRANSTYPE, &livemode, sizeof(livemode)); // set live mode
|
1511
|
+
srt_setsockflag(server->socket, SRTO_RCVSYN, &no, sizeof(no)); // non-blocking mode
|
1512
|
+
srt_setsockflag(server->socket, SRTO_SNDSYN, &no, sizeof(no));
|
1513
|
+
|
1514
|
+
|
1515
|
+
// set up callback
|
1516
|
+
|
1517
|
+
srt_listen_callback(server->socket, rbsrt_server_listen_callback, (void *)self);
|
1518
|
+
|
1519
|
+
|
1520
|
+
// bind server
|
1521
|
+
|
1522
|
+
status = srt_bind(server->socket, (struct sockaddr *)&sa, sizeof(sa));
|
1523
|
+
|
1524
|
+
if (status == SRT_ERROR)
|
1525
|
+
{
|
1526
|
+
rb_raise(rb_eStandardError, "%s", srt_getlasterror_str());
|
1527
|
+
|
1528
|
+
return Qfalse;
|
1529
|
+
}
|
1530
|
+
|
1531
|
+
|
1532
|
+
// listen
|
1533
|
+
|
1534
|
+
status = srt_listen(server->socket, 6); // TODO: Pass backlog size
|
1535
|
+
|
1536
|
+
if (status == SRT_ERROR)
|
1537
|
+
{
|
1538
|
+
rb_raise(rb_eStandardError, "%s", srt_getlasterror_str());
|
1539
|
+
|
1540
|
+
return Qfalse;
|
1541
|
+
}
|
1542
|
+
|
1543
|
+
return self;
|
1544
|
+
}
|
1545
|
+
|
1546
|
+
VALUE rbsrt_server_close(VALUE self)
|
1547
|
+
{
|
1548
|
+
RBSRT_DEBUG_PRINT("server close");
|
1549
|
+
|
1550
|
+
RBSRT_SERVER_UNWRAP(self, server);
|
1551
|
+
|
1552
|
+
if (srt_close(server->socket) == SRT_ERROR)
|
1553
|
+
{
|
1554
|
+
rbsrt_raise_last_srt_error();
|
1555
|
+
}
|
1556
|
+
|
1557
|
+
server->flags &= ~ (RBSRT_SERVER_ACCEPTING | RBSRT_SERVER_BOUND | RBSRT_SERVER_LISTENING);
|
1558
|
+
server->flags |= RBSRT_SERVER_CLOSED;
|
1559
|
+
|
1560
|
+
return Qnil;
|
1561
|
+
}
|
1562
|
+
|
1563
|
+
struct rbsrt_server_epoll_wait_args
|
1564
|
+
{
|
1565
|
+
rbsrt_server_t *server;
|
1566
|
+
int64_t timeout;
|
1567
|
+
int num_events;
|
1568
|
+
SRT_EPOLL_EVENT *events;
|
1569
|
+
};
|
1570
|
+
|
1571
|
+
void *rbsrt_server_epoll_wait(void *args)
|
1572
|
+
{
|
1573
|
+
struct rbsrt_server_epoll_wait_args *arg = args;
|
1574
|
+
|
1575
|
+
int num_events = srt_epoll_uwait(arg->server->epollid, arg->events, arg->num_events, arg->timeout);
|
1576
|
+
|
1577
|
+
return (void *)(uintptr_t)num_events;
|
1578
|
+
}
|
1579
|
+
|
1580
|
+
VALUE rbsrt_server_connection_count(VALUE self)
|
1581
|
+
{
|
1582
|
+
RBSRT_SERVER_UNWRAP(self, server);
|
1583
|
+
|
1584
|
+
return SIZET2NUM(RBSRT_SERVER_NUM_CONNECTIONS(server));
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
VALUE rbsrt_server_start(VALUE self)
|
1588
|
+
{
|
1589
|
+
RBSRT_DEBUG_PRINT("server start");
|
1590
|
+
|
1591
|
+
rb_need_block();
|
1592
|
+
|
1593
|
+
RBSRT_SERVER_UNWRAP(self, server);
|
1594
|
+
|
1595
|
+
// rb_iv_set(self, rb_intern("acceptor_block"), rb_block_proc());
|
1596
|
+
|
1597
|
+
server->acceptor_block = rb_block_proc();
|
1598
|
+
|
1599
|
+
server->epollid = srt_epoll_create();
|
1600
|
+
|
1601
|
+
int event_types = SRT_EPOLL_IN;
|
1602
|
+
|
1603
|
+
srt_epoll_add_usock(server->epollid, server->socket, &event_types);
|
1604
|
+
|
1605
|
+
SRT_EPOLL_EVENT events[1024];
|
1606
|
+
|
1607
|
+
struct rbsrt_server_epoll_wait_args args = {
|
1608
|
+
.server = server,
|
1609
|
+
.timeout = 100,
|
1610
|
+
.num_events = 1024,
|
1611
|
+
.events = events
|
1612
|
+
};
|
1613
|
+
|
1614
|
+
struct sockaddr_storage remote_address;
|
1615
|
+
int addr_size = sizeof(remote_address);
|
1616
|
+
int remote_fd;
|
1617
|
+
int running = 1;
|
1618
|
+
|
1619
|
+
VALUE connections_by_socket = rb_ivar_get(self, rb_intern("@connections_by_socket"));
|
1620
|
+
|
1621
|
+
while (running)
|
1622
|
+
{
|
1623
|
+
int num_events = (int)(uintptr_t)rb_thread_call_without_gvl(rbsrt_server_epoll_wait, &args, RUBY_UBF_IO, 0);
|
1624
|
+
|
1625
|
+
if (num_events <= 0)
|
1626
|
+
{
|
1627
|
+
continue; // timeout
|
1628
|
+
}
|
1629
|
+
|
1630
|
+
int read_buf_size = RBSRT_PAYLOAD_SIZE * 8;
|
1631
|
+
char read_buf[read_buf_size];
|
1632
|
+
int nbytes;
|
1633
|
+
|
1634
|
+
// SRT_MSGCTRL msgctl;
|
1635
|
+
SRT_EPOLL_EVENT *event;
|
1636
|
+
SRTSOCKET sock;
|
1637
|
+
SRT_SOCKSTATUS status;
|
1638
|
+
rbsrt_connection_t *connection;
|
1639
|
+
|
1640
|
+
VALUE rb_connection;
|
1641
|
+
|
1642
|
+
int no = 0;
|
1643
|
+
int no_size = sizeof(no);
|
1644
|
+
int connection_epoll_events = SRT_EPOLL_OUT | SRT_EPOLL_IN | SRT_EPOLL_ERR;
|
1645
|
+
|
1646
|
+
for (int i = 0; i < num_events; i++)
|
1647
|
+
{
|
1648
|
+
event = &args.events[i];
|
1649
|
+
sock = event->fd;
|
1650
|
+
status = srt_getsockstate(sock);
|
1651
|
+
|
1652
|
+
switch (status)
|
1653
|
+
{
|
1654
|
+
// accept connections
|
1655
|
+
case SRTS_LISTENING:
|
1656
|
+
|
1657
|
+
remote_fd = srt_accept(sock, (struct sockaddr *)&remote_address, &addr_size);
|
1658
|
+
|
1659
|
+
srt_setsockflag(remote_fd, SRTO_RCVSYN, &no, no_size);
|
1660
|
+
srt_setsockflag(remote_fd, SRTO_SNDSYN, &no, no_size);
|
1661
|
+
|
1662
|
+
connection = malloc(sizeof(rbsrt_connection_t));
|
1663
|
+
|
1664
|
+
memset(connection, 0, sizeof(rbsrt_connection_t));
|
1665
|
+
|
1666
|
+
rb_connection = TypedData_Make_Struct(mSRTConnectionKlass, rbsrt_connection_t, &rbsrt_connection_rbtype, connection);
|
1667
|
+
|
1668
|
+
connection->socket = remote_fd;
|
1669
|
+
|
1670
|
+
VALUE should_accept = rb_funcall_with_block(self, rb_intern("instance_exec"), 1, &rb_connection, server->acceptor_block);
|
1671
|
+
|
1672
|
+
if (RTEST(should_accept))
|
1673
|
+
{
|
1674
|
+
srt_epoll_add_usock(server->epollid, connection->socket, &connection_epoll_events);
|
1675
|
+
|
1676
|
+
atomic_fetch_add(&server->num_connections, 1);
|
1677
|
+
|
1678
|
+
rb_hash_aset(connections_by_socket, INT2FIX(connection->socket), rb_connection);
|
1679
|
+
}
|
1680
|
+
|
1681
|
+
else
|
1682
|
+
{
|
1683
|
+
atomic_fetch_sub(&server->num_connections, 1);
|
1684
|
+
|
1685
|
+
srt_close(remote_fd);
|
1686
|
+
}
|
1687
|
+
|
1688
|
+
break;
|
1689
|
+
|
1690
|
+
case SRTS_CLOSED:
|
1691
|
+
case SRTS_NONEXIST:
|
1692
|
+
case SRTS_BROKEN:
|
1693
|
+
RBSRT_DEBUG_PRINT("removing connection with socket: %d", sock);
|
1694
|
+
|
1695
|
+
srt_epoll_remove_usock(server->epollid, sock);
|
1696
|
+
|
1697
|
+
rb_connection = rb_hash_delete(connections_by_socket, INT2FIX(sock));
|
1698
|
+
|
1699
|
+
if (RTEST(rb_connection))
|
1700
|
+
{
|
1701
|
+
if (atomic_fetch_sub(&server->num_connections, 1) == 0)
|
1702
|
+
{
|
1703
|
+
DEBUG_ERROR_PRINT("removed to many connections");
|
1704
|
+
}
|
1705
|
+
|
1706
|
+
RBSRT_DEBUG_PRINT("remove connection with socket %d, now %lu sockets", sock, RBSRT_SERVER_NUM_CONNECTIONS(server));
|
1707
|
+
|
1708
|
+
RBSRT_CONNECTION_UNWRAP(rb_connection, removed_connection);
|
1709
|
+
|
1710
|
+
if (removed_connection->at_close_block)
|
1711
|
+
{
|
1712
|
+
rb_funcall(removed_connection->at_close_block, rb_intern("call"), 0);
|
1713
|
+
|
1714
|
+
removed_connection->at_close_block = 0;
|
1715
|
+
}
|
1716
|
+
|
1717
|
+
if (removed_connection->at_data_block)
|
1718
|
+
{
|
1719
|
+
removed_connection->at_data_block = 0;
|
1720
|
+
}
|
1721
|
+
}
|
1722
|
+
|
1723
|
+
break;
|
1724
|
+
|
1725
|
+
case SRTS_CONNECTED:
|
1726
|
+
if (event->events & SRT_EPOLL_IN)
|
1727
|
+
{
|
1728
|
+
RBSRT_DEBUG_PRINT("will read from socket %d (max bytes %d)", sock, read_buf_size);
|
1729
|
+
|
1730
|
+
nbytes = srt_recvmsg2(event->fd, read_buf, read_buf_size, NULL);
|
1731
|
+
|
1732
|
+
if (nbytes == SRT_ERROR)
|
1733
|
+
{
|
1734
|
+
RBSRT_DEBUG_PRINT("failed to read from socket %d: %s", sock, srt_getlasterror_str());
|
1735
|
+
|
1736
|
+
break;
|
1737
|
+
}
|
1738
|
+
|
1739
|
+
if (nbytes > 0)
|
1740
|
+
{
|
1741
|
+
RBSRT_DEBUG_PRINT("received %d bytes from socket %d", nbytes, sock);
|
1742
|
+
|
1743
|
+
rb_connection = rb_hash_lookup(connections_by_socket, INT2FIX(sock));
|
1744
|
+
|
1745
|
+
if (RTEST(rb_connection))
|
1746
|
+
{
|
1747
|
+
RBSRT_DEBUG_PRINT("found connection for socket %d", sock);
|
1748
|
+
|
1749
|
+
TypedData_Get_Struct(rb_connection, rbsrt_connection_t, &rbsrt_connection_rbtype, connection);
|
1750
|
+
|
1751
|
+
if (connection->at_data_block)
|
1752
|
+
{
|
1753
|
+
RBSRT_DEBUG_PRINT("found data handler for socket %d", sock);
|
1754
|
+
|
1755
|
+
VALUE data = rb_str_new(read_buf, nbytes);
|
1756
|
+
|
1757
|
+
rb_funcall(connection->at_data_block, rb_intern("call"), 1, data);
|
1758
|
+
}
|
1759
|
+
}
|
1760
|
+
}
|
1761
|
+
}
|
1762
|
+
|
1763
|
+
// TODO: Handle other events
|
1764
|
+
break;
|
1765
|
+
|
1766
|
+
default:
|
1767
|
+
break;
|
1768
|
+
}
|
1769
|
+
}
|
1770
|
+
}
|
1771
|
+
|
1772
|
+
return Qtrue;
|
1773
|
+
}
|
1774
|
+
|
1775
|
+
|
1776
|
+
// MARK: Connections
|
1777
|
+
|
1778
|
+
VALUE rbsrt_server_accept(VALUE self)
|
1779
|
+
{
|
1780
|
+
RBSRT_DEBUG_PRINT("server accept");
|
1781
|
+
|
1782
|
+
RBSRT_SERVER_UNWRAP(self, server);
|
1783
|
+
|
1784
|
+
// Data_Get_Struct(self, rbsrt_server_t, server);
|
1785
|
+
TypedData_Get_Struct(self, rbsrt_server_t, &rbsrt_server_rbtype, server);
|
1786
|
+
|
1787
|
+
struct sockaddr_storage remote_address;
|
1788
|
+
int addr_size = sizeof(remote_address);
|
1789
|
+
|
1790
|
+
SRTSOCKET socket = srt_accept(server->socket, (struct sockaddr *)&remote_address, &addr_size);
|
1791
|
+
|
1792
|
+
VALUE rbclient = rb_class_new_instance(0, NULL, mSRTClientKlass);
|
1793
|
+
|
1794
|
+
rbsrt_client_t *client;
|
1795
|
+
|
1796
|
+
Data_Get_Struct(rbclient, rbsrt_client_t, client);
|
1797
|
+
|
1798
|
+
client->socket = socket;
|
1799
|
+
|
1800
|
+
client->flags |= RBSRT_CLIENT_CONNECTED;
|
1801
|
+
|
1802
|
+
return rbclient;
|
1803
|
+
}
|
1804
|
+
|
1805
|
+
|
1806
|
+
|
1807
|
+
// MARK: - SRT::Client Class
|
1808
|
+
|
1809
|
+
// MARK: Ruby Type Helpers
|
1810
|
+
|
1811
|
+
size_t rbsrt_client_dsize(const void *client)
|
1812
|
+
{
|
1813
|
+
RBSRT_DEBUG_PRINT("dsize srt client");
|
1814
|
+
|
1815
|
+
return sizeof(rbsrt_client_t);
|
1816
|
+
}
|
1817
|
+
|
1818
|
+
void rbsrt_client_dmark(void *client)
|
1819
|
+
{
|
1820
|
+
RBSRT_DEBUG_PRINT("dmark srt client");
|
1821
|
+
}
|
1822
|
+
|
1823
|
+
|
1824
|
+
// MARK: Initializers
|
1825
|
+
|
1826
|
+
void rbsrt_client_deallocate(rbsrt_client_t *client)
|
1827
|
+
{
|
1828
|
+
RBSRT_DEBUG_PRINT("deallocate srt client");
|
1829
|
+
|
1830
|
+
SRT_SOCKSTATUS status = srt_getsockstate(client->socket);
|
1831
|
+
|
1832
|
+
switch (status)
|
1833
|
+
{
|
1834
|
+
|
1835
|
+
case SRTS_CONNECTED:
|
1836
|
+
case SRTS_CONNECTING:
|
1837
|
+
case SRTS_OPENED:
|
1838
|
+
srt_close(client->socket);
|
1839
|
+
|
1840
|
+
break;
|
1841
|
+
|
1842
|
+
default:
|
1843
|
+
break;
|
1844
|
+
}
|
1845
|
+
|
1846
|
+
free(client);
|
1847
|
+
}
|
1848
|
+
|
1849
|
+
VALUE rbsrt_client_allocate(VALUE klass)
|
1850
|
+
{
|
1851
|
+
RBSRT_DEBUG_PRINT("allocate client");
|
1852
|
+
|
1853
|
+
rbsrt_client_t *client = malloc(sizeof(rbsrt_client_t));
|
1854
|
+
|
1855
|
+
memset(client, 0, sizeof(rbsrt_client_t));
|
1856
|
+
|
1857
|
+
return TypedData_Wrap_Struct(klass, &rbsrt_client_rbtype, client);
|
1858
|
+
}
|
1859
|
+
|
1860
|
+
VALUE rbsrt_client_initialize(VALUE self)
|
1861
|
+
{
|
1862
|
+
RBSRT_DEBUG_PRINT("initialize client");
|
1863
|
+
|
1864
|
+
RBSRT_CLIENT_UNWRAP(self, client);
|
1865
|
+
|
1866
|
+
client->socket = srt_create_socket();
|
1867
|
+
|
1868
|
+
return self;
|
1869
|
+
}
|
1870
|
+
|
1871
|
+
|
1872
|
+
// MARK: - SRT::Poll Klass
|
1873
|
+
|
1874
|
+
size_t rbsrt_poll_dsize(const void *poll)
|
1875
|
+
{
|
1876
|
+
return sizeof(rbsrt_poll_t);
|
1877
|
+
}
|
1878
|
+
|
1879
|
+
void rbsrt_poll_dmark(void *data)
|
1880
|
+
{
|
1881
|
+
rbsrt_poll_t *poll = (rbsrt_poll_t *)data;
|
1882
|
+
|
1883
|
+
if (poll->sockets_by_id)
|
1884
|
+
{
|
1885
|
+
rb_gc_mark(poll->sockets_by_id);
|
1886
|
+
}
|
1887
|
+
}
|
1888
|
+
|
1889
|
+
void rbsrt_poll_deallocate(rbsrt_poll_t *poll)
|
1890
|
+
{
|
1891
|
+
RBSRT_DEBUG_PRINT("deallocate poll");
|
1892
|
+
|
1893
|
+
srt_epoll_release(poll->epollid);
|
1894
|
+
|
1895
|
+
free(poll);
|
1896
|
+
}
|
1897
|
+
|
1898
|
+
int rbsrt_epoll_event_with_splat(VALUE splat, long splat_len)
|
1899
|
+
{
|
1900
|
+
int events = 0;
|
1901
|
+
|
1902
|
+
for (long i = 0; i < splat_len; i++)
|
1903
|
+
{
|
1904
|
+
VALUE event_type = rb_ary_entry(splat, i);
|
1905
|
+
|
1906
|
+
ID event_id = rb_to_id(event_type);
|
1907
|
+
|
1908
|
+
if (event_id == rb_intern("in") || event_id == rb_intern("read"))
|
1909
|
+
{
|
1910
|
+
RBSRT_DEBUG_PRINT("poll add SRT_EPOLL_IN");
|
1911
|
+
|
1912
|
+
events |= SRT_EPOLL_IN;
|
1913
|
+
}
|
1914
|
+
|
1915
|
+
else if (event_id == rb_intern("out") || event_id == rb_intern("write"))
|
1916
|
+
{
|
1917
|
+
RBSRT_DEBUG_PRINT("poll add SRT_EPOLL_OUT");
|
1918
|
+
|
1919
|
+
events |= SRT_EPOLL_OUT;
|
1920
|
+
}
|
1921
|
+
|
1922
|
+
else if (event_id == rb_intern("err") || event_id == rb_intern("error"))
|
1923
|
+
{
|
1924
|
+
RBSRT_DEBUG_PRINT("poll add SRT_EPOLL_ERR");
|
1925
|
+
|
1926
|
+
events |= SRT_EPOLL_ERR;
|
1927
|
+
}
|
1928
|
+
|
1929
|
+
else if (event_id == rb_intern("et") || event_id == rb_intern("edge"))
|
1930
|
+
{
|
1931
|
+
RBSRT_DEBUG_PRINT("poll add SRT_EPOLL_ET");
|
1932
|
+
|
1933
|
+
events |= SRT_EPOLL_ET;
|
1934
|
+
}
|
1935
|
+
|
1936
|
+
else
|
1937
|
+
{
|
1938
|
+
rb_raise(rb_eArgError, "poll event must be one of: :in, :out, :err, :edge");
|
1939
|
+
}
|
1940
|
+
}
|
1941
|
+
|
1942
|
+
return events;
|
1943
|
+
}
|
1944
|
+
|
1945
|
+
VALUE rbsrt_poll_allocate(VALUE klass)
|
1946
|
+
{
|
1947
|
+
RBSRT_DEBUG_PRINT("allocate poll");
|
1948
|
+
|
1949
|
+
rbsrt_poll_t *poll = malloc(sizeof(rbsrt_poll_t));
|
1950
|
+
|
1951
|
+
memset(poll, 0, sizeof(rbsrt_poll_t));
|
1952
|
+
|
1953
|
+
return TypedData_Wrap_Struct(klass, &rbsrt_poll_rbtype, poll);
|
1954
|
+
}
|
1955
|
+
|
1956
|
+
VALUE rbsrt_poll_initialize(VALUE self)
|
1957
|
+
{
|
1958
|
+
RBSRT_DEBUG_PRINT("initialize poll");
|
1959
|
+
|
1960
|
+
RBSRT_POLL_UNWRAP(self, poll);
|
1961
|
+
|
1962
|
+
poll->epollid = srt_epoll_create();
|
1963
|
+
|
1964
|
+
VALUE objects_by_socket = rb_hash_new();
|
1965
|
+
|
1966
|
+
rb_hash_clear(objects_by_socket);
|
1967
|
+
|
1968
|
+
rb_ivar_set(self, rb_intern("@sockets"), objects_by_socket);
|
1969
|
+
|
1970
|
+
return self;
|
1971
|
+
}
|
1972
|
+
|
1973
|
+
VALUE rbsrt_poll_remove_socket(VALUE self, VALUE socket_to_remove)
|
1974
|
+
{
|
1975
|
+
RBSRT_DEBUG_PRINT("poll remove socket");
|
1976
|
+
|
1977
|
+
RBSRT_POLL_UNWRAP(self, poll);
|
1978
|
+
|
1979
|
+
RBSRT_SOCKET_BASE_UNWRAP(socket_to_remove, socket);
|
1980
|
+
|
1981
|
+
VALUE sockets = rb_ivar_get(self, rb_intern("@sockets"));
|
1982
|
+
|
1983
|
+
VALUE removed_socket = rb_hash_delete(sockets, INT2FIX(socket->socket));
|
1984
|
+
|
1985
|
+
if (srt_epoll_remove_usock(poll->epollid, socket->socket) == SRT_ERROR)
|
1986
|
+
{
|
1987
|
+
rbsrt_raise_last_srt_error();
|
1988
|
+
}
|
1989
|
+
|
1990
|
+
return removed_socket;
|
1991
|
+
}
|
1992
|
+
|
1993
|
+
VALUE rbsrt_poll_add_socket(int argc, VALUE* argv, VALUE self)
|
1994
|
+
{
|
1995
|
+
RBSRT_DEBUG_PRINT("poll add socket");
|
1996
|
+
|
1997
|
+
RBSRT_POLL_UNWRAP(self, poll);
|
1998
|
+
|
1999
|
+
VALUE arg1;
|
2000
|
+
VALUE splat;
|
2001
|
+
|
2002
|
+
rb_scan_args(argc, argv, "1*", &arg1, &splat);
|
2003
|
+
|
2004
|
+
RBSRT_SOCKET_BASE_UNWRAP(arg1, socket);
|
2005
|
+
|
2006
|
+
int events = rbsrt_epoll_event_with_splat(splat, rb_array_len(splat));
|
2007
|
+
|
2008
|
+
if (srt_epoll_add_usock(poll->epollid, socket->socket, &events) == SRT_ERROR)
|
2009
|
+
{
|
2010
|
+
rbsrt_raise_last_srt_error();
|
2011
|
+
}
|
2012
|
+
|
2013
|
+
VALUE sockets = rb_ivar_get(self, rb_intern("@sockets"));
|
2014
|
+
|
2015
|
+
rb_hash_aset(sockets, INT2FIX(socket->socket), arg1);
|
2016
|
+
|
2017
|
+
return self;
|
2018
|
+
}
|
2019
|
+
|
2020
|
+
VALUE rbsrt_poll_update_socket(int argc, VALUE* argv, VALUE self)
|
2021
|
+
{
|
2022
|
+
RBSRT_DEBUG_PRINT("poll update socket");
|
2023
|
+
|
2024
|
+
RBSRT_POLL_UNWRAP(self, poll);
|
2025
|
+
|
2026
|
+
VALUE arg1;
|
2027
|
+
VALUE splat;
|
2028
|
+
|
2029
|
+
rb_scan_args(argc, argv, "1*", &arg1, &splat);
|
2030
|
+
|
2031
|
+
int events = rbsrt_epoll_event_with_splat(splat, rb_array_len(splat));
|
2032
|
+
|
2033
|
+
RBSRT_SOCKET_BASE_UNWRAP(arg1, socket);
|
2034
|
+
|
2035
|
+
if (srt_epoll_update_usock(poll->epollid, socket->socket, &events) == SRT_ERROR)
|
2036
|
+
{
|
2037
|
+
rbsrt_raise_last_srt_error();
|
2038
|
+
}
|
2039
|
+
|
2040
|
+
return Qnil;
|
2041
|
+
}
|
2042
|
+
|
2043
|
+
typedef struct RBSRTPollWaitArg
|
2044
|
+
{
|
2045
|
+
int epollid;
|
2046
|
+
int timeout;
|
2047
|
+
int num_sockets;
|
2048
|
+
int num_events;
|
2049
|
+
SRT_EPOLL_EVENT *events;
|
2050
|
+
} rbsrt_poll_wait_arg_t;
|
2051
|
+
|
2052
|
+
void *rbsrt_poll_wait_without_gvl(void *context)
|
2053
|
+
{
|
2054
|
+
rbsrt_poll_wait_arg_t *arg = (rbsrt_poll_wait_arg_t *)context;
|
2055
|
+
|
2056
|
+
arg->num_events = srt_epoll_uwait(arg->epollid, arg->events, arg->num_sockets, arg->timeout);
|
2057
|
+
|
2058
|
+
return arg;
|
2059
|
+
}
|
2060
|
+
|
2061
|
+
VALUE rbsrt_poll_wait(int argc, VALUE* argv, VALUE self)
|
2062
|
+
{
|
2063
|
+
RBSRT_DEBUG_PRINT("poll wait");
|
2064
|
+
|
2065
|
+
RBSRT_POLL_UNWRAP(self, poll);
|
2066
|
+
|
2067
|
+
VALUE timeout;
|
2068
|
+
VALUE block;
|
2069
|
+
|
2070
|
+
rb_scan_args(argc, argv, "01&", &timeout, &block);
|
2071
|
+
|
2072
|
+
int epoll_timeout;
|
2073
|
+
|
2074
|
+
if (!NIL_P(timeout))
|
2075
|
+
{
|
2076
|
+
Check_Type(timeout, T_FIXNUM);
|
2077
|
+
|
2078
|
+
epoll_timeout = FIX2INT(timeout);
|
2079
|
+
}
|
2080
|
+
|
2081
|
+
else
|
2082
|
+
{
|
2083
|
+
epoll_timeout = -1;
|
2084
|
+
}
|
2085
|
+
|
2086
|
+
VALUE sockets = rb_ivar_get(self, rb_intern("@sockets"));
|
2087
|
+
int num_sockets = FIX2INT(rb_hash_size(sockets));
|
2088
|
+
|
2089
|
+
SRT_EPOLL_EVENT events[num_sockets < 8 ? 8 : num_sockets + 8];
|
2090
|
+
|
2091
|
+
VALUE readables = rb_ary_new();
|
2092
|
+
VALUE writables = rb_ary_new();
|
2093
|
+
VALUE errors = rb_ary_new();
|
2094
|
+
|
2095
|
+
rbsrt_poll_wait_arg_t arg = {
|
2096
|
+
.epollid = poll->epollid,
|
2097
|
+
.timeout = epoll_timeout,
|
2098
|
+
.num_sockets = num_sockets,
|
2099
|
+
.num_events = 0,
|
2100
|
+
.events = events
|
2101
|
+
};
|
2102
|
+
|
2103
|
+
rb_thread_call_without_gvl(rbsrt_poll_wait_without_gvl, &arg, RUBY_UBF_IO, NULL);
|
2104
|
+
|
2105
|
+
RBSRT_DEBUG_PRINT("poll did wait");
|
2106
|
+
|
2107
|
+
for (int i = 0; i < arg.num_events; i++)
|
2108
|
+
{
|
2109
|
+
SRT_EPOLL_EVENT *event = &events[i];
|
2110
|
+
|
2111
|
+
VALUE sock = rb_hash_aref(sockets, INT2FIX(event->fd));
|
2112
|
+
|
2113
|
+
if (!RTEST(sock))
|
2114
|
+
{
|
2115
|
+
RBSRT_DEBUG_PRINT("poll matched socket not in socket list");
|
2116
|
+
|
2117
|
+
// TODO: remove unknown socket
|
2118
|
+
|
2119
|
+
continue;
|
2120
|
+
}
|
2121
|
+
|
2122
|
+
if (event->events & SRT_EPOLL_IN)
|
2123
|
+
{
|
2124
|
+
RBSRT_DEBUG_PRINT("poll add readables");
|
2125
|
+
|
2126
|
+
rb_ary_push(readables, sock);
|
2127
|
+
}
|
2128
|
+
|
2129
|
+
if (event->events & SRT_EPOLL_OUT)
|
2130
|
+
{
|
2131
|
+
RBSRT_DEBUG_PRINT("poll add writables");
|
2132
|
+
|
2133
|
+
rb_ary_push(writables, sock);
|
2134
|
+
}
|
2135
|
+
|
2136
|
+
if (event->events & SRT_EPOLL_ERR)
|
2137
|
+
{
|
2138
|
+
RBSRT_DEBUG_PRINT("poll add error");
|
2139
|
+
|
2140
|
+
rb_ary_push(errors, sock);
|
2141
|
+
}
|
2142
|
+
}
|
2143
|
+
|
2144
|
+
if (rb_block_given_p())
|
2145
|
+
{
|
2146
|
+
rb_yield_values(3, readables, writables, errors);
|
2147
|
+
|
2148
|
+
return Qtrue;
|
2149
|
+
}
|
2150
|
+
|
2151
|
+
return rb_ary_new_from_args(3, readables, writables, errors);
|
2152
|
+
}
|
2153
|
+
|
2154
|
+
|
2155
|
+
|
2156
|
+
// MARK: - Ruby Module
|
2157
|
+
|
2158
|
+
void Init_rbsrt()
|
2159
|
+
{
|
2160
|
+
// toplevel SRT module
|
2161
|
+
|
2162
|
+
mSRTModule = rb_define_module("SRT");
|
2163
|
+
|
2164
|
+
rb_define_const(mSRTModule, "SRT_VERSION", rb_str_new_cstr(SRT_VERSION_STRING));
|
2165
|
+
|
2166
|
+
|
2167
|
+
// SRT::Errors
|
2168
|
+
|
2169
|
+
rbsrt_init_errors();
|
2170
|
+
|
2171
|
+
|
2172
|
+
// SRT::Socket Class
|
2173
|
+
|
2174
|
+
mSRTSocketKlass = rb_define_class_under(mSRTModule, "Socket", rb_cObject);
|
2175
|
+
|
2176
|
+
rb_define_alloc_func(mSRTSocketKlass, rbsrt_socket_allocate);
|
2177
|
+
|
2178
|
+
rb_define_method(mSRTSocketKlass, "initialize", rbsrt_socket_initialize, 0);
|
2179
|
+
|
2180
|
+
rbsrt_socket_base_define_basic_api(mSRTSocketKlass);
|
2181
|
+
rbsrt_socket_base_define_base_api(mSRTSocketKlass);
|
2182
|
+
rbsrt_socket_base_define_option_api(mSRTSocketKlass);
|
2183
|
+
rbsrt_socket_base_define_io_api(mSRTSocketKlass);
|
2184
|
+
rbsrt_define_socket_state_api(mSRTSocketKlass);
|
2185
|
+
|
2186
|
+
rb_define_method(mSRTSocketKlass, "accept", rbsrt_socket_accept, 0);
|
2187
|
+
rb_define_method(mSRTSocketKlass, "bind", rbsrt_socket_bind, 2);
|
2188
|
+
rb_define_method(mSRTSocketKlass, "connect", rbsrt_socket_connect, 2);
|
2189
|
+
rb_define_method(mSRTSocketKlass, "listen", rbsrt_socket_listen, 1);
|
2190
|
+
|
2191
|
+
|
2192
|
+
|
2193
|
+
// SRT::Server Class
|
2194
|
+
|
2195
|
+
mSRTServerKlass = rb_define_class_under(mSRTModule, "Server", rb_cObject);
|
2196
|
+
|
2197
|
+
rb_define_alloc_func(mSRTServerKlass, rbsrt_server_allocate);
|
2198
|
+
|
2199
|
+
rb_define_method(mSRTServerKlass, "initialize", rbsrt_server_initialize, 2);
|
2200
|
+
|
2201
|
+
rbsrt_socket_base_define_base_api(mSRTServerKlass);
|
2202
|
+
rbsrt_define_socket_state_api(mSRTServerKlass);
|
2203
|
+
|
2204
|
+
rb_define_method(mSRTServerKlass, "close", rbsrt_server_close, 0);
|
2205
|
+
rb_define_method(mSRTServerKlass, "connection_count", rbsrt_server_connection_count, 0);
|
2206
|
+
rb_define_method(mSRTServerKlass, "start", rbsrt_server_start, 0);
|
2207
|
+
|
2208
|
+
|
2209
|
+
// SRT::Connection Class
|
2210
|
+
|
2211
|
+
mSRTConnectionKlass = rb_define_class_under(mSRTModule, "Connection", rb_cObject);
|
2212
|
+
|
2213
|
+
rb_define_alloc_func(mSRTConnectionKlass, rbsrt_connection_allocate);
|
2214
|
+
|
2215
|
+
rbsrt_socket_base_define_basic_api(mSRTConnectionKlass);
|
2216
|
+
rbsrt_socket_base_define_base_api(mSRTConnectionKlass);
|
2217
|
+
rbsrt_socket_base_define_option_api(mSRTConnectionKlass);
|
2218
|
+
rbsrt_define_socket_state_api(mSRTConnectionKlass);
|
2219
|
+
|
2220
|
+
rb_define_method(mSRTConnectionKlass, "sendmsg", rbsrt_socket_sendmsg, 1);
|
2221
|
+
rb_alias(mSRTConnectionKlass, rb_intern("write"), rb_intern("sendmsg"));
|
2222
|
+
|
2223
|
+
|
2224
|
+
// calbacks
|
2225
|
+
|
2226
|
+
rb_define_method(mSRTConnectionKlass, "at_data", rbsrt_connection_set_at_data_block, 0);
|
2227
|
+
rb_define_method(mSRTConnectionKlass, "at_close", rbsrt_connection_set_at_close_block, 0);
|
2228
|
+
|
2229
|
+
|
2230
|
+
// SRT::Client Class
|
2231
|
+
|
2232
|
+
mSRTClientKlass = rb_define_class_under(mSRTModule, "Client", rb_cObject);
|
2233
|
+
|
2234
|
+
rb_define_alloc_func(mSRTClientKlass, rbsrt_client_allocate);
|
2235
|
+
|
2236
|
+
// SRT::Client methods
|
2237
|
+
|
2238
|
+
rb_define_method(mSRTClientKlass, "initialize", rbsrt_client_initialize, 0);
|
2239
|
+
|
2240
|
+
rbsrt_socket_base_define_basic_api(mSRTClientKlass);
|
2241
|
+
rbsrt_socket_base_define_base_api(mSRTClientKlass);
|
2242
|
+
rbsrt_socket_base_define_connection_api(mSRTClientKlass);
|
2243
|
+
rbsrt_socket_base_define_option_api(mSRTClientKlass);
|
2244
|
+
rbsrt_socket_base_define_io_api(mSRTClientKlass);
|
2245
|
+
rbsrt_define_socket_state_api(mSRTClientKlass);
|
2246
|
+
|
2247
|
+
|
2248
|
+
// SRT::Poll
|
2249
|
+
|
2250
|
+
mSRTPollKlass = rb_define_class_under(mSRTModule, "Poll", rb_cObject);
|
2251
|
+
|
2252
|
+
rb_define_alloc_func(mSRTPollKlass, rbsrt_poll_allocate);
|
2253
|
+
|
2254
|
+
rb_define_method(mSRTPollKlass, "initialize", rbsrt_poll_initialize, 0);
|
2255
|
+
rb_define_method(mSRTPollKlass, "add", rbsrt_poll_add_socket, -1);
|
2256
|
+
rb_define_method(mSRTPollKlass, "update", rbsrt_poll_update_socket, -1);
|
2257
|
+
rb_define_method(mSRTPollKlass, "remove", rbsrt_poll_remove_socket, 1);
|
2258
|
+
rb_define_method(mSRTPollKlass, "wait", rbsrt_poll_wait, -1);
|
2259
|
+
|
2260
|
+
|
2261
|
+
// Init Stats
|
2262
|
+
|
2263
|
+
RBSRT_stat_init(mSRTModule);
|
2264
|
+
|
2265
|
+
// Startup SRT
|
2266
|
+
|
2267
|
+
rbsrt_srt_startup(NULL);
|
2268
|
+
|
2269
|
+
ruby_vm_at_exit(rbsrt_srt_cleanup);
|
2270
|
+
}
|