Skip to content

Commit

Permalink
IP addon finder mac address format tweak (#4481)
Browse files Browse the repository at this point in the history
* mac address format tweaks

Signed-off-by: Andrew Fiddian-Green <[email protected]>
  • Loading branch information
andrewfg authored Jan 27, 2025
1 parent 6764b6d commit fb5ecab
Showing 1 changed file with 49 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
*/
package org.openhab.core.config.discovery.addon.ip;

import static org.openhab.core.config.discovery.addon.AddonFinderConstants.SERVICE_NAME_IP;
import static org.openhab.core.config.discovery.addon.AddonFinderConstants.SERVICE_TYPE_IP;
import static org.openhab.core.config.discovery.addon.AddonFinderConstants.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -79,7 +78,7 @@
/**
* This is a {@link IpAddonFinder} for finding suggested add-ons by sending IP packets to the
* network and collecting responses.
*
*
* This finder is intended to detect devices on the network which do not announce via UPnP
* or mDNS. Some devices respond to queries to defined multicast addresses and ports and thus
* can be detected by sending a single frame on the IP network.
Expand Down Expand Up @@ -363,10 +362,9 @@ private void scan() {
}
}
String macFormat = parameters.getOrDefault(PARAMETER_MAC_FORMAT, "%02X:");
try {
String.format(macFormat, 123);
} catch (IllegalFormatException e) {
if (!macFormatValid(macFormat)) {
logger.warn("{}: discovery-parameter '{}' invalid format specifier", candidate.getUID(), macFormat);
continue;
}

// handle known types
Expand Down Expand Up @@ -599,7 +597,7 @@ private boolean isAddonInstalled(String addonId) {

/**
* Get mac address bytes associated with the given Internet socket address
*
*
* @param inetSocketAddress the Internet address
* @return the mac address as an array of bytes
* @throws SocketException if address is not on this PC, or no mac address is associated
Expand All @@ -614,18 +612,57 @@ private byte[] macBytesFrom(InetSocketAddress inetSocketAddress) throws SocketEx

/**
* Use the given format specifier to format an array of mac address bytes
*
* @param format a standard format specifier; optionally ends with a delimiter e.g. "%02x:" or "%02X"
*
* @param format a standard format specifier; optionally ends with a delimiter e.g. {@code %02x:} or {@code %02X}
* @param bytes the mac address as an array of bytes
*
* @return e.g. '01:02:03:04:A5:B6:C7:D8', '01-02-03-04:a5:b6:c7:d8', or '01020304A5B6C7D8'
* @return e.g. '{@code 01:02:03:04:A5:B6:C7:D8}' or '{@code 01-02-03-04-a5-b6-c7-d8}' or '{@code 01020304A5B6C7D8}'
*/
private String macFormat(String format, byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte byt : bytes) {
result.append(String.format(format, byt));
}
boolean isDelimited = Set.of(':', '-', '.').contains(format.charAt(format.length() - 1));
boolean isDelimited = !Character.isLetterOrDigit(format.charAt(format.length() - 1));
return (isDelimited ? result.substring(0, result.length() - 1) : result).toString();
}

/**
* Check if the given mac format specifier is valid. A valid specifier comprises two parts -- namely
* 1) a numeric format specifier acceptable to the {@code String.format()} method, plus 2) a single
* [optional] delimiter (i.e. a non alphanumeric) character. Examples are as follows:
* <p>
* <li>{@code %02X} produces {@code 01020304A5B6C7D8}</li>
* <li>{@code %02x:} produces {@code 01:02:03:04:a5:b6:c7:d8} (lower case hex)</li>
* <li>{@code %02X-} produces {@code 01-02-03-04-A5-B6-C7-D8} (upper case hex)</li>
* <li>{@code %02X,} produces {@code 01,02,03,04,A5,B6,C7,D8}</li>
* <p>
*
* @return true if the format specifier is valid
*/
private boolean macFormatValid(String format) {
// use String.format() to check first part validity
try {
String.format(format, (byte) 123);
} catch (IllegalFormatException e) {
return false;
}
// get position of numeric format letter e.g. the 'X' in '%02X-'
int last = format.length() - 1;
int index = 0;
while (index <= last) {
if (Character.isLetter(format.charAt(index))) {
break;
}
index++;
}
// check for zero or one character(s) after numeric format letter
switch (last - index) {
case 0:
return true;
case 1:
// check this character is non alphanumeric i.e. a delimiter
return !Character.isLetterOrDigit(format.charAt(last));
}
return false;
}
}

0 comments on commit fb5ecab

Please sign in to comment.