1 /*
2 * Copyright (c) 2011-2014, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "TestPlatform.h"
32 #include "FullIo.hpp"
33
34 #include <iostream>
35 #include <cstdlib>
36 #include <semaphore.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <cerrno>
40 #include <cassert>
41
42 using namespace std;
43
44 const int iDefaultPortNumber = 5001;
45
46 // Starts test-platform in blocking mode
startBlockingTestPlatform(const char * filePath,int portNumber,string & strError)47 static bool startBlockingTestPlatform(const char *filePath, int portNumber, string &strError)
48 {
49
50 // Init semaphore
51 sem_t sem;
52
53 sem_init(&sem, false, 0);
54
55 // Create param mgr
56 CTestPlatform testPlatform(filePath, portNumber, sem);
57
58 // Start platformmgr
59 if (!testPlatform.load(strError)) {
60
61 sem_destroy(&sem);
62
63 return false;
64 }
65
66 // Block here
67 sem_wait(&sem);
68
69 sem_destroy(&sem);
70
71 return true;
72 }
73
notifyParent(int parentFd,bool success)74 static void notifyParent(int parentFd, bool success)
75 {
76 if (not utility::fullWrite(parentFd, &success, sizeof(success))) {
77 cerr << "Unable to warn parent process of load "
78 << (success ? "success" : "failure") << ": "
79 << strerror(errno) << endl;
80 assert(false);
81 }
82 }
83
84 // Starts test-platform in daemon mode
startDaemonTestPlatform(const char * filePath,int portNumber,string & strError)85 static bool startDaemonTestPlatform(const char *filePath, int portNumber, string &strError)
86 {
87 // Pipe used for communication between the child and the parent processes
88 int pipefd[2];
89
90 if (pipe(pipefd) == -1) {
91
92 strError = "pipe failed";
93 return false;
94 }
95
96 // Fork the current process:
97 // - Child process is used to start test-platform
98 // - Parent process is killed in order to turn its child into a daemon
99 pid_t pid = fork();
100
101 if (pid < 0) {
102
103 strError = "fork failed!";
104 return false;
105
106 } else if (pid == 0) {
107
108 // Child process : starts test-platform and notify the parent if it succeeds.
109
110 // Close read side of the pipe
111 close(pipefd[0]);
112
113 // Init semaphore
114 sem_t sem;
115
116 sem_init(&sem, false, 0);
117
118 // Create param mgr
119 CTestPlatform testPlatform(filePath, portNumber, sem);
120
121 // Message to send to parent process
122 bool loadSuccess = testPlatform.load(strError);
123
124 if (!loadSuccess) {
125
126 cerr << strError << endl;
127
128 // Notify parent of failure;
129 notifyParent(pipefd[1], false);
130
131 } else {
132
133 // Notify parent of success
134 notifyParent(pipefd[1], true);
135
136 // Block here
137 sem_wait(&sem);
138 }
139 sem_destroy(&sem);
140
141 return loadSuccess;
142
143 } else {
144
145 // Parent process : need to kill it once the child notifies the successs/failure to start
146 // test-platform (this status is used as exit value of the program).
147
148 // Close write side of the pipe
149 close(pipefd[1]);
150
151 // Message received from the child process
152 bool msgFromChild = false;
153
154 if (not utility::fullRead(pipefd[0], &msgFromChild, sizeof(msgFromChild))) {
155 strError = "Read pipe failed";
156 return false;
157 }
158
159 // return success/failure in exit status
160 return msgFromChild;
161 }
162 }
163
showUsage()164 static void showUsage()
165 {
166 cerr << "test-platform [-dh] <file path> [port number, default "
167 << iDefaultPortNumber << "]" << endl;
168 }
169
showInvalidUsage()170 static void showInvalidUsage()
171 {
172 cerr << "Invalid arguments: ";
173 showUsage();
174 }
175
showHelp()176 static void showHelp()
177 {
178 showUsage();
179 cerr << "<file path> must be a valid .xml file, oftenly ParameterFrameworkConfiguration.xml" << endl;
180 cerr << "Arguments:" << endl
181 << " -d starts as a deamon" << endl
182 << " -h display this help and exit" << endl;
183 }
184
main(int argc,char * argv[])185 int main(int argc, char *argv[])
186 {
187 // Option found by call to getopt()
188 int opt;
189
190 // Port number to be used by test-platform
191 int portNumber;
192
193 // Daemon flag
194 bool isDaemon = false;
195
196 // Index of the <file path> argument in the arguments list provided
197 int indexFilePath = 1;
198
199 // Handle the -d option
200 while ((opt = getopt(argc, argv, "dh")) != -1) {
201 switch (opt) {
202 case 'd':
203 isDaemon = true;
204 indexFilePath = 2;
205 break;
206 case 'h':
207 showHelp();
208 return 0;
209 default:
210 showInvalidUsage();
211 return -1;
212 }
213 }
214
215 // Check the number of arguments
216 if ((argc < indexFilePath + 1) || (argc > indexFilePath + 2)) {
217
218 showInvalidUsage();
219 return -1;
220 }
221
222 char *filePath = argv[indexFilePath];
223 portNumber = argc > indexFilePath + 1 ? atoi(argv[indexFilePath + 1]) : iDefaultPortNumber;
224
225 // Choose either blocking or daemon test-platform
226 bool startError;
227 string strError;
228
229 if (isDaemon) {
230
231 startError = startDaemonTestPlatform(filePath, portNumber, strError);
232 } else {
233
234 startError = startBlockingTestPlatform(filePath, portNumber, strError);
235 }
236
237 if (!startError) {
238
239 cerr << "Test-platform error:" << strError.c_str() << endl;
240 return -1;
241 }
242 return 0;
243 }
244