@@ -35,6 +35,7 @@ var Discovery = Object.create(new events.EventEmitter());
3535 * @param {string } [options.messageId=GUID] WS-Discovery message id
3636 * @param {string } [options.device=defaultroute] Interface to bind on for discovery ex. `eth0`
3737 * @param {number } [options.listeningPort=null] client will listen to discovery data device sent
38+ * @param {number } [options.bufferSize] buffer size in bytes for discovery responses
3839 * @param {Discovery~ProbeCallback } [callback] timeout callback
3940 * @fires Discovery#device
4041 * @fires Discovery#error
@@ -75,20 +76,21 @@ Discovery.probe = function(options, callback) {
7576 messageID = 'urn:uuid:' + ( options . messageId || guid ( ) ) ,
7677 request = Buffer . from (
7778 '<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:dn="http://www.onvif.org/ver10/network/wsdl">' +
78- '<Header>' +
79- '<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">' + messageID + '</wsa:MessageID>' +
80- '<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>' +
81- '<wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>' +
82- '</Header>' +
83- '<Body>' +
84- '<Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
85- '<Types>dn:NetworkVideoTransmitter</Types>' +
86- '<Scopes />' +
87- '</Probe>' +
88- '</Body>' +
89- '</Envelope>'
79+ '<Header>' +
80+ '<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">' + messageID + '</wsa:MessageID>' +
81+ '<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>' +
82+ '<wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>' +
83+ '</Header>' +
84+ '<Body>' +
85+ '<Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
86+ '<Types>dn:NetworkVideoTransmitter</Types>' +
87+ '<Scopes />' +
88+ '</Probe>' +
89+ '</Body>' +
90+ '</Envelope>'
9091 ) ,
91- socket = require ( 'dgram' ) . createSocket ( 'udp4' ) ;
92+ // create a socket with reuse address option, in case there is many nodde processes listening on the same port
93+ socket = require ( 'dgram' ) . createSocket ( 'udp4' , { reuseAddr : true } ) ;
9294
9395 socket . on ( 'error' , function ( err ) {
9496 Discovery . emit ( 'error' , err ) ;
@@ -97,73 +99,94 @@ Discovery.probe = function(options, callback) {
9799
98100 const httpOK200 = 200 ;
99101 const listener = function ( msg , rinfo ) {
100- parseSOAPString ( msg . toString ( ) , function ( err , data , xml , _statusCode ) {
101- // TODO check for matching RelatesTo field and messageId
102- if ( err || ! data [ 0 ] . probeMatches ) {
103- errors . push ( err || new Error ( 'Wrong SOAP message from ' + rinfo . address + ':' + rinfo . port , xml ) ) ;
104- /**
105- * Indicates error response from device.
106- * @event Discovery#error
107- * @type {string }
108- */
109- Discovery . emit ( 'error' , 'Wrong SOAP message from ' + rinfo . address + ':' + rinfo . port , xml ) ;
110- } else {
111- data = linerase ( data ) ;
102+ setImmediate ( ( ) => {
103+ parseSOAPString ( msg . toString ( ) , function ( err , data , xml , _statusCode ) {
104+ // TODO check for matching RelatesTo field and messageId
105+ if ( err || ! data [ 0 ] . probeMatches ) {
106+ errors . push ( err || new Error ( 'Wrong SOAP message from ' + rinfo . address + ':' + rinfo . port , xml ) ) ;
107+ /**
108+ * Indicates error response from device.
109+ * @event Discovery#error
110+ * @type {string }
111+ */
112+ Discovery . emit ( 'error' , 'Wrong SOAP message from ' + rinfo . address + ':' + rinfo . port , xml ) ;
113+ } else {
114+ data = linerase ( data ) ;
112115
113- // Possible to get multiple matches for the same camera
114- // when your computer has more than one network adapter in the same subnet
115- var camAddr = data . probeMatches . probeMatch . endpointReference . address ;
116- if ( ! cams [ camAddr ] ) {
117- var cam ;
118- if ( options . resolve !== false ) {
119- // Create cam with one of the XAddrs uri
120- var camUris = data . probeMatches . probeMatch . XAddrs . split ( ' ' ) . map ( url . parse ) ,
121- camUri = matchXAddr ( camUris , rinfo . address ) ;
122- cam = new Cam ( {
123- hostname : camUri . hostname ,
124- port : camUri . port ,
125- path : camUri . path ,
126- urn : camAddr
127- } ) ;
116+ // Possible to get multiple matches for the same camera
117+ // when your computer has more than one network adapter in the same subnet
118+ var camAddr = data . probeMatches . probeMatch . endpointReference . address ;
119+ if ( ! cams [ camAddr ] ) {
120+ var cam ;
121+ if ( options . resolve !== false ) {
122+ // Create cam with one of the XAddrs uri
123+ var camUris = data . probeMatches . probeMatch . XAddrs . split ( ' ' ) . map ( url . parse ) ,
124+ camUri = matchXAddr ( camUris , rinfo . address ) ;
125+ cam = new Cam ( {
126+ hostname : camUri . hostname ,
127+ port : camUri . port ,
128+ path : camUri . path ,
129+ urn : camAddr
130+ } ) ;
131+ /**
132+ * All available XAddr fields from discovery
133+ * @name xaddrs
134+ * @memberOf Cam#
135+ * @type {Array.<Url> }
136+ */
137+ cam . xaddrs = camUris ;
138+ } else {
139+ cam = data ;
140+ }
141+ cams [ camAddr ] = cam ;
128142 /**
129- * All available XAddr fields from discovery
130- * @name xaddrs
131- * @memberOf Cam#
132- * @type {Array.<Url> }
133- */
134- cam . xaddrs = camUris ;
135- } else {
136- cam = data ;
143+ * Indicates discovered device.
144+ * @event Discovery#device
145+ * @type {Cam|object }
146+ */
147+ Discovery . emit ( 'device' , cam , rinfo , xml ) ;
137148 }
138- cams [ camAddr ] = cam ;
139- /**
140- * Indicates discovered device.
141- * @event Discovery#device
142- * @type {Cam|object }
143- */
144- Discovery . emit ( 'device' , cam , rinfo , xml ) ;
145149 }
146- }
147- } , httpOK200 ) ;
150+ } , httpOK200 ) ;
151+ } ) ;
148152 } ;
149153
154+ // Callback function to bind the socket to the interface
155+ const bindingCallback = function ( err ) {
156+ if ( err ) {
157+ Discovery . emit ( 'error' , err ) ;
158+ callback ( err ) ;
159+ } else {
160+ // set buffer size to the buffer size option in bytes
161+ if ( options . bufferSize && options . bufferSize > 0 ) {
162+ socket . setRecvBufferSize ( options . bufferSize ) ;
163+ }
164+ socket . send ( request , 0 , request . length , 3702 , '239.255.255.250' ) ;
165+ }
166+ } ;
150167 // If device is specified try to bind to that interface
168+ var shouldBind = false ;
151169 if ( options . device ) {
152170 var interfaces = os . networkInterfaces ( ) ;
153171 // Try to find the interface based on the device name
154172 if ( options . device in interfaces ) {
155173 interfaces [ options . device ] . some ( function ( address ) {
156174 // Only use IPv4 addresses
157175 if ( address . family === 'IPv4' ) {
158- socket . bind ( options . listeningPort || null , address . address ) ;
176+ socket . bind ( options . listeningPort || null , address . address , bindingCallback ) ;
177+ shouldBind = true ;
159178 return true ;
160179 }
161180 } ) ;
162181 }
163182 }
164183
184+ // If no device is specified, bind to the default port
185+ if ( ! shouldBind ) {
186+ socket . bind ( options . listeningPort || null , bindingCallback ) ;
187+ }
188+
165189 socket . on ( 'message' , listener ) ;
166- socket . send ( request , 0 , request . length , 3702 , '239.255.255.250' ) ;
167190
168191 setTimeout ( function ( ) {
169192 socket . removeListener ( 'message' , listener ) ;
0 commit comments