PageRenderTime 63ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 0ms

/include/libnode/detail/dgram/socket.h

https://github.com/danielchow/libnode
C Header | 392 lines | 332 code | 59 blank | 1 comment | 50 complexity | 027553b213c7a1848505601bde9d5642 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause
  1. // Copyright (c) 2013-2014 Plenluno All rights reserved.
  2. #ifndef LIBNODE_DETAIL_DGRAM_SOCKET_H_
  3. #define LIBNODE_DETAIL_DGRAM_SOCKET_H_
  4. #include <libnode/config.h>
  5. #include <libnode/dns.h>
  6. #include <libnode/process.h>
  7. #include <libnode/dgram/socket.h>
  8. #include <libnode/detail/uv/udp.h>
  9. #include <libnode/detail/events/event_emitter.h>
  10. namespace libj {
  11. namespace node {
  12. namespace detail {
  13. namespace dgram {
  14. class Socket : public events::EventEmitter<node::dgram::Socket> {
  15. public:
  16. LIBJ_MUTABLE_DEFS(Socket, LIBNODE_DGRAM_SOCKET);
  17. static Ptr create(Type type, JsFunction::Ptr callback) {
  18. Socket* sock = new Socket(type);
  19. sock->on(EVENT_MESSAGE, callback);
  20. return Ptr(sock);
  21. }
  22. virtual void close() {
  23. close(JsFunction::Ptr(new AfterClose(this)));
  24. }
  25. virtual libj::JsObject::Ptr address() {
  26. if (handle_) {
  27. return handle_->getSockName();
  28. } else {
  29. return libj::JsObject::null();
  30. }
  31. }
  32. virtual Boolean send(
  33. Buffer::CPtr buf,
  34. Size offset,
  35. Size length,
  36. Int port,
  37. String::CPtr address,
  38. JsFunction::Ptr callback = JsFunction::null()) {
  39. if (!handle_ || !buf) return false;
  40. Size bufLen = buf->length();
  41. if (offset >= bufLen || offset + length > bufLen) return false;
  42. if (bindState_ == UNBOUND) bind(0);
  43. if (bindState_ != BOUND) {
  44. if (!sendQueue_) {
  45. sendQueue_ = JsArray::create();
  46. on(EVENT_LISTENING, JsFunction::Ptr(new OnListening(this)));
  47. }
  48. JsArray::Ptr params = JsArray::create();
  49. params->add(buf);
  50. params->add(offset);
  51. params->add(length);
  52. params->add(port);
  53. params->add(address);
  54. params->add(callback);
  55. sendQueue_->push(params);
  56. return true;
  57. }
  58. return lookup(
  59. address,
  60. JsFunction::Ptr(new AfterLookupInSend(
  61. this,
  62. buf,
  63. offset,
  64. length,
  65. port,
  66. callback)));
  67. }
  68. virtual Boolean bind(
  69. Int port,
  70. JsFunction::Ptr callback) {
  71. return bind(port, String::null(), callback);
  72. }
  73. virtual Boolean bind(
  74. Int port,
  75. String::CPtr address = String::null(),
  76. JsFunction::Ptr callback = JsFunction::null()) {
  77. if (!handle_ || bindState_ != UNBOUND) return false;
  78. bindState_ = BINDING;
  79. if (callback) once(EVENT_LISTENING, callback);
  80. return lookup(
  81. address,
  82. JsFunction::Ptr(new AfterLookupInBind(this, port)));
  83. }
  84. virtual Boolean setBroadcast(Boolean flag) {
  85. return handle_ && !handle_->setBroadcast(flag ? 1 : 0);
  86. }
  87. virtual Boolean setTTL(Int ttl) {
  88. return handle_ && !handle_->setTTL(ttl);
  89. }
  90. virtual Boolean setMulticastTTL(Int ttl) {
  91. return handle_ && !handle_->setMulticastTTL(ttl);
  92. }
  93. virtual Boolean setMulticastLoopback(Boolean flag) {
  94. return handle_ && !handle_->setMulticastLoopback(flag);
  95. }
  96. virtual Boolean addMembership(
  97. String::CPtr multicastAddress,
  98. String::CPtr multicastInterface = String::null()) {
  99. return handle_ &&
  100. multicastAddress &&
  101. !handle_->addMembership(multicastAddress, multicastInterface);
  102. }
  103. virtual Boolean dropMembership(
  104. String::CPtr multicastAddress,
  105. String::CPtr multicastInterface = String::null()) {
  106. return handle_ &&
  107. multicastAddress &&
  108. !handle_->dropMembership(multicastAddress, multicastInterface);
  109. }
  110. virtual void ref() {
  111. if (handle_) handle_->ref();
  112. }
  113. virtual void unref() {
  114. if (handle_) handle_->unref();
  115. }
  116. private:
  117. Boolean lookup(String::CPtr addr, JsFunction::Ptr callback) {
  118. LIBJ_STATIC_SYMBOL_DEF(defaultIP4, "0.0.0.0");
  119. LIBJ_STATIC_SYMBOL_DEF(defaultIP6, "::0");
  120. if (type_ == UDP4) {
  121. if (!addr) addr = defaultIP4;
  122. return dns::lookup(addr, 4, callback);
  123. } else {
  124. assert(type_ == UDP6);
  125. if (!addr) addr = defaultIP6;
  126. return dns::lookup(addr, 6, callback);
  127. }
  128. }
  129. uv::UdpSend* uvSend(
  130. Buffer::CPtr buf,
  131. Size offset,
  132. Size length,
  133. Int port,
  134. String::CPtr ip) {
  135. if (type_ == UDP4) {
  136. return handle_->send4(buf, offset, length, port, ip);
  137. } else {
  138. assert(type_ == UDP6);
  139. return handle_->send6(buf, offset, length, port, ip);
  140. }
  141. }
  142. Int uvBind(String::CPtr addr, Int port, Int flags) {
  143. assert(handle_);
  144. if (type_ == UDP4) {
  145. return handle_->bind4(addr, port, flags);
  146. } else {
  147. assert(type_ == UDP6);
  148. return handle_->bind6(addr, port, flags);
  149. }
  150. }
  151. void startListening() {
  152. assert(handle_);
  153. handle_->setOnMessage(JsFunction::Ptr(new OnMessage(this)));
  154. handle_->recvStart();
  155. receiving_ = true;
  156. bindState_ = BOUND;
  157. emit(EVENT_LISTENING);
  158. }
  159. void stopReceiving() {
  160. if (receiving_) {
  161. handle_->recvStop();
  162. receiving_ = false;
  163. }
  164. }
  165. void close(JsFunction::Ptr cb) {
  166. if (handle_) {
  167. stopReceiving();
  168. handle_->close();
  169. handle_ = NULL;
  170. emit(EVENT_CLOSE);
  171. if (cb) process::nextTick(cb);
  172. }
  173. }
  174. private:
  175. class OnMessage : LIBJ_JS_FUNCTION(OnMessage)
  176. public:
  177. OnMessage(Socket* self) : self_(self) {}
  178. virtual Value operator()(JsArray::Ptr args) {
  179. self_->emit(EVENT_MESSAGE, args);
  180. return Status::OK;
  181. }
  182. private:
  183. Socket* self_;
  184. };
  185. class OnListening : LIBJ_JS_FUNCTION(OnListening)
  186. OnListening(Socket* self) : self_(self) {}
  187. virtual Value operator()(JsArray::Ptr args) {
  188. assert(self_->sendQueue_);
  189. Size len = self_->sendQueue_->length();
  190. for (Size i = 0; i < len; i++) {
  191. JsArray::Ptr ps = self_->sendQueue_->getPtr<JsArray>(i);
  192. Buffer::CPtr buf = ps->getCPtr<Buffer>(0);
  193. Size offset = to<Size>(ps->get(1));
  194. Size length = to<Size>(ps->get(2));
  195. Int port = to<Int>(ps->get(3));
  196. String::CPtr address = ps->getCPtr<String>(4);
  197. JsFunction::Ptr callback = ps->getPtr<JsFunction>(5);
  198. self_->send(buf, offset, length, port, address, callback);
  199. }
  200. self_->sendQueue_->clear();
  201. return Status::OK;
  202. }
  203. private:
  204. Socket* self_;
  205. };
  206. class AfterSend : LIBJ_JS_FUNCTION(AfterSend)
  207. public:
  208. virtual Value operator()(JsArray::Ptr args) {
  209. assert(!to<Int>(args->get(0), -1));
  210. uv::UdpSend* udpSend = to<uv::UdpSend*>(args->get(1));
  211. if (udpSend && udpSend->cb) {
  212. invoke(
  213. udpSend->cb,
  214. libj::Error::null(),
  215. udpSend->buffer->length());
  216. }
  217. return Status::OK;
  218. }
  219. };
  220. class AfterLookupInSend : LIBJ_JS_FUNCTION(AfterLookupInSend)
  221. public:
  222. AfterLookupInSend(
  223. Socket* self,
  224. Buffer::CPtr buf,
  225. Size offset,
  226. Size length,
  227. Int port,
  228. JsFunction::Ptr callback)
  229. : self_(self)
  230. , buf_(buf)
  231. , offset_(offset)
  232. , length_(length)
  233. , port_(port)
  234. , callback_(callback) {}
  235. virtual Value operator()(JsArray::Ptr args) {
  236. libj::Error::CPtr err = args->getCPtr<libj::Error>(0);
  237. if (err) {
  238. if (callback_) invoke(callback_, err);
  239. self_->emit(EVENT_ERROR, err);
  240. return err;
  241. }
  242. if (!self_->handle_) return Status::OK;
  243. uv::UdpSend* udpSend = self_->uvSend(
  244. buf_,
  245. offset_,
  246. length_,
  247. port_,
  248. args->getCPtr<String>(1));
  249. if (udpSend) {
  250. JsFunction::Ptr afterSend(new AfterSend());
  251. udpSend->onComplete = afterSend;
  252. udpSend->cb = callback_;
  253. } else {
  254. libj::Error::CPtr err = node::uv::Error::last();
  255. invoke(callback_, err, 0);
  256. }
  257. return Status::OK;
  258. }
  259. private:
  260. Socket* self_;
  261. Buffer::CPtr buf_;
  262. Size offset_;
  263. Size length_;
  264. Int port_;
  265. JsFunction::Ptr callback_;
  266. };
  267. class AfterLookupInBind : LIBJ_JS_FUNCTION(AfterLookupInBind)
  268. public:
  269. AfterLookupInBind(Socket* self, Int port)
  270. : self_(self)
  271. , port_(port) {}
  272. virtual Value operator()(JsArray::Ptr args) {
  273. libj::Error::CPtr err = args->getCPtr<libj::Error>(0);
  274. if (err) {
  275. self_->bindState_ = UNBOUND;
  276. self_->emit(EVENT_ERROR, err);
  277. return err;
  278. }
  279. if (!self_->handle_) return Status::OK;
  280. String::CPtr ip = args->getCPtr<String>(1);
  281. if (self_->uvBind(ip, port_, 0)) {
  282. err = node::uv::Error::last();
  283. self_->bindState_ = UNBOUND;
  284. self_->emit(EVENT_ERROR, err);
  285. return err;
  286. }
  287. self_->startListening();
  288. return Status::OK;
  289. }
  290. private:
  291. Socket* self_;
  292. Int port_;
  293. };
  294. class AfterClose : LIBJ_JS_FUNCTION(AfterClose)
  295. public:
  296. AfterClose(Socket* self) : self_(self) {}
  297. virtual Value operator()(JsArray::Ptr args) {
  298. #ifdef LIBNODE_REMOVE_LISTENER
  299. self_->removeAllListeners();
  300. #endif
  301. return Status::OK;
  302. }
  303. private:
  304. Socket* self_;
  305. };
  306. private:
  307. enum BindState {
  308. UNBOUND,
  309. BINDING,
  310. BOUND
  311. };
  312. private:
  313. uv::Udp* handle_;
  314. Type type_;
  315. Boolean receiving_;
  316. BindState bindState_;
  317. JsArray::Ptr sendQueue_;
  318. Socket(Type type)
  319. : handle_(new uv::Udp())
  320. , type_(type)
  321. , receiving_(false)
  322. , bindState_(UNBOUND)
  323. , sendQueue_(JsArray::null()) {}
  324. public:
  325. virtual ~Socket() {
  326. if (handle_) handle_->close();
  327. }
  328. };
  329. } // namespace dgram
  330. } // namespace detail
  331. } // namespace node
  332. } // namespace libj
  333. #endif // LIBNODE_DETAIL_DGRAM_SOCKET_H_