Imported Upstream version 0.9.1
[platform/upstream/iotivity.git] / examples / OICMiddle / RestInput.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "WrapResource.h"
22 #include "RestInput.h"
23 #include "LineInput.h"
24 #include "OICMiddle.h"
25
26 using namespace std;
27
28 #define BUFLEN 10000
29 #define MAX_CONNS 5
30
31 static bool enableDebug = false; // set to true to print debug messages
32
33 void printDebugMessage(std::string message)
34 {
35     if (enableDebug) {
36         cout << "RestInput: " << message  << endl;
37     }
38 }
39
40 RestInput::RestInput(LineInput *lineInput) : m_lineInput(lineInput)
41 {
42     m_data = (char*)malloc(BUFLEN);
43     m_thread = new std::thread[MAX_CONNS];
44     m_threadCount = 0;
45 }
46
47 bool RestInput::init()
48 {
49     m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
50     if (m_sockfd < 0) {
51         cerr << "Failed to open socket. Exiting" << endl;
52         return false;
53     }
54     m_port = 1441; //listening on port 1441
55
56     m_serverAddr.sin_family = AF_INET;
57     m_serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
58     m_serverAddr.sin_port = htons(m_port);
59
60     if (::bind(m_sockfd, (struct sockaddr*)&m_serverAddr, sizeof m_serverAddr) < 0) {
61         cerr << "Failed to bind. Exiting " << endl;
62         return false;
63     }
64
65     listen(m_sockfd, MAX_CONNS);
66     startAccept(m_sockfd);
67     return true;
68 }
69
70 // accept incoming connection(s)
71 void RestInput::startAccept(int &sockfd)
72 {
73     if (m_threadCount >= MAX_CONNS) {
74         cerr << " Max # of connections reached. Skipping " << endl;
75         return;
76     } else {
77         while (true) {
78             int connfd = accept(sockfd, (struct sockaddr *)NULL, NULL);
79             if (connfd < 0) {
80                 cerr << " Failed to accept incoming connection " << endl;
81                 return;
82             }
83             int n = read(connfd, m_data, BUFLEN);
84             if (n < 0) {
85                 cerr << "Failed to read from socket" << endl;
86                 return;
87             }
88             startThread();
89         }
90     }
91 }
92
93 // start client thread
94 void RestInput::startThread()
95 {
96     std::thread t(&RestInput::processClient, this);
97     m_thread[m_threadCount] = std::move(t);
98     m_thread[m_threadCount++].join();
99 }
100
101 // process read commands for the client
102 void RestInput::processClient(void)
103 {
104     std::string restCmd = m_data;
105     std::size_t found = restCmd.find('\n');
106     if (found != std::string::npos) {
107         restCmd = restCmd.substr(0, found-1);
108     }
109     handleRead(restCmd);
110 }
111
112 void RestInput::handleRead(std::string& restCmd)
113 {
114     parseString(restCmd);
115     if (restCmd.find("exit") == 0) {
116         std::thread::id id = std::this_thread::get_id();
117         for(int i = 0; i < m_threadCount; ++i) {
118             if (id == m_thread[i].get_id()) {
119                 m_thread[i].detach();
120                 --m_threadCount;
121                 cout << "Exiting thread " << id << endl;
122             }
123         }
124         return;
125     }
126     stringstream ss;
127     observecb_t cb;
128     std::string msg = "command sent to LineInput is: " + restCmd;
129     printDebugMessage(msg);
130     m_lineInput->processLine(restCmd, ss, cb);
131     if (restCmd.find("show") != string::npos) {
132         // if command is show, we want to list out the details of each resource
133         handleShow(ss, cb);
134     }
135 }
136
137 void RestInput::handleShow(stringstream &ss, observecb_t &cb) {
138     std::string temp = ss.str();
139     size_t n = std::count(temp.begin(), temp.end(), '\n'); // number of resources found
140     std::stringstream sstm;
141     std::string lineInputData;
142
143     for (size_t i = 0; i < n; ++i) {
144         sstm.str("");
145         sstm << "details " << i;
146         lineInputData = sstm.str();
147         std::string msg = "Details: " + lineInputData;
148         printDebugMessage(msg);
149         m_lineInput->processLine(lineInputData, ss, cb);
150         sstm.str("");
151         sstm << "get " << i;
152         lineInputData = sstm.str();
153         msg = "Get: " + lineInputData;
154         printDebugMessage(msg);
155         m_lineInput->processLine(lineInputData, ss, cb);
156     }
157 }
158
159 void RestInput::parseString(std::string &toParse)
160 {
161     std::size_t pos = toParse.find("HTTP"); // split on HTTP
162     toParse = toParse.substr(0, pos);
163     pos = toParse.find("/"); // find 1st occurance of /
164     toParse = toParse.substr(pos + 1, toParse.size() - 1);
165     std::replace(toParse.begin(), toParse.end(), '/', ' '); // replace all '/' with ' '
166 }