Permalink
Browse files

UDP support

  • Loading branch information...
1 parent 3e88201 commit 24d2aef0619ceb04f57bab9bb294be0ee17b5fd7 @rphillips rphillips committed Aug 7, 2012
Showing with 517 additions and 25 deletions.
  1. +221 −0 lib/luvit/dgram.lua
  2. +12 −0 lib/luvit/uv.lua
  3. +1 −0 luvit.gyp
  4. +4 −0 src/luv.c
  5. +171 −25 src/luv_udp.c
  6. +4 −0 src/luv_udp.h
  7. +2 −0 src/luvit_exports.c
  8. +40 −0 tests/test-dgram-multicast.lua
  9. +62 −0 tests/test-dgram.lua
View
@@ -0,0 +1,221 @@
+--[[
+
+Copyright 2012 The Luvit Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS-IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+--]]
+
+-- Ported from node's dgram.js.
+
+local dns = require('dns')
+local net = require('net')
+local Udp = require('uv').Udp
+local Emitter = require('core').Emitter
+
+local dgram = {}
+
+local function lookup(address, family, callback)
+ local matchedFamily = net.isIP(address)
+ if matchedFamily then
+ return callback(nil, address, matchedFamily)
+ end
+ return dns.lookup(address, family, callback)
+end
+
+local function lookup4(address, callback)
+ return lookup(address or '0.0.0.0', 4, callback)
+end
+
+local function lookup6(address, callback)
+ return lookup(address or '::0', 6, callback)
+end
+
+local function newHandle(family)
+ if family == 'udp4' then
+ local handle = Udp:new()
+ handle.lookup = lookup4
+ handle.bind = handle.bind
+ handle.send = handle.send
+ return handle
+ end
+
+ if family == 'udp6' then
+ local handle = Udp:new()
+ handle.lookup = lookup6
+ handle.bind = handle.bind6
+ handle.send = handle.send6
+ return handle
+ end
+
+ error('Bad socket type specified. Valid types are: udp4, udp6')
+end
+
+--[[ Socket ]]--
+
+local Socket = Emitter:extend()
+
+dgram.Socket = Socket
+
+function Socket:initialize(family, listener)
+ self._handle = newHandle(family)
+ self._receiving = false
+ self._bound = false
+ self._family = family
+
+ self:_initEmitters()
+
+ if type(listener) == 'function' then
+ self:on('message', listener)
+ end
+end
+
+function Socket:_initEmitters()
+ self._handle:on('close', function(msg, rinfo)
+ self._handle = nil
+ self:emit('close')
+ end)
+
+ self._handle:on('message', function(msg, rinfo)
+ self:emit('message', msg, rinfo)
+ end)
+
+ self._handle:on('error', function(err)
+ self:emit('error', err)
+ end)
+end
+
+function dgram.createSocket(family, listener)
+ return Socket:new(family, listener)
+end
+
+function Socket:bind(port, address)
+ self:_healthCheck()
+
+ self._handle.lookup(address, function(err, ip)
+ if err then
+ process.nextTick(function()
+ self:emit('error', err)
+ end)
+ return
+ end
+
+ self._handle:bind(ip, port or 0)
+ self._bound = true
+ self:_startReceiving()
+ self:emit('listening')
+ end)
+end
+
+function Socket:send(msg, port, address, callback)
+ self:_healthCheck()
+ self:_startReceiving()
+
+ self._handle.lookup(address, function(err, ip)
+ if err then
+ if callback then callback(err) end
+ self:emit('error', err)
+ return
+ end
+
+ self._handle:send(msg, port, address, callback)
+ end)
+end
+
+function Socket:close()
+ self:_healthCheck()
+ self:_stopReceiving()
+ self._handle:close()
+end
+
+function Socket:address()
+ self:_healthCheck()
+
+ return self._handle:getsockname()
+end
+
+function Socket:setBroadcast(opt)
+ self._handle:setBroadcast(opt and 1 or 0)
+end
+
+function Socket:setTTL(opt)
+ self._handle:setTTL(opt)
+end
+
+function Socket:setMulticastTTL(opt)
+ self._handle:setMulticastTTL(opt)
+end
+
+function Socket:setMulticastLoopback(opt)
+ self._handle:setMulticastLoopback(opt and 1 or 0)
+end
+
+function Socket:setMembership(multicastAddress, interfaceAddress, op)
+ self:_healthCheck()
+
+ if not multicastAddress then
+ error("multicast address must be specified")
+ end
+
+ if not multicastInterface then
+ if self._family == 'udp4' then
+ multicastInterface = '0.0.0.0'
+ elseif self._family == 'udp6' then
+ multicastInterface = '::0'
+ end
+ end
+
+ self._handle:setMembership(multicastAddress, multicastInterface, op)
+end
+
+function Socket:addMembership(multicastAddress, interfaceAddress)
+ self:setMembership(multicastAddress, interfaceAddress, 'join')
+end
+
+function Socket:dropMembership(multicastAddress, interfaceAddress)
+ self:setMembership(multicastAddress, interfaceAddress, 'leave')
+end
+
+function Socket:_healthCheck()
+ if not self._handle then
+ error('self._handle uninitialized')
+ end
+end
+
+function Socket:_startReceiving()
+ if self._receiving then
+ return
+ end
+
+ if not self._bound then
+ self:bind()
+
+ if not self._bound then
+ error('implicit bind failed')
+ end
+ end
+
+ self._handle:recvStart()
+ self._receiving = true
+end
+
+function Socket:_stopReceiving()
+ if not self._receiving then
+ return
+ end
+
+ self._handle:recvStop()
+ self._receiving = false
+end
+
+return dgram
View
@@ -153,6 +153,18 @@ Udp.recvStart = native.udpRecvStart
-- Udp:recvStop()
Udp.recvStop = native.udpRecvStop
+-- Udp:setBroadcast(opt)
+Udp.setBroadcast = native.udpSetBroadcast
+
+-- Udp:setTTL(opt)
+Udp.setTTL = native.udpSetTTL
+
+-- Udp:setMulticastTTL(opt)
+Udp.setMulticastTTL = native.udpSetMulticastTTL
+
+-- Udp:setMulticastLoopback(opt)
+Udp.setMulticastLoopback = native.udpSetMulticastLoopback
+
--------------------------------------------------------------------------------
local Pipe = Stream:extend()
View
@@ -66,6 +66,7 @@
'lib/luvit/buffer.lua',
'lib/luvit/childprocess.lua',
'lib/luvit/core.lua',
+ 'lib/luvit/dgram.lua',
'lib/luvit/dns.lua',
'lib/luvit/fiber.lua',
'lib/luvit/fs.lua',
View
@@ -50,6 +50,10 @@ static const luaL_reg luv_f[] = {
{"udpSend6", luv_udp_send6},
{"udpRecvStart", luv_udp_recv_start},
{"udpRecvStop", luv_udp_recv_stop},
+ {"udpSetBroadcast", luv_udp_set_broadcast},
+ {"udpSetTTL", luv_udp_set_ttl},
+ {"udpSetMulticastTTL", luv_udp_set_multicast_ttl},
+ {"udpSetMulticastLoopback", luv_udp_set_multicast_loopback},
/* FS Watcher functions */
{"newFsWatcher", luv_new_fs_watcher},
Oops, something went wrong.

0 comments on commit 24d2aef

Please sign in to comment.