87 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "NetworkServerLookup.hpp"
 | |
| 
 | |
| #include <stdexcept>
 | |
| 
 | |
| #include <QHostInfo>
 | |
| #include <QString>
 | |
| 
 | |
| std::tuple<QHostAddress, quint16>
 | |
| network_server_lookup (QString query
 | |
| 		       , quint16 default_service_port
 | |
| 		       , QHostAddress default_host_address
 | |
| 		       , QAbstractSocket::NetworkLayerProtocol required_protocol)
 | |
| {
 | |
|   query = query.trimmed ();
 | |
| 
 | |
|   QHostAddress host_address {default_host_address};
 | |
|   quint16 service_port {default_service_port};
 | |
| 
 | |
|   QString host_name;
 | |
|   if (!query.isEmpty ())
 | |
|     {
 | |
|       int port_colon_index {-1};
 | |
| 
 | |
|       if ('[' == query[0])
 | |
|         {
 | |
|           // assume IPv6 combined address/port syntax [<address>]:<port>
 | |
|           auto close_bracket_index = query.lastIndexOf (']');
 | |
|           host_name = query.mid (1, close_bracket_index - 1);
 | |
|           port_colon_index = query.indexOf (':', close_bracket_index);
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           port_colon_index = query.lastIndexOf (':');
 | |
|           host_name = query.left (port_colon_index);
 | |
|         }
 | |
|       host_name = host_name.trimmed ();
 | |
| 
 | |
|       if (port_colon_index >= 0)
 | |
|         {
 | |
|           bool ok;
 | |
|           service_port = query.mid (port_colon_index + 1).trimmed ().toUShort (&ok);
 | |
|           if (!ok)
 | |
|             {
 | |
|               throw std::runtime_error {"network server lookup error: invalid port"};
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   if (!host_name.isEmpty ())
 | |
|     {
 | |
|       auto host_info = QHostInfo::fromName (host_name);
 | |
|       if (host_info.addresses ().isEmpty ())
 | |
|         {
 | |
|           throw std::runtime_error {"network server lookup error: host name lookup failed"};
 | |
|         }
 | |
| 
 | |
|       bool found {false};
 | |
|       for (int i {0}; i < host_info.addresses ().size () && !found; ++i)
 | |
|         {
 | |
|           host_address = host_info.addresses ().at (i);
 | |
|           switch (required_protocol)
 | |
|             {
 | |
|             case QAbstractSocket::IPv4Protocol:
 | |
|             case QAbstractSocket::IPv6Protocol:
 | |
|               if (required_protocol != host_address.protocol ())
 | |
|                 {
 | |
|                   break;
 | |
|                 }
 | |
|               // drop through
 | |
| 
 | |
|             case QAbstractSocket::AnyIPProtocol:
 | |
|               found = true;
 | |
|               break;
 | |
| 
 | |
|             default:
 | |
|               throw std::runtime_error {"network server lookup error: invalid required protocol"};
 | |
|             }
 | |
|         }
 | |
|       if (!found)
 | |
|         {
 | |
|           throw std::runtime_error {"network server lookup error: no suitable host address found"};
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   return std::make_tuple (host_address, service_port);
 | |
| }
 | 
