/*
CVSNT mdns helpers - minimdns
Copyright (C) 2004-5 Tony Hoyle and March-Hare Software Ltd
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <config.h>
#include "lib/api_system.h"
#include "cvs_string.h"
#include "mdns_mini.h"
#include "ServerIO.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#define sock_errno WSAGetLastError()
#else
#define SOCKET int
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define sock_errno errno
#endif
void CMdnsHelperMini::_browse_srv_func(const char *name, uint16_t port, const char *target, void *userdata)
{
((CMdnsHelperMini*)userdata)->browse_srv_func(name,port,target);
}
void CMdnsHelperMini::browse_srv_func(const char *name, uint16_t port, const char *target)
{
m_callbacks->srv_fn(name,port,target,m_userdata);
}
void CMdnsHelperMini::_browse_txt_func(const char *name, const char *txt, void *userdata)
{
((CMdnsHelperMini*)userdata)->browse_txt_func(name,txt);
}
void CMdnsHelperMini::browse_txt_func(const char *name, const char *txt)
{
m_callbacks->txt_fn(name,txt,m_userdata);
}
void CMdnsHelperMini::_browse_ipv4_func(const char *name, const ipv4_address_t *ipv4, void *userdata)
{
((CMdnsHelperMini*)userdata)->browse_ipv4_func(name,ipv4);
}
void CMdnsHelperMini::browse_ipv4_func(const char *name, const ipv4_address_t *ipv4)
{
m_callbacks->ipv4_fn(name,ipv4->address,m_userdata);
}
void CMdnsHelperMini::_browse_ipv6_func(const char *name, const ipv6_address_t *ipv6, void *userdata)
{
((CMdnsHelperMini*)userdata)->browse_ipv6_func(name,ipv6);
}
void CMdnsHelperMini::browse_ipv6_func(const char *name, const ipv6_address_t *ipv6)
{
m_callbacks->ipv6_fn(name,ipv6->address,m_userdata);
}
CMdnsHelperMini::CMdnsHelperMini()
{
m_handle = NULL;
}
CMdnsHelperMini::~CMdnsHelperMini()
{
close();
}
int CMdnsHelperMini::open()
{
m_handle = mdns_open();
return m_handle?0:-1;
}
int CMdnsHelperMini::publish(const char *instance, const char *service, const char *location, int port, const char *text)
{
char host[1024];
char tmp[256];
strncpy(tmp,service,sizeof(tmp));
char *p=tmp+strlen(tmp)-1;
if(strlen(tmp)>0 && *p=='.') *(p--)='\0';
if(strlen(tmp)>6 && !strcmp(p-5,".local")) *(p-5)='\0';
service = tmp;
int ret;
mdns_service_item_t *serv = new mdns_service_item_t;
serv->Instance = strdup(instance);
serv->Service = strdup(service);
serv->Port = port;
serv->Location = NULL;
serv->ipv4 = NULL;
serv->ipv6 = NULL;
if(gethostname(host,sizeof(host)))
strcpy(host,"unknown");
p=strchr(host,'.');
if(p) *p='\0';
strcat(host,".local");
serv->Location = strdup(host);
if(!location)
{
if(gethostname(host,sizeof(host)))
strcpy(host,"unknown");
location = host;
}
addrinfo hint = {0}, *addr = NULL, *ai;
int err=getaddrinfo(location,NULL,&hint,&addr);
if(err)
{
#ifdef EAI_SYSTEM
if(err==EAI_SYSTEM) err=sock_errno;
#endif
CServerIo::trace(3,"Unable to resolve host %s: %s",location,gai_strerror(err));
return false;
}
for(ai = addr; ai; ai=ai->ai_next)
{
if(ai->ai_family==PF_INET6 && !serv->ipv6)
{
sockaddr_in6 *sin = (sockaddr_in6*)ai->ai_addr;
serv->ipv6 = new ipv6_address_t;
memcpy(serv->ipv6->address,&sin->sin6_addr,sizeof(serv->ipv6->address));
}
if(ai->ai_family==PF_INET && !serv->ipv4)
{
sockaddr_in *sin = (sockaddr_in*)ai->ai_addr;
int type = ntohl(sin->sin_addr.s_addr)>>24;
if(type!=127 && type!=255)
{
serv->ipv4 = new ipv4_address_t;
memcpy(serv->ipv4->address,&sin->sin_addr,sizeof(serv->ipv4->address));
}
else
{
printf("Hostname %s returned loopback address! Invalid DNS configuration.\n");
}
}
}
freeaddrinfo(addr);
if(!(ret=mdns_add_service(m_handle,serv)))
{
m_services.push_back(serv);
}
else
{
if(serv->Instance) free((void*)serv->Instance);
if(serv->Service) free((void*)serv->Service);
if(serv->Location) free((void*)serv->Location);
delete serv->ipv4;
delete serv->ipv6;
delete serv;
}
return ret;
}
int CMdnsHelperMini::step()
{
return mdns_server_step(m_handle);
}
int CMdnsHelperMini::browse(const char *service, MdnsBrowseCallback *callbacks, void *userdata)
{
struct mdns_callback serv_fn =
{
NULL,/*name_func*/
_browse_srv_func,
_browse_txt_func,
_browse_ipv4_func,
_browse_ipv6_func
};
if(!callbacks->ipv4_fn)
serv_fn.ipv4_func = NULL;
if(!callbacks->ipv6_fn)
serv_fn.ipv6_func = NULL;
if(!callbacks->txt_fn)
serv_fn.txt_func = NULL;
if(!callbacks->srv_fn)
serv_fn.srv_func = NULL;
m_userdata = userdata;
m_callbacks = callbacks;
return mdns_query_services(m_handle,service,&serv_fn,this,0);
}
int CMdnsHelperMini::close()
{
mdns_close(m_handle);
m_handle = NULL;
for(size_t n=0; n<m_services.size(); n++)
{
mdns_service_item_t *serv = m_services[n];
if(serv->Instance) free((void*)serv->Instance);
if(serv->Service) free((void*)serv->Service);
if(serv->Location) free((void*)serv->Location);
delete serv->ipv4;
delete serv->ipv6;
delete serv;
}
m_services.resize(0);
return 0;
}
extern "C" CMdnsHelperBase *MdnsHelperMini_Alloc()
{
return new CMdnsHelperMini();
}
syntax highlighted by Code2HTML, v. 0.9.1