From 2d6bd814e667e2ec76f55afe26d5d80a4c7ec97fa064d2edde2820f77ffc7cfe Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 26 Aug 2016 14:55:31 +0000 Subject: [PATCH] Accepting request 423113 from home:mwilck:branches:Printing - Fixed device communication/detection problems with mdns/Bonjour see https://bugs.launchpad.net/hplip/+bug/1616861 In my home network, the HP printer/scanner (ENVY 5530) often fails with messages like this: hp-toolbox[7119]: [7119]: error: Unable to communicate with device (code=12): hp:/net/ENVY_5530_series?zc=HP3464A9E628B4 I've tracked this down to two problems with the MDNS implementation in HPLIP: 1. On a multi-homed host, HPLIP uses only one interface for MDNS multicast send and receive. This leads to failure if the printer is not on the "default" network. The code uses just INADDR_ANY in its multicast IP_MULTPATH_IF and IP_ADD_MEMBERSHIP setsockopt calls, meaning that the kernel has to figure out the interface to use. This fails if the system has no default route, or if the HP device is on a different network than the default route. The solution is to receive and send multicast on all interfaces. 2. MDNS authorities (including HP printers) don't answer every query, especially the same query is repeated quickly. The latter happens when the HP tools start, causing the MDNS lookup procedure to fail and the "communication error" to be detected. This can be solved by retrying the query after a short wait (1-2s). This build contains fixes for both problems. OBS-URL: https://build.opensuse.org/request/show/423113 OBS-URL: https://build.opensuse.org/package/show/Printing/hplip?expand=0&rev=128 --- hplip-mdns-retry-query.patch | 86 ++++++ hplip-mdns.patch | 553 +++++++++++++++++++++++++++++++++++ hplip.changes | 6 + hplip.spec | 9 +- 4 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 hplip-mdns-retry-query.patch create mode 100644 hplip-mdns.patch diff --git a/hplip-mdns-retry-query.patch b/hplip-mdns-retry-query.patch new file mode 100644 index 0000000..bde0179 --- /dev/null +++ b/hplip-mdns-retry-query.patch @@ -0,0 +1,86 @@ +diff --git a/protocol/discovery/mdns.c b/protocol/discovery/mdns.c +index 92e153a..75ef0ea 100644 +--- a/protocol/discovery/mdns.c ++++ b/protocol/discovery/mdns.c +@@ -436,7 +436,7 @@ static int mdns_read_single_response(int udp_socket, char *recvbuffer, int recvb + FD_SET(udp_socket, &master); + maxfd = udp_socket; + tmo.tv_sec = 0; +- tmo.tv_usec = 300000; ++ tmo.tv_usec = 10000; + + readfd = master; + ret = select(maxfd + 1, &readfd, NULL, NULL, &tmo); +@@ -549,6 +549,34 @@ static void mdns_rr_cleanup(DNS_RECORD *rr) + } + } + ++static DNS_RECORD* send_and_receive(struct mdns_socket *mdns_sock, ++ const char *name, ++ int query_type, int read_mode) ++{ ++ /* wait up to ~1s */ ++ const useconds_t DELTA_T = 251000; ++ const int RETRIES = 8; ++ int retry = RETRIES; ++ DNS_RECORD *rr_list; ++ ++ while (retry) { ++ if (mdns_send_query(mdns_sock, name, query_type) == MDNS_STATUS_OK) { ++ rr_list = mdns_read_responses(mdns_sock->socket, read_mode, name); ++ if (rr_list != NULL) { ++ DBG("send_and_receive: got response after %d retries\n", ++ RETRIES - retry); ++ return rr_list; ++ } ++ } ++ /* MDNS servers delay responses. If the server just responded ++ * to some query (maybe an earlier one we sent), we may need to wait. */ ++ --retry; ++ usleep(DELTA_T); ++ } ++ BUG("send_and_receive: no response after %d retries\n", RETRIES); ++ return NULL; ++} ++ + int mdns_probe_nw_scanners(char* uris_buf, int buf_size, int *count) + { + int n = 0, bytes_read = 0; +@@ -562,11 +590,7 @@ int mdns_probe_nw_scanners(char* uris_buf, int buf_size, int *count) + if (mdns_open_socket(&mdns_sock) != MDNS_STATUS_OK) + goto bugout; + +- /* Send dns query */ +- mdns_send_query(&mdns_sock, scanner_name, QTYPE_PTR); +- +- /* Read Responses */ +- rr_list = mdns_read_responses(mdns_sock.socket, MODE_READ_ALL, scanner_name); ++ rr_list = send_and_receive(&mdns_sock, scanner_name, QTYPE_PTR, MODE_READ_ALL); + + /* Update URIs buffer */ + bytes_read = mdns_update_uris(rr_list, uris_buf, buf_size, count); +@@ -598,10 +622,8 @@ int mdns_lookup(char* hostname, unsigned char* ip) + + /* Send dns query */ + sprintf(fqdn, "%s.local", hostname); +- mdns_send_query(&mdns_sock, fqdn, QTYPE_A); + +- /* Read Responses */ +- rr_list = mdns_read_responses(mdns_sock.socket, MODE_READ_SINGLE, fqdn); ++ rr_list = send_and_receive(&mdns_sock, fqdn, QTYPE_A, MODE_READ_SINGLE); + + /* Update IP Address buffer */ + if(rr_list) +diff --git a/protocol/discovery/mdns.h b/protocol/discovery/mdns.h +index 34066fb..56d8847 100644 +--- a/protocol/discovery/mdns.h ++++ b/protocol/discovery/mdns.h +@@ -102,5 +102,8 @@ static int mdns_parse_respponse(unsigned char *Response, DNS_RECORD *rr); + static void mdns_rr_cleanup(DNS_RECORD *rr); + static DNS_RECORD *mdns_read_responses(int udp_socket, int mode, const char *question); + static unsigned char* mdns_readMDL(unsigned char *p, unsigned char *normalized_mdl, int len); ++static DNS_RECORD* send_and_receive(struct mdns_socket *mdns_sock, const char *name, ++ int query_type, int read_mode); ++static int get_ipv4_address(const char *iface, struct in_addr *addr); + #endif // _DISCOVERY_MDNS_H + diff --git a/hplip-mdns.patch b/hplip-mdns.patch new file mode 100644 index 0000000..49370de --- /dev/null +++ b/hplip-mdns.patch @@ -0,0 +1,553 @@ +diff --git a/base/mdns.py b/base/mdns.py +index 03bdb92..11d08b8 100644 +--- a/base/mdns.py ++++ b/base/mdns.py +@@ -35,6 +35,17 @@ from .g import * + from . import utils + from .sixext import BytesIO, to_bytes_utf8, to_bytes_latin, to_string_latin + ++if hasattr(socket, "if_nameindex"): ++ if_nameindex = socket.if_nameindex ++else: ++ def _if_nameindex(): ++ """"Poor man's if_nameindex for Python 2.""" ++ import os ++ sysdir = "/sys/class/net" ++ return sorted([ (int(open("%s/%s/ifindex" % (sysdir, iface), "r").read(), 0), iface) ++ for iface in os.listdir(sysdir) ]) ++ if_nameindex = _if_nameindex ++ + MAX_ANSWERS_PER_PACKET = 24 + + QTYPE_A = 1 +@@ -45,6 +56,8 @@ QTYPE_PTR = 12 + + QCLASS_IN = 1 + ++MCAST_ADDR='224.0.0.251' ++ + # Caller needs to ensure, data should be in string format. + def read_utf8(offset, data, l): + return offset+l, data[offset:offset+l] +@@ -188,11 +201,6 @@ def createSocketsWithsetOption(ttl=4): + s=None + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) +- x = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +- x.connect(('1.2.3.4', 56)) +- intf = x.getsockname()[0] +- x.close() +- + s.setblocking(0) + ttl = struct.pack('B', ttl) + except socket.error: +@@ -209,14 +217,42 @@ def createSocketsWithsetOption(ttl=4): + + try: + s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, ttl) +- s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0')) + s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP ,1) + except Exception as e: + log.error("Unable to setup multicast socket for mDNS: %s" % e) + if s: + s.close() + return None +- return s ++ ++ ifaces = [] ++ for idx, name in if_nameindex(): ++ mreqn = struct.pack("=4sii", socket.inet_aton(MCAST_ADDR), ++ socket.ntohl(socket.INADDR_ANY), idx) ++ try: ++ s.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, mreqn) ++ except Exception as e: ++ log.debug("Failed to join multicast group on interface %s: %s" % ++ (name, e)) ++ else: ++ log.debug("Joined multicast group on interface %s" % name) ++ ifaces.append((idx, name)) ++ ++ if len(ifaces) == 0: ++ log.error("failed to join multicast group on any interface") ++ s.close() ++ return None ++ ++ return (s, ifaces) ++ ++def closeSocket(s): ++ for idx, name in if_nameindex(): ++ mreqn = struct.pack("=4sii", socket.inet_aton(MCAST_ADDR), ++ socket.ntohl(socket.INADDR_ANY), idx) ++ try: ++ s.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP, mreqn) ++ except Exception: ++ pass ++ s.close() + + def updateReceivedData(data, answers): + update_spinner() +@@ -299,13 +335,22 @@ def updateReceivedData(data, answers): + break + return y, answers + ++def send_packets(s, answers, name, mcast_addr, mcast_port): ++ for p in create_outgoing_packets(answers): ++ log.debug("Outgoing on %s: (%d)" % (name, len(p))) ++ log.log_data(p, width=16) ++ try: ++ s.sendto(p, 0, (mcast_addr, mcast_port)) ++ except socket.error as e: ++ log.debug("Unable to send broadcast DNS packet on %s: %s" % (name, e)) ++ raise + + def detectNetworkDevices(ttl=4, timeout=10): +- mcast_addr, mcast_port ='224.0.0.251', 5353 ++ mcast_addr, mcast_port =MCAST_ADDR, 5353 + found_devices = {} + answers = [] + +- s = createSocketsWithsetOption(ttl) ++ s, ifaces = createSocketsWithsetOption(ttl) + if not s: + return {} + +@@ -321,14 +366,24 @@ def detectNetworkDevices(ttl=4, timeout=10): + break + + if now >= next: +- try: +- for p in create_outgoing_packets(answers): +- log.debug("Outgoing: (%d)" % len(p)) +- log.log_data(p, width=16) +- s.sendto(p, 0, (mcast_addr, mcast_port)) ++ good = [] ++ for idx, name in ifaces: ++ mreqn = struct.pack("=4sii", socket.inet_aton(mcast_addr), ++ socket.ntohl(socket.INADDR_ANY), idx) ++ try: ++ s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, mreqn) ++ except socket.error as e: ++ log.debug("failed to set IP_MULTICAST_IF on %s" % name) ++ continue ++ try: ++ send_packets(s, answers, name, mcast_addr, mcast_port) ++ except socket.error: ++ continue ++ else: ++ good.append((idx, name)) + +- except socket.error as e: +- log.error("Unable to send broadcast DNS packet: %s" % e) ++ if len(good) == 0: ++ log.error("Failed to send MDNS packet on any interface") + + next += delay + delay *= 2 +@@ -347,7 +402,5 @@ def detectNetworkDevices(ttl=4, timeout=10): + found_devices[y['ip']] = y + + log.debug("Found %d devices" % len(found_devices)) +- s.close() ++ closeSocket(s) + return found_devices +- +- +diff --git a/protocol/discovery/mdns.c b/protocol/discovery/mdns.c +index 3324d2a..92e153a 100644 +--- a/protocol/discovery/mdns.c ++++ b/protocol/discovery/mdns.c +@@ -1,3 +1,4 @@ ++ + /***************************************************************************** + mdns.c - mDNS related calls + +@@ -29,14 +30,17 @@ + #endif + + #include ++#include + #include + #include + #include + #include + #include + #include ++#include + #include "mdns.h" + #include ++#include + + /* Convert "www.google.com" to "3www6google3com". */ + static int mdns_convert_name_to_dns(const char *name, int name_size, char *dns_name) +@@ -71,14 +75,50 @@ static int mdns_convert_name_to_dns(const char *name, int name_size, char *dns_n + return x; /* return length DOES include null termination */ + } + ++#define MREQN_INIT(_mr, index) do { \ ++ (&(_mr))->imr_multiaddr.s_addr = inet_addr("224.0.0.251"); \ ++ (&(_mr))->imr_address.s_addr = htonl(INADDR_ANY); \ ++ (&(_mr))->imr_ifindex = (index); \ ++ } while(0) ++ ++struct mdns_socket { ++ int socket; ++ struct if_nameindex *idx; ++ struct if_nameindex **good; ++}; ++#define MDNS_SOCKET_INIT { .socket = -1, .idx = NULL, .good = NULL, } ++ ++static int get_ipv4_address(const char *iface, struct in_addr *addr) ++{ ++ int s, r; ++ struct ifreq ifr; ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ strncpy(ifr.ifr_name, iface, IFNAMSIZ-1); ++ ++ s = socket(AF_INET, SOCK_DGRAM, 0); ++ r = ioctl(s, SIOCGIFADDR, &ifr); ++ close(s); ++ ++ if (r == -1) { ++ DBG("error in SIOCGIFADDR for %s: %m\n", iface); ++ return MDNS_STATUS_ERROR; ++ } ++ ++ if (addr != NULL) ++ memcpy(addr, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, ++ sizeof(*addr)); ++ return MDNS_STATUS_OK; ++} + +-static int mdns_open_socket(int *psocket) ++static int mdns_open_socket(struct mdns_socket *mdns_sock) + { + int stat = MDNS_STATUS_ERROR; +- int udp_socket = -1, yes = 1; ++ int udp_socket = -1, yes = 1, ifaces; + char loop = 0, ttl = 255; + struct sockaddr_in recv_addr , addr; +- struct ip_mreq mreq; ++ struct ip_mreqn mreqn; ++ struct if_nameindex *idx; + + DBG("mdns_open_socket entry.\n"); + +@@ -120,24 +160,86 @@ static int mdns_open_socket(int *psocket) + 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); ++ mdns_sock->idx = if_nameindex(); ++ if (mdns_sock->idx == NULL) { ++ BUG("if_nameindex failed: %m\n"); ++ goto bugout; ++ } ++ ++ for (idx = mdns_sock->idx, ifaces = 0; ++ idx && (idx->if_index != 0 || idx->if_name != NULL); idx++) { ++ ifaces ++; ++ } ++ ++ mdns_sock->good = calloc(ifaces, sizeof(struct if_nameindex*)); ++ if (mdns_sock->good == NULL) ++ goto bugout; ++ ++ for (idx = mdns_sock->idx, ifaces = 0; ++ idx && (idx->if_index != 0 || idx->if_name != NULL); idx++) { ++ ++ /* Skip lo and interfaces without IPv4 address */ ++ if (!strcmp(idx->if_name, "lo")) ++ continue; ++ if (get_ipv4_address(idx->if_name, NULL) == MDNS_STATUS_ERROR) ++ continue; ++ ++ /* Join the multicast group on each local interface */ ++ MREQN_INIT(mreqn, idx->if_index); ++ if (setsockopt(udp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqn, ++ sizeof(struct ip_mreqn)) == -1) { ++ BUG("unable to add to multicast group for %s: %m\n", idx->if_name); ++ } else { ++ mdns_sock->good[ifaces++] = idx; ++ DBG("added multicast group on interface %s\n", idx->if_name); ++ } ++ } ++ ++ if (ifaces == 0) { ++ BUG("no interfaces for multicast found\n"); + goto bugout; + } + +- *psocket = udp_socket; +- DBG("pSocket = [%d]: %m\n", *psocket); ++ mdns_sock->socket = udp_socket; ++ DBG("Socket = [%d]: %m\n", mdns_sock->socket); + stat = MDNS_STATUS_OK; + + bugout: ++ if (stat != MDNS_STATUS_OK) ++ mdns_close_socket(mdns_sock); + return stat; + } + +-static void mdns_create_query_packet(char* fqdn, int query_type, char* querybuf, int *length) ++static void mdns_close_socket(struct mdns_socket *mdns_sock) ++{ ++ int i; ++ struct if_nameindex *idx; ++ struct ip_mreqn mreqn; ++ if (mdns_sock->socket != -1) { ++ for (i = 0; mdns_sock->good[i]; i++) { ++ idx = mdns_sock->good[i]; ++ MREQN_INIT(mreqn, idx->if_index); ++ if (setsockopt(mdns_sock->socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, ++ &mreqn, sizeof(struct ip_mreqn)) == -1) { ++ BUG("unable to drop multicast group for %s: %m\n", idx->if_name); ++ }; ++ } ++ close(mdns_sock->socket); ++ mdns_sock->socket = -1; ++ } ++ ++ if (mdns_sock->idx != NULL) { ++ if_freenameindex(mdns_sock->idx); ++ mdns_sock->idx = NULL; ++ } ++ ++ if (mdns_sock->good != NULL) { ++ free(mdns_sock->good); ++ mdns_sock->good = NULL; ++ } ++} ++ ++static void mdns_create_query_packet(const 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 }; +@@ -157,14 +259,14 @@ static void mdns_create_query_packet(char* fqdn, int query_type, char* querybuf, + *length = n; + } + +-static int mdns_send_query(int udp_socket, char *fqdn, int query_type) ++static int mdns_send_query(struct mdns_socket *mdns_sock, const char *fqdn, int query_type) + { + char querybuf[256] = {0,}; +- int length = 0; ++ int length = 0, i, success; + int stat = MDNS_STATUS_OK; + struct sockaddr_in send_addr; + +- DBG("mdns_send_query entry. send socket=%d len=%d\n", udp_socket, length); ++ DBG("mdns_send_query entry. send socket=%d len=%d\n", mdns_sock->socket, length); + + mdns_create_query_packet(fqdn, query_type, querybuf, &length); + +@@ -172,8 +274,26 @@ static int mdns_send_query(int udp_socket, char *fqdn, int query_type) + 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; ++ ++ for (i = 0, success = 0; mdns_sock->good[i]; i++) { ++ struct if_nameindex *idx; ++ struct ip_mreqn mreqn; ++ idx = mdns_sock->good[i]; ++ MREQN_INIT(mreqn, idx->if_index); ++ if (setsockopt(mdns_sock->socket, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn)) ++ == -1) { ++ DBG("failed to set IP_MULTICAST_IF to %s\n", idx->if_name); ++ continue; ++ } ++ if (sendto(mdns_sock->socket, querybuf, length, 0, ++ (struct sockaddr *) &send_addr, sizeof(send_addr))< 0) { ++ DBG("failed to send on %s\n", idx->if_name); ++ } else ++ success++; ++ } ++ ++ if (success == 0) ++ stat = MDNS_STATUS_ERROR; + + DBG("mdns_send_query returning with status(%d)...\n", stat); + return stat; +@@ -252,7 +372,7 @@ static void mdns_read_header(char *Response, DNS_PKT_HEADER *h) + + } + +-static void mdns_parse_respponse(unsigned char *Response, DNS_RECORD *rr) ++static int mdns_parse_respponse(unsigned char *Response, DNS_RECORD *rr) + { + unsigned char *p = Response; + unsigned short type = 0, data_len = 0; +@@ -263,6 +383,11 @@ static void mdns_parse_respponse(unsigned char *Response, DNS_RECORD *rr) + mdns_read_header(Response, &h); + p += MDNS_HEADER_SIZE; + ++ if (h.answers + h.additionals <= 0) { ++ DBG("mdns_parse_respponse: no answers"); ++ return MDNS_STATUS_ERROR; ++ } ++ + for (i = 0; i < h.questions; i++) + { + p += mdns_readName(Response, p, rr->name); +@@ -295,6 +420,7 @@ static void mdns_parse_respponse(unsigned char *Response, DNS_RECORD *rr) + } + + DBG("mdns_parse_respponse returning MDL = %s, IP = %s\n",rr->mdl, rr->ip); ++ return MDNS_STATUS_OK; + } + + static int mdns_read_single_response(int udp_socket, char *recvbuffer, int recvbufsize) +@@ -328,7 +454,7 @@ static int mdns_read_single_response(int udp_socket, char *recvbuffer, int recvb + return ret; + } + +-static DNS_RECORD *mdns_read_responses(int udp_socket, int mode) ++static DNS_RECORD *mdns_read_responses(int udp_socket, int mode, const char *question) + { + int retries = 3, ret = 0; + char recvbuffer[MAX_MDNS_RESPONSE_LEN] = { 0, }; +@@ -351,17 +477,22 @@ static DNS_RECORD *mdns_read_responses(int udp_socket, int mode) + 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); ++ memset(temp, 0, sizeof(DNS_RECORD)); ++ if (mdns_parse_respponse(recvbuffer, temp) == MDNS_STATUS_OK && ++ (mode == MODE_READ_ALL || question == NULL || ++ !strncmp(question, temp->name, sizeof(temp->name)-1))) { ++ if(head == NULL) ++ rr = head = temp; ++ else ++ { ++ rr->next = temp; ++ rr = rr->next; ++ } ++ } else { ++ DBG("Parse error or wrong MDNS name"); ++ free(temp); ++ continue; ++ } + + if(mode == MODE_READ_SINGLE) + break; +@@ -421,28 +552,28 @@ static void mdns_rr_cleanup(DNS_RECORD *rr) + int mdns_probe_nw_scanners(char* uris_buf, int buf_size, int *count) + { + int n = 0, bytes_read = 0; +- int udp_socket = 0; ++ struct mdns_socket mdns_sock = MDNS_SOCKET_INIT; + int stat = MDNS_STATUS_ERROR; + DNS_RECORD *rr_list = NULL; ++ const char scanner_name[] = "_scanner._tcp.local"; + + DBG("mdns_probe_nw_scanners entry.\n"); + /* Open UDP socket */ +- if (mdns_open_socket(&udp_socket) != MDNS_STATUS_OK) ++ if (mdns_open_socket(&mdns_sock) != MDNS_STATUS_OK) + goto bugout; + + /* Send dns query */ +- mdns_send_query(udp_socket, "_scanner._tcp.local", QTYPE_PTR); ++ mdns_send_query(&mdns_sock, scanner_name, QTYPE_PTR); + + /* Read Responses */ +- rr_list = mdns_read_responses(udp_socket, MODE_READ_ALL); ++ rr_list = mdns_read_responses(mdns_sock.socket, MODE_READ_ALL, scanner_name); + + /* 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_close_socket(&mdns_sock); + + mdns_rr_cleanup(rr_list); + +@@ -455,22 +586,22 @@ bugout: + */ + int mdns_lookup(char* hostname, unsigned char* ip) + { +- int udp_socket = 0; ++ struct mdns_socket mdns_sock = MDNS_SOCKET_INIT; + 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) ++ if (mdns_open_socket(&mdns_sock) != MDNS_STATUS_OK) + goto bugout; + + /* Send dns query */ + sprintf(fqdn, "%s.local", hostname); +- mdns_send_query(udp_socket, fqdn, QTYPE_A); ++ mdns_send_query(&mdns_sock, fqdn, QTYPE_A); + + /* Read Responses */ +- rr_list = mdns_read_responses(udp_socket, MODE_READ_SINGLE); ++ rr_list = mdns_read_responses(mdns_sock.socket, MODE_READ_SINGLE, fqdn); + + /* Update IP Address buffer */ + if(rr_list) +@@ -481,8 +612,7 @@ int mdns_lookup(char* hostname, unsigned char* ip) + } + + bugout: +- if (udp_socket >= 0) +- close(udp_socket); ++ mdns_close_socket(&mdns_sock); + + mdns_rr_cleanup(rr_list); + return stat; +diff --git a/protocol/discovery/mdns.h b/protocol/discovery/mdns.h +index 8fccc82..34066fb 100644 +--- a/protocol/discovery/mdns.h ++++ b/protocol/discovery/mdns.h +@@ -86,19 +86,21 @@ typedef struct _DNS_PKT_HEADER + int mdns_probe_nw_scanners(char* buf, int buf_size, int *count); + int mdns_lookup(char* hostname, unsigned char* ip); + ++struct mdns_socket; + + /*Helper Function Prototypes*/ + static int mdns_convert_name_to_dns(const char *name, int name_size, char *dns_name); + static int mdns_read_single_response(int udp_socket, char *recvbuffer, int recvbufsize); +-static int mdns_open_socket(int *psocket); +-static int mdns_send_query(int udp_socket, char *fqdn, int query_type); ++static int mdns_open_socket(struct mdns_socket *mdns_sock); ++static void mdns_close_socket(struct mdns_socket *mdns_sock); ++static int mdns_send_query(struct mdns_socket *mdns_sock, const char *fqdn, int query_type); + static int mdns_readName(unsigned char* start, unsigned char *p, char *buf); + static int mdns_update_uris(DNS_RECORD *rr, char* uris_buf, int buf_size, int *count); +-static void mdns_create_query_packet(char* fqdn, int query_type, char* dnsquery, int *length); ++static void mdns_create_query_packet(const char* fqdn, int query_type, char* dnsquery, int *length); + static void mdns_read_header(char *Response, DNS_PKT_HEADER *h); +-static void mdns_parse_respponse(unsigned char *Response, DNS_RECORD *rr); ++static int mdns_parse_respponse(unsigned char *Response, DNS_RECORD *rr); + static void mdns_rr_cleanup(DNS_RECORD *rr); +-static DNS_RECORD *mdns_read_responses(int udp_socket, int mode); ++static DNS_RECORD *mdns_read_responses(int udp_socket, int mode, const char *question); + static unsigned char* mdns_readMDL(unsigned char *p, unsigned char *normalized_mdl, int len); + #endif // _DISCOVERY_MDNS_H + diff --git a/hplip.changes b/hplip.changes index a811496..0390138 100644 --- a/hplip.changes +++ b/hplip.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Aug 26 13:10:15 UTC 2016 - martin.wilck@suse.com + +- Fixed device communication/detection problems with mdns/Bonjour + see https://bugs.launchpad.net/hplip/+bug/1616861 + ------------------------------------------------------------------- Mon Jun 6 07:06:46 UTC 2016 - jweberhofer@weberhofer.at diff --git a/hplip.spec b/hplip.spec index f46336e..56f5c00 100644 --- a/hplip.spec +++ b/hplip.spec @@ -56,6 +56,10 @@ Patch107: hplip-udev-rules-in-usr.patch # Patch108 add_missing_includes_and_define_GNU_SOURCE.patch adds missing '#include <...>' # and missing '#define _GNU_SOURCE' see https://bugs.launchpad.net/hplip/+bug/1456590 Patch108: add_missing_includes_and_define_GNU_SOURCE.patch +# Patch200 fixes device communication and detection via MDNS in some network setups: +Patch200: hplip-mdns.patch +# Patch201 makes MDNS lookups more robust by retrying queries: +Patch201: hplip-mdns-retry-query.patch # HPLIP's Python module cupsext.so has a build-time dependancy on the CUPS version: # It needs symbols (like ippFirstAttribute, ippNextAttribute, ippSetOperation etc) # that are defined only in libcups.so version > 1.5. For backward compatibility @@ -350,6 +354,8 @@ This sub-package is only required by developers. # Patch108 add_missing_includes_and_define_GNU_SOURCE.patch adds missing '#include <...>' # and missing '#define _GNU_SOURCE' see https://bugs.launchpad.net/hplip/+bug/1456590 %patch108 -p1 -b .add_missing_includes_and_define_GNU_SOURCE.orig +%patch200 -p1 -b .mdns +%patch201 -p1 -b .mdns-retry %build # If AUTOMAKE='automake --foreign' is not set, autoreconf (in fact automake) @@ -407,7 +413,8 @@ export CXXFLAGS="%{optflags} -fno-strict-aliasing" --with-drvdir=%{_libexecdir}/cups/driver \ --with-mimedir=%{_sysconfdir}/cups \ --with-docdir=%{_defaultdocdir}/%{name} \ - --with-htmldir==%{_defaultdocdir}/%{name} + --with-htmldir==%{_defaultdocdir}/%{name} \ + CFLAGS='%{optflags}' make %install