Commit abd78803 authored by Patrick Lankswert's avatar Patrick Lankswert Committed by Gerrit Code Review

Merge "This a complete version of OICMiddle. The ReST capability has limited...

Merge "This a complete version of OICMiddle. The ReST capability has limited functionality, which we hope to expand shortly after release.  We believe the other parts of OICMiddle are sufficiently robust that the application will be useful as both demo and example in the OIC 0.9.0 release."
parents a093524e 87f7589e
Pipeline #66 failed with stages
//******************************************************************
//
// Copyright 2014 Intel Corporation.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <map>
#include "WrapResource.h"
#include "Client.h"
MiddleClient::MiddleClient()
{
m_findCB = bind(&MiddleClient::foundOCResource, this, placeholders::_1);
}
bool MiddleClient::init()
{
findResources();
return true;
}
void MiddleClient::findResources()
{
m_resourceMap.clear();
OC::OCPlatform::findResource("", OC_WELL_KNOWN_QUERY, m_findCB);
}
void MiddleClient::foundOCResource(shared_ptr<OCResource> resource)
{
WrapResource *wres;
string resourceID = formatResourceID(resource);
m_mutexFoundCB.lock();
try {
wres = m_resourceMap.at(resourceID);
} catch (const std::out_of_range) {
wres = new WrapResource(resourceID, resource);
m_resourceMap[resourceID] = wres;
}
m_mutexFoundCB.unlock();
wres->findTypes();
}
/*
* I need a unique ID, so I concatenate the host string and resource uri
* It's arbitrary and sufficient.
*/
string MiddleClient::formatResourceID(std::shared_ptr<OCResource> resource)
{
string host = resource->host();
if (host.compare(0, 7, "coap://") == 0)
host = host.erase(0, 7);
return host + resource->uri();
}
void MiddleClient::addResource(WrapResource *wres)
{
string resourceID = wres->getResourceID();
try {
m_resourceMap[resourceID];
} catch (const std::out_of_range) {
m_resourceMap[resourceID] = wres;
}
}
#ifndef CLIENT_H
#define CLIENT_H
//******************************************************************
//
// Copyright 2014 Intel Corporation.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <mutex>
#include "OICMiddle.h"
typedef map<string, WrapResource *> resourcemap_t;
typedef pair<string, WrapResource *> resourcemappair_t;
class MiddleClient
{
public:
MiddleClient();
bool init();
void findResources();
friend class LineInput;
friend class HueResource;
friend class HueResources;
friend class RestInput;
protected:
mutex m_mutexFoundCB;
map<string, WrapResource *> m_resourceMap;
HueResources *m_hueResources;
std::function<void(std::shared_ptr<OCResource> resource)> m_findCB;
void foundOCResource(shared_ptr<OCResource> resource);
string formatResourceID(std::shared_ptr<OCResource> resource);
void findHueResources();
void addResource(WrapResource *wres);
};
#endif // CLIENT_H
This diff is collapsed.
#ifndef LINEINPUT_H
#define LINEINPUT_H
//******************************************************************
//
// Copyright 2014 Intel Corporation.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "OICMiddle.h"
#include "Client.h"
#include "Server.h"
typedef vector<string> elements_t;
enum ParseState {
PS_None,
PS_Between,
PS_Infirst,
PS_Startsecond,
PS_Insecond,
PS_Endsecond,
};
class LineInput
{
public:
LineInput(MiddleClient *client);
void setServer(MiddleServer *server);
int run();
LineResult processLine(string command, stringstream& result, observecb_t cb);
protected:
MiddleClient *m_client;
MiddleServer *m_server;
vector<string> m_resourceList;
observecb_t m_obsCB;
WrapResource *m_observer;
char m_elem[1000];
LineResult processHelp(elements_t& elems, stringstream& ss);
LineResult processUnrecognized(elements_t& elems, stringstream& ss);
LineResult processFind(elements_t& elems, stringstream& ss);
LineResult processShow(elements_t& elems, stringstream& ss);
LineResult processDetails(elements_t& elems, stringstream& ss);
LineResult processGet(elements_t& elems, stringstream& ss);
LineResult processPut(elements_t& elems, stringstream& ss);
LineResult processObserve(elements_t& elems, stringstream& ss, observecb_t cb);
LineResult processCancel(elements_t& elems, stringstream& ss);
WrapResource *resolveResource(string resID, stringstream& ss);
LineResult parseLine(string lineIn, elements_t& elems);
ParseState finishElem(char*& e, elements_t& elems);
ParseState putCharInElem(char c, char *& e, ParseState newState);
void obsCB(const token_t token, const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode, const int sequenceNumber);
void registerResourceWithServer(std::string &url);
};
#endif // LINEINPUT_H
//******************************************************************
//
// Copyright 2014 Intel Corporation.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// OICMiddle.cpp : OIC demo application for Minnowboard
//
#include <unistd.h>
#include "OICMiddle.h"
#include "WrapResource.h"
#include "Client.h"
#include "Server.h"
#include "LineInput.h"
#include "RestInput.h"
class Middle middle; // one and only
Middle::Middle() :
m_appType(AT_None),
m_useLineInput(false),
m_useRestInput(false),
m_client(nullptr),
m_server(nullptr),
m_lineInput(nullptr),
m_restInput(nullptr)
{
}
void Middle::init()
{
}
void Middle::run(int argc, char* argv[])
{
parseCommandLineOptions(argc, argv);
startPlatform();
if (m_appType & AT_Client) {
m_client = new MiddleClient();
m_client->init();
}
m_lineInput = new LineInput(m_client);
if (m_appType & AT_Server) {
m_server = new MiddleServer();
m_server->init();
}
if (m_useRestInput) {
if (!m_server) {
m_server = new MiddleServer();
m_server->init();
}
m_restInput = new RestInput(m_lineInput);
m_restInput->init();
}
if (m_useLineInput) {
if (m_server) {
m_lineInput->setServer(m_server);
}
m_lineInput->run();
} else {
while (true)
sleep(1);
}
}
void Middle::startPlatform()
{
uint16_t port = 0;
//std::string ipaddr = INADDR_ANY;
std::string ipaddr = "0.0.0.0";
PlatformConfig cfg { ServiceType::InProc, ModeType::Both,
ipaddr, port, QualityOfService::LowQos};
OC::OCPlatform::Configure(cfg);
}
void Middle::provideHelp()
{
static const char usage[] = "\nUsage: IOCMiddle args\n"
" where args may include any of these:\n"
"\t-client Run OIC client\n"
"\t-server Run OIC server\n"
"\t-both Run OIC client and server\n"
"\t-console Run console line interpreter\n"
"\t-rest Run ReST server\n"
"\t-hue addr Enable Hue resources on bridge at addr\n"
"\t-help Show Usage again\n"
"Any combination of the above is okay.\n\n";
cout << usage;
}
bool Middle::parseCommandLineOptions(int argc, char *argv[])
{
bool any = false;
for (int i = 1; i < argc; i++) {
if (argv[i] == string("-server")) {
middle.m_appType = AT_Server; any = true;
} else if (argv[i] == string("-client")) {
middle.m_appType = AT_Client; any = true;
} else if (argv[i] == string("-both")) {
middle.m_appType = AT_Both; any = true;
} else if (argv[i] == string("-console")) {
middle.m_useLineInput = true; any = true;
} else if (argv[i] == string("-rest")) {
middle.m_useRestInput = true; any = true;
} else if (argv[i] == string("-hue")) {
if (i + 1 < argc && argv[i + 1][0] != '-') {
m_hueAddr = argv[++i];
any = true;
}
} else if (argv[i] == string("-help")) {
any = false;
break;
} else {
std::cerr << "Not enough or invalid arguments, please try again.\n";
exit(1);
}
}
if (!any)
provideHelp();
return true;
}
int main(int argc, char* argv[])
{
middle.run(argc, argv);
return 0;
}
#ifndef OICMIDDLE_H
#define OICMIDDLE_H
//******************************************************************
//
// Copyright 2014 Intel Corporation.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <string>
#include <cstdlib>
#include "OCPlatform.h"
#include "OCApi.h"
class MiddleClient;
class MiddleServer;
class LineInput;
class RestInput;
class WrapResource;
class HueResources;
using namespace OC;
using namespace std;
enum AppType {
AT_None = 0,
AT_Server = 1,
AT_Client = 2,
AT_Both = 3
};
enum LineResult {
LR_OK,
LR_NoCommand,
LR_NoClient,
LR_NoResource,
LR_Timeout,
LR_Param,
LR_Unrecognized,
LR_Quit,
LR_Syntax,
LR_Error
};
class HueResource;
typedef int token_t;
typedef map<string, string> stringmap_t;
class Middle
{
public:
Middle();
void init();
void run(int argc, char* argv[]);
protected:
friend class MiddleClient;
friend class MiddleServer;
friend class RestInput;
friend class HueResources;
AppType m_appType;
bool m_useLineInput;
bool m_useRestInput;
string m_hueAddr;
MiddleClient *m_client;
MiddleServer *m_server;
LineInput *m_lineInput;
RestInput *m_restInput;
protected:
void startPlatform();
bool parseCommandLineOptions(int argc, char *argv[]);
void provideHelp();
};
extern Middle middle;
#endif // OICMIDDLE_H
OICMiddle was written to
* be part of a demonstration of OIC Yocto capability,
* act as an example of resource callbacks using class methods,
* provide a simple promiscuous resource editor for examining OIC systems, and
* act as a starting code base for further exploration of OIC capabilities.
As a demonstration, it runs on an Minnowboard running a Yocto-built OS, acting
as a gateway between an Android device (acting as an OIC client) and an
Edison board (acting as an OIC server) with sensors and actuators.
As an example of resource callbacks, it shows a method of using class methods
as callbacks, a critical capability not shown in any of the examples in
iotivity/resource/examples.
As a promiscuous resource editor, it can find, get, put and observe any
resource using a simple command-line interface using the system console.
As a code base, the command-line editor can be the basis for adding additional
editing capabilities, like the additions of various filters.
Running OICMiddle with no arguments on a console shows the various capabilities
it offers. The most important are:
-client. Act as an OIC client.
-console. Accept command lines from console input to drive the OIC client.
-server. Advertise resources found by the OIC client as OIC resources.
The -server capabilites might be the basis for a gateway.
Typing 'help' (or invalid commands) to the console gives a console usage
message. The important ones are:
find Find all resources. Also performed automatically at startup.
show Show the found resources and an assigned index.
get Get the value(s) of the resource with the given index.
put Put one or more resource values for the given index.
12/24/2014
//******************************************************************
//
// Copyright 2014 Intel Corporation.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "WrapResource.h"
#include "RestInput.h"
#include "LineInput.h"
#include "OICMiddle.h"
using namespace std;
#define BUFLEN 10000
#define MAX_CONNS 5
static bool enableDebug = false; // set to true to print debug messages
void printDebugMessage(std::string message)
{
if (enableDebug) {
cout << "RestInput: " << message << endl;
}
}
RestInput::RestInput(LineInput *lineInput) : m_lineInput(lineInput)
{
m_data = (char*)malloc(BUFLEN);
m_thread = new std::thread[MAX_CONNS];
m_threadCount = 0;
}
bool RestInput::init()
{
m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (m_sockfd < 0) {
cerr << "Failed to open socket. Exiting" << endl;
return false;
}
m_port = 1441; //listening on port 1441
m_serverAddr.sin_family = AF_INET;
m_serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
m_serverAddr.sin_port = htons(m_port);
if (::bind(m_sockfd, (struct sockaddr*)&m_serverAddr, sizeof m_serverAddr) < 0) {
cerr << "Failed to bind. Exiting " << endl;
return false;
}
listen(m_sockfd, MAX_CONNS);
startAccept(m_sockfd);
return true;
}
// accept incoming connection(s)
void RestInput::startAccept(int &sockfd)
{
if (m_threadCount >= MAX_CONNS) {
cerr << " Max # of connections reached. Skipping " << endl;
return;
} else {
while (true) {
int connfd = accept(sockfd, (struct sockaddr *)NULL, NULL);
if (connfd < 0) {
cerr << " Failed to accept incoming connection " << endl;
return;
}
int n = read(connfd, m_data, BUFLEN);
if (n < 0) {
cerr << "Failed to read from socket" << endl;
return;
}
startThread();
}
}
}
// start client thread
void RestInput::startThread()
{
std::thread t(&RestInput::processClient, this);
m_thread[m_threadCount] = std::move(t);
m_thread[m_threadCount++].join();
}
// process read commands for the client
void RestInput::processClient(void)
{
std::string restCmd = m_data;
std::size_t found = restCmd.find('\n');
if (found != std::string::npos) {
restCmd = restCmd.substr(0, found-1);
}
handleRead(restCmd);
}
void RestInput::handleRead(std::string& restCmd)
{
parseString(restCmd);
if (restCmd.find("exit") == 0) {
std::thread::id id = std::this_thread::get_id();
for(int i = 0; i < m_threadCount; ++i) {
if (id == m_thread[i].get_id()) {
m_thread[i].detach();
--m_threadCount;
cout << "Exiting thread " << id << endl;
}
}
return;
}
stringstream ss;
observecb_t cb;
std::string msg = "command sent to LineInput is: " + restCmd;
printDebugMessage(msg);
m_lineInput->processLine(restCmd, ss, cb);
if (restCmd.find("show") != string::npos) {
// if command is show, we want to list out the details of each resource
handleShow(ss, cb);
}
}
void RestInput::handleShow(stringstream &ss, observecb_t &cb) {
std::string temp = ss.str();