/// <summary> /// Attempts to advertise the service on the network. /// </summary> public void Publish() { Stop(); registerReplyCb = new mDNSImports.DNSServiceRegisterReply(RegisterReply); DNSServiceErrorType err; ushort txtRecordLen = (TXTRecordData != null) ? Convert.ToUInt16(TXTRecordData.Length) : (ushort)0; ushort port = (ushort)System.Net.IPAddress.HostToNetworkOrder((short)mPort); err = mDNSImports.DNSServiceRegister(out registeredServiceHandle, 0, 0, Name, Type, Domain, null, port, txtRecordLen, TXTRecordData, registerReplyCb, IntPtr.Zero); if (err == DNSServiceErrorType.NoError) { SetupWatchSocket(registeredServiceHandle); } else { Stop(); if (DidNotPublishService != null) { DNSServiceException exception = new DNSServiceException("DNSServiceRegister", err); DidNotPublishService(this, exception); } } }
/// <summary> /// Called with the result of the call to DNSServiceRegister() in the Publish() method. /// /// If this object instance is configured with an <see cref="DNSService.InvokeableObject">InvokeableObject</see>, /// this method is called in a thread safe manner. Typically, this means it's called on the application main loop. /// </summary> /// <param name="sdRef"> /// The DNSServiceRef initialized by DNSServiceRegister(). /// </param> /// <param name="flags"> /// Currently unused, reserved for future use. /// </param> /// <param name="errorCode"> /// Will be NoError on success, otherwise will indicate the failure that occurred /// (including name conflicts, if the kDNSServiceFlagsNoAutoRename flag was used when registering.) /// Other parameters are undefined if errorCode is nonzero. /// </param> /// <param name="name"> /// The service name registered (if the application did not specify a name in /// DNSServiceRegister(), this indicates what name was automatically chosen). /// </param> /// <param name="regtype"> /// The type of service registered, as it was passed to the callout. /// </param> /// <param name="domain"> /// The domain on which the service was registered (if the application did not /// specify a domain in DNSServiceRegister(), this indicates the default domain /// on which the service was registered). /// </param> /// <param name="context"> /// The context pointer that was passed to the callout. /// </param> private void RegisterReply(IntPtr sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, String name, String regtype, String domain, IntPtr context) { if (errorCode == DNSServiceErrorType.NoError) { // Update name, type domain to match what was actually published mName = name; mType = regtype; mDomain = domain; if (DidPublishService != null) { DidPublishService(this); } } else { Stop(); if (DidNotPublishService != null) { DNSServiceException exception = new DNSServiceException("DNSServiceRegister", errorCode); DidNotPublishService(this, exception); } } }
/// <summary> /// Starts a resolve process with a timeout. /// </summary> /// <param name="seconds">The maximum number of seconds to attempt a resolve.</param> public void ResolveWithTimeout(int seconds) { Stop(); resolveReplyCb = new mDNSImports.DNSServiceResolveReply(ResolveReply); DNSServiceErrorType err; err = mDNSImports.DNSServiceResolve(out registeredServiceHandle, 0, 0, Name, Type, Domain, resolveReplyCb, IntPtr.Zero); if (err == DNSServiceErrorType.NoError) { SetupWatchSocket(registeredServiceHandle); resolveTimer = new System.Threading.Timer(new TimerCallback(ResolveTimerCallback), resolveReplyCb, (seconds * 1000), Timeout.Infinite); } else { Stop(); if (DidNotResolveService != null) { DNSServiceException exception = new DNSServiceException("DNSServiceResolve", err); DidNotResolveService(this, exception); } } }
/// <summary> /// Called with the result of the call to DNSServiceResolve(). /// /// If this object instance is configured with an <see cref="DNSService.InvokeableObject">InvokeableObject</see>, /// this method is called in a thread safe manner. Typically, this means it's called on the application main loop. /// </summary> /// <param name="sdRef"> /// The DNSServiceRef initialized by DNSServiceResolve(). /// </param> /// <param name="flags"> /// Currently unused, reserved for future use. /// </param> /// <param name="interfaceIndex"> /// The interface on which the service was resolved. /// </param> /// <param name="errorCode"> /// Will be NoError (0) on success, otherwise will indicate the failure that occurred. /// Other parameters are undefined if the errorCode is nonzero. /// </param> /// <param name="fullname"> /// The full service domain name, in the form [servicename].[protocol].[domain]. /// (This name is escaped following standard DNS rules, making it suitable for /// passing to standard system DNS APIs such as res_query(), or to the /// special-purpose functions included in this API that take fullname parameters.) /// </param> /// <param name="hosttarget"> /// The target hostname of the machine providing the service. This name can /// be passed to functions like gethostbyname() to identify the host's IP address. /// </param> /// <param name="port"> /// The port, in network byte order, on which connections are accepted for this service. /// </param> /// <param name="txtLen"> /// The length of the txt record, in bytes. /// </param> /// <param name="txtRecord"> /// The service's primary txt record, in standard txt record format. /// </param> /// <param name="context"> /// The context pointer that was passed to the callout. /// </param> private void ResolveReply(IntPtr sdRef, DNSServiceFlags flags, UInt32 interfaceIndex, DNSServiceErrorType errorCode, String fullname, String hosttarget, UInt16 port, UInt16 txtLen, byte[] txtRecord, IntPtr context) { if (errorCode == DNSServiceErrorType.NoError) { // Update internal variables mHostName = hosttarget; mPort = ((int)System.Net.IPAddress.NetworkToHostOrder((short)port) & 0x0000ffff); // We may want to update the txt record. // The service may not have a txt record yet if it's never been monitored or resolved before. // Also, if it's not currently being monitored, then the returned txt record may include updates if (mTXTRecordData == null || !NetService.ByteArrayCompare(mTXTRecordData, txtRecord)) { mTXTRecordData = txtRecord; // Invoke delegate if set if (DidUpdateTXT != null) { DidUpdateTXT(this); } } // At this point we have a host name, but we don't have the actual IP address. // We could use the Windows API's (System.Net.Dns.BeginGetHostEntry) to // convert from host name to IP, but they're painfully slow. // According to the following website (and my own personal testing), // using DNSServiceQueryRecord is much faster: // http://lists.apple.com/archives/Bonjour-dev/2006/Jan/msg00008.html //AsyncCallback cb = new AsyncCallback(c.AsyncGetHostEntryCallback); //IAsyncResult ar = System.Net.Dns.BeginGetHostEntry(hosttarget, cb, c); // Begin the process of looking up the IP address(es) IPLookup(); } else { Stop(); if (DidNotResolveService != null) { DNSServiceException exception = new DNSServiceException("DNSServiceResolve", errorCode); DidNotResolveService(this, exception); } } }
void publishService_DidNotPublishService(NetService service, DNSServiceException exception) { MessageBox.Show(String.Format("A DNSServiceException occured: {0}", exception.Message), "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); serviceNameTextBox.Enabled = true; serviceTypeTextBox.Enabled = true; portTextBox.Enabled = true; startStopButton.Text = "Publish"; startStopButton.Enabled = true; mPublishing = false; }
/// <summary> /// Called when the resolve timer fires. /// /// If this object instance is configured with an <see cref="DNSService.InvokeableObject">InvokeableObject</see>, /// this method is called in a thread safe manner. Typically, this means it's called on the application main loop. /// </summary> /// <param name="state">The object passed to the timer during initialization.</param> private void ResolveTimerReply(object state) { mDNSImports.DNSServiceResolveReply resolveReplyCbThen = (mDNSImports.DNSServiceResolveReply)state; if (resolveReplyCbThen == resolveReplyCb) { Stop(); if (DidNotResolveService != null) { DNSServiceException exception = new DNSServiceException("Timeout", DNSServiceErrorType.Timeout); DidNotResolveService(this, exception); } } }
/// <summary> /// Called with the result of the call to DNSServiceQueryRecord() in the IPLookup() method. /// /// If this object instance is configured with an <see cref="DNSService.InvokeableObject">InvokeableObject</see>, /// this method is called in a thread safe manner. Typically, this means it's called on the application main loop. /// </summary> /// <param name="sdRef"> /// The DNSServiceRef initialized by DNSServiceQueryRecord(). /// </param> /// <param name="flags"> /// Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd. /// The Add flag is NOT set for PTR records with a ttl of 0, i.e. "Remove" events. /// </param> /// <param name="interfaceIndex"> /// The interface on which the query was resolved. /// </param> /// <param name="errorCode"> /// Will be NoError on success, otherwise will indicate the failure that occurred. /// Other parameters are undefined if errorCode is nonzero. /// </param> /// <param name="fullname"> /// The resource record's full domain name. /// </param> /// <param name="rrType"> /// The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) /// </param> /// <param name="rrClass"> /// The class of the resource record (usually kDNSServiceClass_IN). /// </param> /// <param name="rdLength"> /// The length, in bytes, of the resource record rdata. /// </param> /// <param name="rData"> /// The raw rdata of the resource record. /// </param> /// <param name="ttl"> /// The resource record's time to live, in seconds. /// </param> /// <param name="context"> /// The context pointer that was passed to the callout. /// </param> private void IPLookupReply(IntPtr sdRef, DNSServiceFlags flags, UInt32 interfaceIndex, DNSServiceErrorType errorCode, String fullname, DNSServiceType rrType, DNSServiceClass rrClass, UInt16 rdLength, byte[] rData, UInt32 ttl, IntPtr context) { if (errorCode == DNSServiceErrorType.NoError) { if ((flags & DNSServiceFlags.Add) > 0) { System.Net.IPAddress addr = new System.Net.IPAddress(rData); System.Net.IPEndPoint ep = new System.Net.IPEndPoint(addr, mPort); mAddresses.Add(ep); } if ((flags & DNSServiceFlags.MoreComing) == 0) { Stop(); if (DidResolveService != null) { DidResolveService(this); } } } else { Stop(); if (DidNotResolveService != null) { DNSServiceException exception = new DNSServiceException("DNSServiceQueryRecord", errorCode); DidNotResolveService(this, exception); } } }
/// <summary> /// This method begins the process of looking up the IP address(es) associated with the current hostname. /// </summary> private void IPLookup() { mAddresses = new ArrayList(); ipLookupReplyCb = new mDNSImports.DNSServiceQueryReply(IPLookupReply); DNSServiceErrorType err; err = mDNSImports.DNSServiceQueryRecord(out ipLookupQueryHandle, 0, 0, HostName, DNSServiceType.A, DNSServiceClass.IN, ipLookupReplyCb, IntPtr.Zero); if (err == DNSServiceErrorType.NoError) { SetupWatchSocket(ipLookupQueryHandle); } else { Stop(); if (DidNotResolveService != null) { DNSServiceException exception = new DNSServiceException("DNSServiceQueryRecord", err); DidNotResolveService(this, exception); } } }
private void FailedToPublishService(NetService service, DNSServiceException error) { string msg = String.Format("Failed to publish service {0}", service.Name); Log.Warn(msg, error); }
/// <summary> /// Service couldn't be published /// </summary> /// <param name="service"></param> /// <param name="exception"></param> void publishService_DidNotPublishService(NetService service, DNSServiceException exception) { LogMessage(String.Format("Bonjour publish error: {0}", exception.Message), LogType.Error); }
void publishService_DidNotPublishService(NetService service, DNSServiceException ex) { WriteToLog(Urgency.ERROR, ex.Message); }
/// <summary> /// Called with the result of the call to DNSServiceQueryRecord() in the IPLookup() method. /// /// If this object instance is configured with an <see cref="DNSService.InvokeableObject">InvokeableObject</see>, /// this method is called in a thread safe manner. Typically, this means it's called on the application main loop. /// </summary> /// <param name="sdRef"> /// The DNSServiceRef initialized by DNSServiceQueryRecord(). /// </param> /// <param name="flags"> /// Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd. /// The Add flag is NOT set for PTR records with a ttl of 0, i.e. "Remove" events. /// </param> /// <param name="interfaceIndex"> /// The interface on which the query was resolved. /// </param> /// <param name="errorCode"> /// Will be NoError on success, otherwise will indicate the failure that occurred. /// Other parameters are undefined if errorCode is nonzero. /// </param> /// <param name="fullname"> /// The resource record's full domain name. /// </param> /// <param name="rrType"> /// The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) /// </param> /// <param name="rrClass"> /// The class of the resource record (usually kDNSServiceClass_IN). /// </param> /// <param name="rdLength"> /// The length, in bytes, of the resource record rdata. /// </param> /// <param name="rData"> /// The raw rdata of the resource record. /// </param> /// <param name="ttl"> /// The resource record's time to live, in seconds. /// </param> /// <param name="context"> /// The context pointer that was passed to the callout. /// </param> private void IPLookupReply(IntPtr sdRef, DNSServiceFlags flags, UInt32 interfaceIndex, DNSServiceErrorType errorCode, String fullname, DNSServiceType rrType, DNSServiceClass rrClass, UInt16 rdLength, byte[] rData, UInt32 ttl, IntPtr context) { if (errorCode == DNSServiceErrorType.NoError) { if((flags & DNSServiceFlags.Add) > 0) { System.Net.IPAddress addr = new System.Net.IPAddress(rData); System.Net.IPEndPoint ep = new System.Net.IPEndPoint(addr, mPort); mAddresses.Add(ep); } if ((flags & DNSServiceFlags.MoreComing) == 0) { Stop(); if (DidResolveService != null) { DidResolveService(this); } } } else { Stop(); if (DidNotResolveService != null) { DNSServiceException exception = new DNSServiceException("DNSServiceQueryRecord", errorCode); DidNotResolveService(this, exception); } } }
/// <summary> /// /// </summary> /// <param name="service"></param> /// <param name="exception"></param> static private void publishService_DidNotPublishService(NetService service, DNSServiceException exception) { MessageBox.Show(String.Format("A DNSServiceException occured: {0}", exception.Message), "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); }
void publishService_DidNotPublishService(NetService service, DNSServiceException exception) { }
protected void NetServiceDidNotResolve(NetService sender, DNSServiceException exception) { logger.TraceEvent(TraceEventType.Verbose, 0, String.Format("{0}: didNotResolve: {1}", sender, exception)); }
/// <summary> /// Is called when the service attempted to be published but couldnt be for some reason. /// Conforms to the delegate specified by NetService's DidNotPublishService event. /// Displays error message and quits the application. /// </summary> /// <param name="service">The NetService that failed to successfully publish</param> /// <param name="exception">The exception that occured</param> private void publishService_DidNotPublishService(NetService service, DNSServiceException exception) { LogMessage(String.Format("A DNSServiceException occured: {0}", exception.Message), LogType.Error); Stop(); }