001/**
002 *
003 * Copyright 2020-2021 Aditya Borikar, Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smack.websocket.rce;
018
019import java.net.InetAddress;
020import java.net.URI;
021import java.net.URISyntaxException;
022import java.net.UnknownHostException;
023import java.util.Arrays;
024import java.util.Collection;
025import java.util.List;
026import java.util.logging.Level;
027import java.util.logging.Logger;
028
029import org.jivesoftware.smack.datatypes.UInt16;
030import org.jivesoftware.smack.util.rce.RemoteConnectionEndpoint;
031
032public abstract class WebSocketRemoteConnectionEndpoint implements RemoteConnectionEndpoint {
033
034    public static final String INSECURE_WEB_SOCKET_SCHEME = "ws";
035    public static final String SECURE_WEB_SOCKET_SCHEME = INSECURE_WEB_SOCKET_SCHEME + "s";
036
037    private static final Logger LOGGER = Logger.getAnonymousLogger();
038
039    private final URI uri;
040    private final UInt16 port;
041
042    protected WebSocketRemoteConnectionEndpoint(URI uri) {
043        this.uri = uri;
044        int portInt = uri.getPort();
045        if (portInt >= 0) {
046            port = UInt16.from(portInt);
047        } else {
048            port = null;
049        }
050    }
051
052    public final URI getUri() {
053        return uri;
054    }
055
056    @Override
057    public final String getHost() {
058        return uri.getHost();
059    }
060
061    @Override
062    public UInt16 getPort() {
063        return port;
064    }
065
066    public abstract boolean isSecureEndpoint();
067
068    private List<? extends InetAddress> inetAddresses;
069
070    private void resolveInetAddressesIfRequired() {
071        if (inetAddresses != null) {
072            return;
073        }
074
075        String host = getHost();
076        InetAddress[] addresses;
077        try {
078            addresses = InetAddress.getAllByName(host);
079        } catch (UnknownHostException e) {
080            LOGGER.log(Level.WARNING, "Could not resolve IP addresses of " + host, e);
081            return;
082        }
083        inetAddresses = Arrays.asList(addresses);
084    }
085
086    @Override
087    public Collection<? extends InetAddress> getInetAddresses() {
088        resolveInetAddressesIfRequired();
089        return inetAddresses;
090    }
091
092    @Override
093    public String getDescription() {
094        return null;
095    }
096
097    @Override
098    public String toString() {
099        return uri.toString();
100    }
101
102    public static WebSocketRemoteConnectionEndpoint from(CharSequence uriCharSequence) throws URISyntaxException {
103        String uriString = uriCharSequence.toString();
104        URI uri = URI.create(uriString);
105        return from(uri);
106    }
107
108    public static WebSocketRemoteConnectionEndpoint from(URI uri) {
109        String scheme = uri.getScheme();
110        switch (scheme) {
111        case INSECURE_WEB_SOCKET_SCHEME:
112            return new InsecureWebSocketRemoteConnectionEndpoint(uri);
113        case SECURE_WEB_SOCKET_SCHEME:
114            return new SecureWebSocketRemoteConnectionEndpoint(uri);
115        default:
116            throw new IllegalArgumentException("Only allowed protocols are " + INSECURE_WEB_SOCKET_SCHEME + " and " + SECURE_WEB_SOCKET_SCHEME);
117        }
118    }
119}