1// SMTarget.cpp
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string>
6
7#include <OS.h>
8#include <String.h>
9#include <TestShell.h>
10#include <TestUtils.h>
11#include <cppunit/TestAssert.h>
12
13#include "SMTarget.h"
14#include "SMLooper.h"
15#include "SMRemoteTargetApp.h"
16
17
18using namespace std;
19
20
21// SMTarget
22
23// constructor
24SMTarget::SMTarget()
25{
26}
27
28// destructor
29SMTarget::~SMTarget()
30{
31}
32
33// Init
34void
35SMTarget::Init(bigtime_t unblockTime, bigtime_t replyDelay)
36{
37}
38
39// Handler
40BHandler *
41SMTarget::Handler()
42{
43	return NULL;
44}
45
46// Messenger
47BMessenger
48SMTarget::Messenger()
49{
50	return BMessenger();
51}
52
53// DeliverySuccess
54bool
55SMTarget::DeliverySuccess()
56{
57	return false;
58}
59
60
61// LocalSMTarget
62
63// constructor
64LocalSMTarget::LocalSMTarget(bool preferred)
65			 : SMTarget(),
66			   fHandler(NULL),
67			   fLooper(NULL)
68{
69	// create looper and handler
70	fLooper = new SMLooper;
71	fLooper->Run();
72	if (!preferred) {
73		fHandler = new SMHandler;
74		CHK(fLooper->Lock());
75		fLooper->AddHandler(fHandler);
76		fLooper->Unlock();
77	}
78}
79
80// destructor
81LocalSMTarget::~LocalSMTarget()
82{
83	if (fLooper) {
84		fLooper->Lock();
85		if (fHandler) {
86			fLooper->RemoveHandler(fHandler);
87			delete fHandler;
88		}
89		fLooper->Quit();
90	}
91}
92
93// Init
94void
95LocalSMTarget::Init(bigtime_t unblockTime, bigtime_t replyDelay)
96{
97	fLooper->SetReplyDelay(replyDelay);
98	fLooper->BlockUntil(unblockTime);
99}
100
101// Handler
102BHandler *
103LocalSMTarget::Handler()
104{
105	return fHandler;
106}
107
108// Messenger
109BMessenger
110LocalSMTarget::Messenger()
111{
112	return BMessenger(fHandler, fLooper);
113}
114
115// DeliverySuccess
116bool
117LocalSMTarget::DeliverySuccess()
118{
119	return fLooper->DeliverySuccess();
120}
121
122
123// RemoteSMTarget
124
125static const char *kSMRemotePortName = "BMessenger_SMRemoteTarget";
126
127// constructor
128RemoteSMTarget::RemoteSMTarget(bool preferred)
129			  : SMTarget(),
130				fLocalPort(-1),
131				fRemotePort(-1),
132				fTarget()
133{
134	// create unused port name
135	int32 id = atomic_add(&fID, 1);
136	string portName(kSMRemotePortName);
137	BString idString;
138	idString << id;
139	portName += idString.String();
140	// create local port
141	fLocalPort = create_port(5, portName.c_str());
142	CHK(fLocalPort >= 0);
143	// execute the remote app
144	BString unescapedTestDir(BTestShell::GlobalTestDir());
145	unescapedTestDir.CharacterEscape(" \t\n!\"'`$&()?*+{}[]<>|", '\\');
146	string remoteApp(unescapedTestDir.String());
147	remoteApp += "/SMRemoteTargetApp ";
148	remoteApp += portName;
149	if (preferred)
150		remoteApp += " preferred";
151	else
152		remoteApp += " specific";
153	remoteApp += " &";
154	system(remoteApp.c_str());
155	// wait for the remote app to send its init data
156	smrt_init initData;
157	CHK(_GetReply(SMRT_INIT, &initData, sizeof(smrt_init)) == B_OK);
158	fRemotePort = initData.port;
159	fTarget = initData.messenger;
160}
161
162// destructor
163RemoteSMTarget::~RemoteSMTarget()
164{
165	_SendRequest(SMRT_QUIT);
166	delete_port(fLocalPort);
167}
168
169// Init
170void
171RemoteSMTarget::Init(bigtime_t unblockTime, bigtime_t replyDelay)
172{
173	smrt_get_ready data;
174	data.unblock_time = unblockTime;
175	data.reply_delay = replyDelay;
176	CHK(_SendRequest(SMRT_GET_READY, &data, sizeof(smrt_get_ready)) == B_OK);
177}
178
179// Messenger
180BMessenger
181RemoteSMTarget::Messenger()
182{
183	return fTarget;
184}
185
186// DeliverySuccess
187bool
188RemoteSMTarget::DeliverySuccess()
189{
190	CHK(_SendRequest(SMRT_DELIVERY_SUCCESS_REQUEST) == B_OK);
191	smrt_delivery_success data;
192	CHK(_GetReply(SMRT_DELIVERY_SUCCESS_REPLY, &data,
193				  sizeof(smrt_delivery_success)) == B_OK);
194	return data.success;
195}
196
197// _SendRequest
198status_t
199RemoteSMTarget::_SendRequest(int32 code, const void *buffer, size_t size)
200{
201	return write_port(fRemotePort, code, buffer, size);
202}
203
204// _GetReply
205status_t
206RemoteSMTarget::_GetReply(int32 expectedCode, void *buffer, size_t size)
207{
208	status_t error = B_OK;
209	int32 code;
210	ssize_t readSize = read_port(fLocalPort, &code, buffer, size);
211	if (readSize < 0)
212		error = readSize;
213	else if ((uint32)readSize != size)
214		error = B_ERROR;
215	else if (code != expectedCode)
216		error = B_ERROR;
217	return error;
218}
219
220// ID
221int32 RemoteSMTarget::fID = 0;
222
223
224