// server must reply with CLOSE_NOTIFY
if (!session.isClient()) {
DTLSMessage closeNotify = new AlertMessage(AlertLevel.WARNING, AlertDescription.CLOSE_NOTIFY);
flight = new DTLSFlight();
flight.addMessage(new Record(ContentType.ALERT, session.getWriteEpoch(), session.getSequenceNumber(), closeNotify, session));
flight.setRetransmissionNeeded(false);
}
if (dtlsSessions.remove(addressToKey(peerAddress))!=null) {
LOGGER.info("Closed session with peer: " + peerAddress.toString());
} else {
LOGGER.warning("Session to close not found: " + peerAddress.toString());
}
break;
// remote implementation might use any alert (e.g., against padding oracle attack)
default:
LOGGER.warning(alert.getDescription() + " with " + peerAddress.toString());
// cleaning up
cancelPreviousFlight(peerAddress);
dtlsSessions.remove(addressToKey(peerAddress));
handshakers.remove(addressToKey(peerAddress));
break;
//TODO somehow tell CoAP endpoint to cancel
}
break;
case CHANGE_CIPHER_SPEC:
case HANDSHAKE:
LOGGER.finest(" => handshaker: "+handshaker);
if (handshaker == null) {
/*
* A handshake message received, but no handshaker
* available: this must mean that we either received
* a HelloRequest (from server) or a ClientHello
* (from client) => initialize appropriate
* handshaker type
*/
HandshakeMessage handshake = (HandshakeMessage) record.getFragment();
switch (handshake.getMessageType()) {
case HELLO_REQUEST:
/*
* Client side: server desires a re-handshake
*/
if (session == null) {
// create new session
session = new DTLSSession(peerAddress, true);
// store session according to peer address
dtlsSessions.put(addressToKey(peerAddress), session);
LOGGER.info("Created new session as client with peer: " + peerAddress.toString());
}
handshaker = new ClientHandshaker(peerAddress, null, session);
handshakers.put(addressToKey(peerAddress), handshaker);
LOGGER.finest("Stored re-handshaker: " + handshaker.toString() + " for " + peerAddress.toString());
break;
case CLIENT_HELLO:
/*
* Server side: server received a client hello:
* check first if client wants to resume a
* session (message must contain session
* identifier) and then check if particular
* session still available, otherwise conduct
* full handshake with fresh session.
*/
if (!(handshake instanceof FragmentedHandshakeMessage)) {
// check if session identifier set
ClientHello clientHello = (ClientHello) handshake;
session = getSessionByIdentifier(clientHello.getSessionId().getSessionId());
}
if (session == null) {
// create new session
session = new DTLSSession(peerAddress, false);
// store session according to peer address
dtlsSessions.put(addressToKey(peerAddress), session);
LOGGER.info("Created new session as server with peer: " + peerAddress.toString());
handshaker = new ServerHandshaker(peerAddress, session);
} else {
handshaker = new ResumingServerHandshaker(peerAddress, session);
}
handshakers.put(addressToKey(peerAddress), handshaker);
LOGGER.finest("Stored handshaker: " + handshaker.toString() + " for " + peerAddress.toString());
break;
default:
LOGGER.severe("Received unexpected first handshake message (type="+handshake.getMessageType()+") from " + peerAddress.toString() + ":\n" + handshake.toString());
break;
}
}
flight = handshaker.processMessage(record);
break;
default:
LOGGER.severe("Received unknown DTLS record from " + peerAddress.toString() + ":\n" + ByteArrayUtils.toHexString(data));
break;
}
if (flight != null) {
cancelPreviousFlight(peerAddress);
flight.setPeerAddress(peerAddress);
flight.setSession(session);
if (flight.isRetransmissionNeeded()) {
flights.put(addressToKey(peerAddress), flight);
scheduleRetransmission(flight);
}
sendFlight(flight);
}
if (raw != null) {
raw.setAddress(packet.getAddress());
raw.setPort(packet.getPort());
return raw;
}
}
} catch (Exception e) {
/*
* If it is a known handshake failure, send the specific Alert,
* otherwise the general Handshake_Failure Alert.
*/
DTLSFlight flight = new DTLSFlight();
flight.setRetransmissionNeeded(false);
flight.setPeerAddress(peerAddress);
flight.setSession(session);
AlertMessage alert;
if (e instanceof HandshakeException) {
alert = ((HandshakeException) e).getAlert();
LOGGER.severe("Handshake Exception (" + peerAddress.toString() + "): " + e.getMessage());
} else {
alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.HANDSHAKE_FAILURE);
LOGGER.log(Level.SEVERE, "Unknown Exception (" + peerAddress + ").", e);
}
LOGGER.log(Level.SEVERE, "Datagram which lead to exception (" + peerAddress + "): " + ByteArrayUtils.toHexString(data), e);
if (session == null) {
// if the first received message failed, no session has been set
session = new DTLSSession(peerAddress, false);
}
cancelPreviousFlight(peerAddress);
flight.addMessage(new Record(ContentType.ALERT, session.getWriteEpoch(), session.getSequenceNumber(), alert, session));
sendFlight(flight);
} // receive()
return null;
}