1 /* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include "iotjs_def.h"
18 #include "iotjs_module_udp.h"
20 #include "iotjs_handlewrap.h"
21 #include "iotjs_module_buffer.h"
22 #include "iotjs_module_tcp.h"
23 #include "iotjs_reqwrap.h"
26 static void iotjs_udpwrap_destroy(iotjs_udpwrap_t* udpwrap);
29 iotjs_udpwrap_t* iotjs_udpwrap_create(const iotjs_jval_t* judp) {
30 iotjs_udpwrap_t* udpwrap = IOTJS_ALLOC(iotjs_udpwrap_t);
31 IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_udpwrap_t, udpwrap);
33 iotjs_handlewrap_initialize(&_this->handlewrap, judp,
34 (uv_handle_t*)(&_this->handle),
35 (JFreeHandlerType)iotjs_udpwrap_destroy);
37 const iotjs_environment_t* env = iotjs_environment_get();
38 uv_udp_init(iotjs_environment_loop(env), &_this->handle);
44 static void iotjs_udpwrap_destroy(iotjs_udpwrap_t* udpwrap) {
45 IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_udpwrap_t, udpwrap);
46 iotjs_handlewrap_destroy(&_this->handlewrap);
47 IOTJS_RELEASE(udpwrap);
51 iotjs_udpwrap_t* iotjs_udpwrap_from_handle(uv_udp_t* udp_handle) {
52 uv_handle_t* handle = (uv_handle_t*)(udp_handle);
53 iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_handle(handle);
54 iotjs_udpwrap_t* udpwrap = (iotjs_udpwrap_t*)handlewrap;
55 IOTJS_ASSERT(iotjs_udpwrap_udp_handle(udpwrap) == udp_handle);
60 iotjs_udpwrap_t* iotjs_udpwrap_from_jobject(const iotjs_jval_t* judp) {
61 iotjs_handlewrap_t* handlewrap = iotjs_handlewrap_from_jobject(judp);
62 return (iotjs_udpwrap_t*)handlewrap;
66 uv_udp_t* iotjs_udpwrap_udp_handle(iotjs_udpwrap_t* udpwrap) {
67 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_udpwrap_t, udpwrap);
68 uv_handle_t* handle = iotjs_handlewrap_get_uv_handle(&_this->handlewrap);
69 return (uv_udp_t*)handle;
73 iotjs_jval_t* iotjs_udpwrap_jobject(iotjs_udpwrap_t* udpwrap) {
74 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_udpwrap_t, udpwrap);
75 return iotjs_handlewrap_jobject(&_this->handlewrap);
79 #define THIS iotjs_send_reqwrap_t* send_reqwrap
81 iotjs_send_reqwrap_t* iotjs_send_reqwrap_create(const iotjs_jval_t* jcallback,
82 const size_t msg_size) {
83 iotjs_send_reqwrap_t* send_reqwrap = IOTJS_ALLOC(iotjs_send_reqwrap_t);
84 IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_send_reqwrap_t, send_reqwrap);
86 iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req);
87 _this->msg_size = msg_size;
93 static void iotjs_send_reqwrap_destroy(THIS) {
94 IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_send_reqwrap_t, send_reqwrap);
95 iotjs_reqwrap_destroy(&_this->reqwrap);
96 IOTJS_RELEASE(send_reqwrap);
100 void iotjs_send_reqwrap_dispatched(THIS) {
101 IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_send_reqwrap_t, send_reqwrap);
102 iotjs_send_reqwrap_destroy(send_reqwrap);
106 uv_udp_send_t* iotjs_send_reqwrap_req(THIS) {
107 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_send_reqwrap_t, send_reqwrap);
112 const iotjs_jval_t* iotjs_send_reqwrap_jcallback(THIS) {
113 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_send_reqwrap_t, send_reqwrap);
114 return iotjs_reqwrap_jcallback(&_this->reqwrap);
118 size_t iotjs_send_reqwrap_msg_size(THIS) {
119 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_send_reqwrap_t, send_reqwrap);
120 return _this->msg_size;
126 JHANDLER_FUNCTION(UDP) {
127 JHANDLER_CHECK_THIS(object);
128 JHANDLER_CHECK_ARGS(0);
130 const iotjs_jval_t* judp = JHANDLER_GET_THIS(object);
131 iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_create(judp);
132 IOTJS_UNUSED(udp_wrap);
136 JHANDLER_FUNCTION(Bind) {
137 JHANDLER_CHECK_THIS(object);
138 JHANDLER_CHECK_ARGS_2(string, number);
140 const iotjs_jval_t* judp = JHANDLER_GET_THIS(object);
141 iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_jobject(judp);
143 iotjs_string_t address = JHANDLER_GET_ARG(0, string);
144 const int port = JHANDLER_GET_ARG(1, number);
145 const iotjs_jval_t* this_obj = JHANDLER_GET_THIS(object);
146 iotjs_jval_t reuse_addr =
147 iotjs_jval_get_property(this_obj, IOTJS_MAGIC_STRING__REUSEADDR);
148 IOTJS_ASSERT(iotjs_jval_is_boolean(&reuse_addr) ||
149 iotjs_jval_is_undefined(&reuse_addr));
152 if (!iotjs_jval_is_undefined(&reuse_addr)) {
153 flags = iotjs_jval_as_boolean(&reuse_addr) ? UV_UDP_REUSEADDR : 0;
156 char addr[sizeof(sockaddr_in6)];
158 uv_ip4_addr(iotjs_string_data(&address), port, (sockaddr_in*)(&addr));
161 err = uv_udp_bind(iotjs_udpwrap_udp_handle(udp_wrap),
162 (const sockaddr*)(&addr), flags);
165 iotjs_jhandler_return_number(jhandler, err);
167 iotjs_jval_destroy(&reuse_addr);
168 iotjs_string_destroy(&address);
172 static void OnAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
173 if (suggested_size > IOTJS_MAX_READ_BUFFER_SIZE) {
174 suggested_size = IOTJS_MAX_READ_BUFFER_SIZE;
177 buf->base = iotjs_buffer_allocate(suggested_size);
178 buf->len = suggested_size;
182 static void OnRecv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf,
183 const struct sockaddr* addr, unsigned int flags) {
184 if (nread == 0 && addr == NULL) {
185 if (buf->base != NULL)
186 iotjs_buffer_release(buf->base);
190 iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_handle(handle);
193 const iotjs_jval_t* judp = iotjs_udpwrap_jobject(udp_wrap);
194 IOTJS_ASSERT(iotjs_jval_is_object(judp));
196 // onmessage callback
197 iotjs_jval_t jonmessage =
198 iotjs_jval_get_property(judp, IOTJS_MAGIC_STRING_ONMESSAGE);
199 IOTJS_ASSERT(iotjs_jval_is_function(&jonmessage));
201 iotjs_jargs_t jargs = iotjs_jargs_create(4);
202 iotjs_jargs_append_number(&jargs, nread);
203 iotjs_jargs_append_jval(&jargs, judp);
206 if (buf->base != NULL)
207 iotjs_buffer_release(buf->base);
208 iotjs_make_callback(&jonmessage, iotjs_jval_get_undefined(), &jargs);
209 iotjs_jval_destroy(&jonmessage);
210 iotjs_jargs_destroy(&jargs);
214 iotjs_jval_t jbuffer = iotjs_bufferwrap_create_buffer(nread);
215 iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(&jbuffer);
217 iotjs_bufferwrap_copy(buffer_wrap, buf->base, nread);
219 iotjs_jargs_append_jval(&jargs, &jbuffer);
221 iotjs_jval_t rinfo = iotjs_jval_create_object();
222 AddressToJS(&rinfo, addr);
223 iotjs_jargs_append_jval(&jargs, &rinfo);
225 iotjs_make_callback(&jonmessage, iotjs_jval_get_undefined(), &jargs);
227 iotjs_jval_destroy(&rinfo);
228 iotjs_jval_destroy(&jbuffer);
229 iotjs_jval_destroy(&jonmessage);
230 iotjs_buffer_release(buf->base);
231 iotjs_jargs_destroy(&jargs);
235 JHANDLER_FUNCTION(RecvStart) {
236 JHANDLER_CHECK_THIS(object);
237 JHANDLER_CHECK_ARGS(0);
239 const iotjs_jval_t* judp = JHANDLER_GET_THIS(object);
240 iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_jobject(judp);
243 uv_udp_recv_start(iotjs_udpwrap_udp_handle(udp_wrap), OnAlloc, OnRecv);
245 // UV_EALREADY means that the socket is already bound but that's okay
246 if (err == UV_EALREADY)
249 iotjs_jhandler_return_number(jhandler, err);
253 JHANDLER_FUNCTION(RecvStop) {
254 JHANDLER_CHECK_THIS(object);
255 JHANDLER_CHECK_ARGS(0);
257 const iotjs_jval_t* judp = JHANDLER_GET_THIS(object);
258 iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_jobject(judp);
260 int r = uv_udp_recv_stop(iotjs_udpwrap_udp_handle(udp_wrap));
262 iotjs_jhandler_return_number(jhandler, r);
266 static void OnSend(uv_udp_send_t* req, int status) {
267 iotjs_send_reqwrap_t* req_wrap = (iotjs_send_reqwrap_t*)(req->data);
268 IOTJS_ASSERT(req_wrap != NULL);
270 // Take callback function object.
271 const iotjs_jval_t* jcallback = iotjs_send_reqwrap_jcallback(req_wrap);
273 if (iotjs_jval_is_function(jcallback)) {
274 // Take callback function object.
276 iotjs_jargs_t jargs = iotjs_jargs_create(2);
277 iotjs_jargs_append_number(&jargs, status);
278 iotjs_jargs_append_number(&jargs, iotjs_send_reqwrap_msg_size(req_wrap));
280 iotjs_make_callback(jcallback, iotjs_jval_get_undefined(), &jargs);
281 iotjs_jargs_destroy(&jargs);
284 iotjs_send_reqwrap_dispatched(req_wrap);
288 // Send messages using the socket.
292 // [3] callback function
293 JHANDLER_FUNCTION(Send) {
294 JHANDLER_CHECK_THIS(object);
295 JHANDLER_CHECK_ARGS_3(object, number, string);
296 IOTJS_ASSERT(iotjs_jval_is_function(iotjs_jhandler_get_arg(jhandler, 3)) ||
297 iotjs_jval_is_undefined(iotjs_jhandler_get_arg(jhandler, 3)));
299 const iotjs_jval_t* judp = JHANDLER_GET_THIS(object);
300 iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_jobject(judp);
302 const iotjs_jval_t* jbuffer = JHANDLER_GET_ARG(0, object);
303 const unsigned short port = JHANDLER_GET_ARG(1, number);
304 iotjs_string_t address = JHANDLER_GET_ARG(2, string);
305 const iotjs_jval_t* jcallback = JHANDLER_GET_ARG(3, object);
307 iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer);
308 char* buffer = iotjs_bufferwrap_buffer(buffer_wrap);
309 int len = iotjs_bufferwrap_length(buffer_wrap);
311 iotjs_send_reqwrap_t* req_wrap = iotjs_send_reqwrap_create(jcallback, len);
317 char addr[sizeof(sockaddr_in6)];
319 uv_ip4_addr(iotjs_string_data(&address), port, (sockaddr_in*)(&addr));
322 err = uv_udp_send(iotjs_send_reqwrap_req(req_wrap),
323 iotjs_udpwrap_udp_handle(udp_wrap), &buf, 1,
324 (const sockaddr*)(&addr), OnSend);
328 iotjs_send_reqwrap_dispatched(req_wrap);
331 iotjs_jhandler_return_number(jhandler, err);
333 iotjs_string_destroy(&address);
338 JHANDLER_FUNCTION(Close) {
339 JHANDLER_CHECK_THIS(object);
340 JHANDLER_CHECK_ARGS(0);
342 const iotjs_jval_t* judp = JHANDLER_GET_THIS(object);
343 iotjs_handlewrap_t* wrap = iotjs_handlewrap_from_jobject(judp);
345 iotjs_handlewrap_close(wrap, NULL);
349 GetSockNameFunction(udpwrap, udp_handle, uv_udp_getsockname);
352 JHANDLER_FUNCTION(GetSockeName) {
353 DoGetSockName(jhandler);
357 #define IOTJS_UV_SET_SOCKOPT(fn) \
358 JHANDLER_CHECK_THIS(object); \
359 JHANDLER_CHECK_ARGS_1(number); \
361 const iotjs_jval_t* judp = JHANDLER_GET_THIS(object); \
362 iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_jobject(judp); \
364 int flag = JHANDLER_GET_ARG(0, number); \
365 int err = fn(iotjs_udpwrap_udp_handle(udp_wrap), flag); \
367 iotjs_jhandler_return_number(jhandler, err);
370 JHANDLER_FUNCTION(SetBroadcast) {
371 #if !defined(__NUTTX__) && !defined(__TIZENRT__)
372 IOTJS_UV_SET_SOCKOPT(uv_udp_set_broadcast);
374 IOTJS_ASSERT(!"Not implemented");
376 iotjs_jhandler_return_null(jhandler);
381 JHANDLER_FUNCTION(SetTTL) {
382 #if !defined(__NUTTX__) && !defined(__TIZENRT__)
383 IOTJS_UV_SET_SOCKOPT(uv_udp_set_ttl);
385 IOTJS_ASSERT(!"Not implemented");
387 iotjs_jhandler_return_null(jhandler);
392 JHANDLER_FUNCTION(SetMulticastTTL) {
393 #if !defined(__NUTTX__) && !defined(__TIZENRT__)
394 IOTJS_UV_SET_SOCKOPT(uv_udp_set_multicast_ttl);
396 IOTJS_ASSERT(!"Not implemented");
398 iotjs_jhandler_return_null(jhandler);
403 JHANDLER_FUNCTION(SetMulticastLoopback) {
404 #if !defined(__NUTTX__) && !defined(__TIZENRT__)
405 IOTJS_UV_SET_SOCKOPT(uv_udp_set_multicast_loop);
407 IOTJS_ASSERT(!"Not implemented");
409 iotjs_jhandler_return_null(jhandler);
413 #undef IOTJS_UV_SET_SOCKOPT
416 void SetMembership(iotjs_jhandler_t* jhandler, uv_membership membership) {
417 #if !defined(__NUTTX__) && !defined(__TIZENRT__)
418 JHANDLER_CHECK_THIS(object);
419 JHANDLER_CHECK_ARGS_1(string);
421 const iotjs_jval_t* judp = JHANDLER_GET_THIS(object);
422 iotjs_udpwrap_t* udp_wrap = iotjs_udpwrap_from_jobject(judp);
424 iotjs_string_t address = JHANDLER_GET_ARG(0, string);
425 const iotjs_jval_t* arg1 = iotjs_jhandler_get_arg(jhandler, 1);
426 bool isUndefinedOrNull =
427 iotjs_jval_is_undefined(arg1) || iotjs_jval_is_null(arg1);
428 iotjs_string_t iface;
430 const char* iface_cstr;
431 if (isUndefinedOrNull) {
434 iface = iotjs_jval_as_string(arg1);
435 iface_cstr = iotjs_string_data(&iface);
438 int err = uv_udp_set_membership(iotjs_udpwrap_udp_handle(udp_wrap),
439 iotjs_string_data(&address), iface_cstr,
442 iotjs_jhandler_return_number(jhandler, err);
444 iotjs_string_destroy(&address);
445 if (!isUndefinedOrNull)
446 iotjs_string_destroy(&iface);
448 IOTJS_ASSERT(!"Not implemented");
450 iotjs_jhandler_return_null(jhandler);
455 JHANDLER_FUNCTION(AddMembership) {
456 SetMembership(jhandler, UV_JOIN_GROUP);
460 JHANDLER_FUNCTION(DropMembership) {
461 SetMembership(jhandler, UV_LEAVE_GROUP);
465 JHANDLER_FUNCTION(Ref) {
466 IOTJS_ASSERT(!"Not implemented");
468 iotjs_jhandler_return_null(jhandler);
472 JHANDLER_FUNCTION(Unref) {
473 IOTJS_ASSERT(!"Not implemented");
475 iotjs_jhandler_return_null(jhandler);
479 iotjs_jval_t InitUdp() {
480 iotjs_jval_t udp = iotjs_jval_create_function_with_dispatch(UDP);
482 iotjs_jval_t prototype = iotjs_jval_create_object();
483 iotjs_jval_set_property_jval(&udp, IOTJS_MAGIC_STRING_PROTOTYPE, &prototype);
485 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_BIND, Bind);
486 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_RECVSTART, RecvStart);
487 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_RECVSTOP, RecvStop);
488 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SEND, Send);
489 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_CLOSE, Close);
490 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_GETSOCKNAME,
492 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETBROADCAST,
494 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETTTL, SetTTL);
495 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETMULTICASTTTL,
497 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_SETMULTICASTLOOPBACK,
498 SetMulticastLoopback);
499 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_ADDMEMBERSHIP,
501 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_DROPMEMBERSHIP,
503 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_REF, Ref);
504 iotjs_jval_set_method(&prototype, IOTJS_MAGIC_STRING_UNREF, Unref);
506 iotjs_jval_destroy(&prototype);