2 *******************************************************************
4 * Copyright 2016 Samsung Electronics All Rights Reserved.
6 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
20 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 package org.iotivity.cloud.ciserver.protocols;
24 import java.net.InetSocketAddress;
25 import java.nio.charset.StandardCharsets;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
30 import org.iotivity.cloud.base.CoapClient;
31 import org.iotivity.cloud.base.SessionManager;
32 import org.iotivity.cloud.base.protocols.coap.CoapRequest;
33 import org.iotivity.cloud.base.protocols.coap.CoapResponse;
34 import org.iotivity.cloud.base.protocols.coap.enums.CoapMethod;
35 import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
36 import org.iotivity.cloud.ciserver.Constants;
37 import org.iotivity.cloud.util.Logger;
38 import org.iotivity.cloud.util.Net;
40 import io.netty.channel.ChannelDuplexHandler;
41 import io.netty.channel.ChannelHandler.Sharable;
42 import io.netty.channel.ChannelHandlerContext;
43 import io.netty.channel.SimpleChannelInboundHandler;
44 import io.netty.util.AttributeKey;
48 * This class is relay handler relating Cloud Interface
52 public class CoapRelayHandler extends ChannelDuplexHandler {
54 /////////// Handler for Resource Directory
55 private static final AttributeKey<ChannelHandlerContext> keyRDClient = AttributeKey
56 .newInstance("rdCtx");
58 private static class RDHandler
59 extends SimpleChannelInboundHandler<CoapResponse> {
61 public void channelRead0(ChannelHandlerContext ctx, CoapResponse msg)
63 Logger.d("Receive response from RD, forward to client");
65 ChannelHandlerContext ctxToDevice = ctx.channel().attr(keyRDClient)
67 ctxToDevice.writeAndFlush(msg);
71 public void exceptionCaught(ChannelHandlerContext ctx,
73 cause.printStackTrace();
78 private CoapClient rdClient = new CoapClient();
81 ////////// Handler for Account Server
82 private static final AttributeKey<List<CoapRequest>> keyAccountClient = AttributeKey
83 .newInstance("accountCtx");
85 private class AccountHandler
86 extends SimpleChannelInboundHandler<CoapResponse> {
88 public void channelRead0(ChannelHandlerContext ctx, CoapResponse msg)
90 Logger.d("Receive response from AS, make request to RD");
92 CoapRequest rdRequest = null;
94 switch (msg.getResponseCode()) {
96 // response of POST request
97 rdRequest = ctx.channel().attr(keyAccountClient).get()
99 rdClient.sendRequest(rdRequest);
103 // response of GET request, contains did list
104 rdRequest = ctx.channel().attr(keyAccountClient).get()
106 // change uri to send RD
107 rdRequest.setUriPath(Constants.RD_URI);
108 rdRequest.setUriQuery(Constants.DEVICE_LIST);
109 rdRequest.setPayload(msg.getPayload());
110 rdClient.sendRequest(rdRequest);
119 public void exceptionCaught(ChannelHandlerContext ctx,
121 cause.printStackTrace();
126 private CoapClient asClient = new CoapClient();
129 private SessionManager sessionManager = null;
131 public CoapRelayHandler(SessionManager sessionManager, String rdAddress,
132 int rdPort, String acAddress, int acPort) {
133 this.sessionManager = sessionManager;
135 rdClient.addHandler(new RDHandler());
137 asClient.addHandler(new AccountHandler());
140 rdClient.startClient(new InetSocketAddress(rdAddress, rdPort));
141 asClient.startClient(new InetSocketAddress(acAddress, acPort));
142 } catch (InterruptedException e) {
143 // TODO Auto-generated catch block
147 asClient.getChannelFuture().channel().attr(keyAccountClient)
148 .set(new ArrayList<CoapRequest>());
151 private static final AttributeKey<ChannelHandlerContext> keyDevice = AttributeKey
152 .newInstance("deviceCtx");
154 private HashMap<String, CoapClient> ciRelayClients = new HashMap<String, CoapClient>();
157 public void channelRead(ChannelHandlerContext ctx, Object msg)
160 if (msg instanceof CoapRequest) {
161 CoapRequest request = (CoapRequest) msg;
162 // Parse uri, send to RD
163 String uriPath = request.getUriPath();
164 CoapRequest accountRequest = null;
165 String userId, deviceId, authPayload;
166 CoapResponse response = null;
168 Logger.d("Request received, URI: " + uriPath);
170 case Constants.AUTH_URI:
171 // This case user wants to logout
172 if (request.getUriQuery().endsWith("logout")) {
173 ctx.channel().attr(Constants.Attribute_UserId).remove();
174 response = new CoapResponse(CoapStatus.DELETED);
176 response = new CoapResponse(CoapStatus.BAD_REQUEST);
178 ctx.writeAndFlush(response);
181 case Constants.RD_URI:
182 // RD POST means publish device to server
183 switch (request.getRequestMethod()) {
185 userId = ctx.channel()
186 .attr(Constants.Attribute_UserId).get();
187 deviceId = request.decodeDeviceId();
188 authPayload = String.format(
189 "{\"userid\":\"%s\",\"deviceid\":\"%s\"}",
191 accountRequest = new CoapRequest(CoapMethod.POST);
192 accountRequest.setUriPath(Constants.ACCOUNT_URI);
193 accountRequest.setUriQuery("reqtype=publish");
194 accountRequest.setToken(request.getToken());
195 accountRequest.setPayload(authPayload.getBytes(StandardCharsets.UTF_8));
197 // TODO: deviceId must be registered after session
199 Logger.d("Adding deviceId to session: " + deviceId);
200 sessionManager.addSession(deviceId, ctx);
204 Logger.e("Unsupported request type");
208 rdClient.getChannelFuture().channel().attr(keyRDClient)
211 // Add original request to list for future use
212 asClient.getChannelFuture().channel().attr(keyAccountClient)
214 asClient.sendRequest(accountRequest);
217 case Constants.WELL_KNOWN_URI:
218 switch (request.getRequestMethod()) {
220 userId = ctx.channel()
221 .attr(Constants.Attribute_UserId).get();
222 authPayload = String.format("{\"userid\":\"%s\"}",
224 accountRequest = new CoapRequest(CoapMethod.GET);
225 accountRequest.setUriPath(Constants.ACCOUNT_URI);
226 accountRequest.setUriQuery("reqtype=find");
227 accountRequest.setToken(request.getToken());
228 accountRequest.setPayload(authPayload.getBytes());
232 Logger.e("Unsupported request type");
236 rdClient.getChannelFuture().channel().attr(keyRDClient)
239 // Add original request to list for future use
240 asClient.getChannelFuture().channel().attr(keyAccountClient)
242 asClient.sendRequest(accountRequest);
245 case Constants.KEEP_ALIVE_URI:
249 List<String> uriPathList = request.getUriPathSegments();
250 String originUriPathList = request.getUriPath();
251 Logger.i("uriPahtList: " + uriPathList.toString());
252 String ciAddress = uriPathList.get(0);
253 String did = uriPathList.get(1);
255 Logger.i("CI address: " + ciAddress);
256 Logger.i("did: " + did);
259 String hostAddress = Net.getMyIpAddress().replace("/", "");
260 Logger.i("hostAddress : " + hostAddress);
261 // if published CI is mine
262 if (hostAddress.equals(ciAddress) == true) {
263 // find ctx about did, and send msg
264 Logger.d("published CI is mine");
265 String resource = new String();
266 List<String> pathSegments = uriPathList.subList(2,
268 for (String path : pathSegments) {
272 Logger.i("resource: " + resource);
273 request.setUriPath(resource);
275 ChannelHandlerContext deviceCtx = sessionManager
277 if (deviceCtx != null) {
278 deviceCtx.attr(keyDevice).set(ctx);
279 deviceCtx.writeAndFlush(request);
281 Logger.e("deviceCtx is null");
282 response = new CoapResponse(CoapStatus.FORBIDDEN);
283 response.setToken(request.getToken());
284 ctx.writeAndFlush(response);
287 // if CI is not connected, connect and send msg
288 CoapClient otherCI = null;
289 synchronized (ciRelayClients) {
290 otherCI = ciRelayClients.get(ciAddress);
291 if (otherCI == null) {
292 otherCI = new CoapClient();
294 new InetSocketAddress(ciAddress, 5683));
295 ciRelayClients.put(ciAddress, otherCI);
298 request.setUriPath(originUriPathList);
299 otherCI.sendRequest(request);
304 } else if (msg instanceof CoapResponse) {
305 if (ctx.attr(keyDevice).get() != null) {
306 Logger.i("ctx.channel : "
307 + ctx.attr(keyDevice).get().channel().toString());
308 ctx.attr(keyDevice).get().writeAndFlush(msg);
313 super.channelRead(ctx, msg);
317 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
319 cause.printStackTrace();