summaryrefslogtreecommitdiff
path: root/protocol/discovery/mdns.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocol/discovery/mdns.c')
-rw-r--r--protocol/discovery/mdns.c496
1 files changed, 0 insertions, 496 deletions
diff --git a/protocol/discovery/mdns.c b/protocol/discovery/mdns.c
deleted file mode 100644
index abca295af..000000000
--- a/protocol/discovery/mdns.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/*****************************************************************************
- mdns.c - mDNS related calls
-
- (c) 2015 Copyright HP Development Company, LP
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is furnished to do
- so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Client/Server generic message format (see messaging-protocol.doc):
-
- Author: Sanjay Kumar
- \*****************************************************************************/
-
-//#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include "mdns.h"
-
-/* Convert "www.google.com" to "3www6google3com". */
-static int mdns_convert_name_to_dns(const char *name, int name_size, char *dns_name)
-{
- int i, x = 0;
- char *p = dns_name;
-
- if (name == 0 || name[0] == 0)
- return 0;
-
- for (i = 0; i < name_size && name[i]; i++)
- {
- if (name[i] == '.')
- {
- *p++ = i - x; /* length */
- for (; x < i; x++)
- *p++ = name[x];
- x++;
- }
- }
-
- if (i)
- {
- *p++ = i - x; /* length */
- for (; x < i; x++)
- *p++ = name[x];
- x++;
- }
-
- p[x++] = 0;
-
- return x; /* return length DOES include null termination */
-}
-
-
-static int mdns_open_socket(int *psocket)
-{
- int stat = MDNS_STATUS_ERROR;
- int udp_socket = -1, yes = 1;
- char loop = 0, ttl = 255;
- struct sockaddr_in recv_addr , addr;
- struct ip_mreq mreq;
-
- DBG("mdns_open_socket entry.\n");
-
- if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- {
- BUG("unable to create udp socket: %m\n");
- goto bugout;
- }
-
- /* Get rid of "address already in use" error message. */
- if (setsockopt(udp_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
- {
- BUG("unable to setsockopt: %m\n");
- goto bugout;
- }
-
- /* Bind the socket to port and IP equal to INADDR_ANY. */
- bzero(&recv_addr, sizeof(recv_addr));
- recv_addr.sin_family = AF_INET;
- recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- recv_addr.sin_port = htons(5353);
- if (bind(udp_socket, (struct sockaddr *) &recv_addr, sizeof(recv_addr)) == -1)
- {
- BUG("unable to bind udp socket: %m\n");
- goto bugout;
- }
-
- /* Set multicast loopback off. */
- if (setsockopt(udp_socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) == -1)
- {
- BUG("unable to setsockopt: %m\n");
- goto bugout;
- }
-
- /* Set ttl to 255. Required by mdns. */
- if (setsockopt(udp_socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))== -1)
- {
- BUG("unable to setsockopt: %m\n");
- goto bugout;
- }
-
- /* Join the .local multicast group */
- mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.251");
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- if (setsockopt(udp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1) {
- BUG("unable to add to multicast group: %m\n");
- close(udp_socket);
- goto bugout;
- }
-
- *psocket = udp_socket;
- DBG("pSocket = [%d]: %m\n", *psocket);
- stat = MDNS_STATUS_OK;
-
-bugout:
- return stat;
-}
-
-static void mdns_create_query_packet(char* fqdn, int query_type, char* querybuf, int *length)
-{
- int n = 0;
- char header[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- // ID/FLAGS/QDCNT/ANCNT/NSCNT/ARCNT
-
- DBG("mdns_create_query_packet.\n");
- memcpy(querybuf, header, sizeof(header));
- n = sizeof(header);
-
- n += mdns_convert_name_to_dns(fqdn, strlen(fqdn), querybuf + n);
- querybuf[n++] = 0x00;
- querybuf[n++] = query_type;
- querybuf[n++] = 0x00;
- querybuf[n++] = QCLASS_IN;
-
- //DBG_DUMP(dnsquery, n);
- *length = n;
-}
-
-static int mdns_send_query(int udp_socket, char *fqdn, int query_type)
-{
- char querybuf[256] = {0,};
- int length = 0;
- int stat = MDNS_STATUS_OK;
- struct sockaddr_in send_addr;
-
- DBG("mdns_send_query entry. send socket=%d len=%d\n", udp_socket, length);
-
- mdns_create_query_packet(fqdn, query_type, querybuf, &length);
-
- bzero(&send_addr, sizeof(send_addr));
- send_addr.sin_family = AF_INET;
- send_addr.sin_addr.s_addr = inet_addr("224.0.0.251");
- send_addr.sin_port = htons(5353);
- if (sendto(udp_socket, querybuf, length, 0, (struct sockaddr *) &send_addr, sizeof(send_addr)) < 0)
- stat = MDNS_STATUS_ERROR;
-
- DBG("mdns_send_query returning with status(%d)...\n", stat);
- return stat;
-}
-
-static int mdns_readName(unsigned char* start, unsigned char *Response, char *buf)
-{
- int size = 0;
- char *name = buf;
- unsigned char *p = Response;
-
- while (size = *p++)
- {
- if (size >= 0xC0)
- {
- //Compressed Size. Just ignore it.
- p++; //skip Offset byte
- return (p - Response);
- }
- memcpy(name, p, size);
- name[size] = '.';
- p += size;
- name += size + 1;
- }
-
- *(name - 1) = '\0';
-
- DBG("Name = [%s]\n", buf);
- return (p - Response);
-}
-
-
-static unsigned char* mdns_readMDL(unsigned char *p, unsigned char *normalized_mdl, int len)
-{
- int i = 0;
- int j = 0;
- int z = 0;
- int size = 0;
-
- unsigned char* mdl = normalized_mdl;
- while (i < len)
- {
- size = *p++;
- i += size + 1;
-
- if (strncmp(p, "mdl=", 4) == 0)
- {
- z = 4;
- }
- else if (strncmp(p, "ty=", 3) == 0)
- {
- z = 3+3;
- }
-
- if(z > 0)
- {
- for (j = z; j < size; j++)
- {
- if (*(p + j) == ' ')
- *mdl++ = '_'; //Replace white space with underscore
- else
- *mdl++ = tolower(*(p + j));
- }
-
- *mdl++ = '\0';
- break;
- }
- p += size;
-
- }
- DBG("MDL = [%s]\n", normalized_mdl);
- return p + 4;
-}
-
-static void mdns_read_header(char *Response, DNS_PKT_HEADER *h)
-{
- h->id = Response[0] << 8 | Response[1];
- h->flags = Response[2] << 8 | Response[3];
- h->questions = Response[4] << 8 | Response[5];
- h->answers = Response[6] << 8 | Response[7];
- h->authorities = Response[8] << 8 | Response[9];
- h->additionals = Response[10]<< 8 | Response[11];
-
- DBG("ID=%x flags=%x Q=%x A=%x AUTH=%x ADD=%x\n", h->id, h->flags, h->questions,
- h->answers, h->authorities, h->additionals);
-
-}
-
-static void mdns_parse_respponse(unsigned char *Response, DNS_RECORD *rr)
-{
- unsigned char *p = Response;
- unsigned short type = 0, data_len = 0;
- DNS_PKT_HEADER h;
- int i = 0;
-
- DBG("mdns_parse_respponse entry.\n");
- mdns_read_header(Response, &h);
- p += MDNS_HEADER_SIZE;
-
- for (i = 0; i < h.questions; i++)
- {
- p += mdns_readName(Response, p, rr->name);
- p += 4; //Skip TYPE(2 bytes)/CLASS(2 bytes)
- }
-
- for (i = 0; i < (h.answers + h.additionals); i++)
- {
- p += mdns_readName(Response, p, rr->name);
- type = (*p << 8 | *(p+1));
- p += 8; //Skip type(2 bytes)/class(2 bytes)/TTL(4 bytes)
-
- data_len = ( *p << 8 | *(p+1));
- p += 2; //Skip data_len(2 bytes)
-
- switch (type)
- {
- case QTYPE_A:
- sprintf(rr->ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
- break;
- case QTYPE_TXT:
- mdns_readMDL(p, rr->mdl, data_len);
- break;
- default:
- break;
- }
-
- p += data_len;
- //DBG("TYPE = %d, Length = %d\n",type, data_len);
- }
-
- DBG("mdns_parse_respponse returning MDL = %s, IP = %s\n",rr->mdl, rr->ip);
-}
-
-static int mdns_read_single_response(int udp_socket, char *recvbuffer, int recvbufsize)
-{
- struct timeval tmo;
- struct sockaddr_in addr;
- socklen_t addrlen = sizeof(addr);
- fd_set master, readfd;
- int len = 0, maxfd = 0, ret = 0;
-
- DBG("mdns_read_single_response.\n");
- FD_ZERO(&master);
- FD_SET(udp_socket, &master);
- maxfd = udp_socket;
- tmo.tv_sec = 0;
- tmo.tv_usec = 300000;
-
- readfd = master;
- ret = select(maxfd + 1, &readfd, NULL, NULL, &tmo);
- if (ret > 0)
- {
- bzero(&addr, sizeof(addr));
- if ((len = recvfrom(udp_socket, recvbuffer, recvbufsize, 0, (struct sockaddr *) &addr, &addrlen)) < 0)
- {
- BUG("recvfrom error: (%m)\n");
- ret = -1;
- }
- }
-
- DBG("mdns_read_single_response exiting with ret = %d\n", ret);
- return ret;
-}
-
-static DNS_RECORD *mdns_read_responses(int udp_socket, int mode)
-{
- int retries = 3, ret = 0;
- char recvbuffer[MAX_MDNS_RESPONSE_LEN] = { 0, };
- DNS_RECORD *rr = NULL, *head = NULL, *temp = NULL;
-
- DBG("mdns_read_responses.\n");
- while (1 )
- {
- memset(recvbuffer, 0, sizeof(recvbuffer));
- ret = mdns_read_single_response(udp_socket, recvbuffer, sizeof(recvbuffer));
- if (ret <= 0)
- {
- if (ret == 0 && retries--) //READ TIMEOUT. Retry few more times.
- continue;
- else
- break;
- }
- else
- {
- temp = (DNS_RECORD *)malloc(sizeof(DNS_RECORD));
- if(temp)
- {
- temp->next = NULL;
- if(head == NULL)
- rr = head = temp;
- else
- {
- rr->next = temp;
- rr = rr->next;
- }
-
- memset(rr, 0, sizeof(DNS_RECORD));
- mdns_parse_respponse(recvbuffer, rr);
-
- if(mode == MODE_READ_SINGLE)
- break;
- }
- }
- } // while(1)
-
- DBG("mdns_read_responses returning with (%p).\n", head);
- return head;
-}
-
-static int mdns_update_uris(DNS_RECORD *rr, char* uris_buf, int buf_size, int *count)
-{
- char tempuri[MAX_URI_LEN] = {0};
- int bytes_read = 0;
-
- DBG("mdns_update_uris.\n");
-
- *count = 0;
- memset(uris_buf, 0, buf_size);
-
- while(rr)
- {
- if (rr->mdl[0] && rr->ip[0] /*&& strstr(rr->mdl, "scanjet")*/)
- {
- memset(tempuri, 0, sizeof(tempuri));
- sprintf(tempuri, "hp:/net/%s?ip=%s&queue=false", rr->mdl, rr->ip);
-
- //Check whether buffer has enough space to add new URI and check for duplicate URIs.
- if(bytes_read + sizeof(tempuri) < buf_size && !strstr(uris_buf, tempuri))
- {
- bytes_read += sprintf(uris_buf + bytes_read, "%s;", tempuri);
- (*count)++;
- *(uris_buf + bytes_read) = '\0';
- }
- }
- rr = rr->next;
- }
-
- DBG("mdns_update_uris Count=[%d] bytes=[%d] URIs = %s\n",*count, bytes_read, uris_buf);
- return bytes_read;
-}
-
-static void mdns_rr_cleanup(DNS_RECORD *rr)
-{
- DNS_RECORD *temp = NULL;
-
- DBG("mdns_rr_cleanup entry.\n");
- while(rr)
- {
- temp = rr->next;
- free(rr);
- rr = temp;
- }
-}
-
-int mdns_probe_nw_scanners(char* uris_buf, int buf_size, int *count)
-{
- int n = 0, bytes_read = 0;
- int udp_socket = 0;
- int stat = MDNS_STATUS_ERROR;
- DNS_RECORD *rr_list = NULL;
-
- DBG("mdns_probe_nw_scanners entry.\n");
- /* Open UDP socket */
- if (mdns_open_socket(&udp_socket) != MDNS_STATUS_OK)
- goto bugout;
-
- /* Send dns query */
- mdns_send_query(udp_socket, "_scanner._tcp.local", QTYPE_PTR);
- mdns_send_query(udp_socket, "_uscan._tcp.local", QTYPE_PTR);
-
- /* Read Responses */
- rr_list = mdns_read_responses(udp_socket, MODE_READ_ALL);
-
- /* Update URIs buffer */
- bytes_read = mdns_update_uris(rr_list, uris_buf, buf_size, count);
- DBG("mdns_probe_nw_scanners returned with bytes_read = [%d].\n",bytes_read);
-
-bugout:
- if (udp_socket >= 0)
- close(udp_socket);
-
- mdns_rr_cleanup(rr_list);
-
- return bytes_read;
-}
-
-/*
- * Lookup IP for MDNS host name.
- * MDNS host name example: "npi7c8a3e" (LaserJet p2055dn)
- */
-int mdns_lookup(char* hostname, unsigned char* ip)
-{
- int udp_socket = 0;
- int stat = MDNS_STATUS_ERROR;
- char fqdn[MAX_NAME_LENGTH] = {0};
- DNS_RECORD *rr_list = NULL;
-
- DBG("mdns_probe_nw_scanners entry.\n");
- /* Open UDP socket */
- if (mdns_open_socket(&udp_socket) != MDNS_STATUS_OK)
- goto bugout;
-
- /* Send dns query */
- sprintf(fqdn, "%s.local", hostname);
- mdns_send_query(udp_socket, fqdn, QTYPE_A);
-
- /* Read Responses */
- rr_list = mdns_read_responses(udp_socket, MODE_READ_SINGLE);
-
- /* Update IP Address buffer */
- if(rr_list)
- {
- strcpy(ip, rr_list->ip);
- stat = MDNS_STATUS_OK;
- DBG("IP = [%s].\n",ip);
- }
-
-bugout:
- if (udp_socket >= 0)
- close(udp_socket);
-
- mdns_rr_cleanup(rr_list);
- return stat;
-}
-