MoteHost: Improve error checking when daemonizing
[remote/remote-mci.git] / diku_mch / MoteHost.cc
blob0ce628d10824b4ebda60fbd4b0e98362971d16fd
1 #include "MoteHost.h"
3 namespace remote { namespace diku_mch {
5 using namespace remote::util;
7 int MoteHost::clientsock;
8 int MoteHost::plugpipe;
9 Message MoteHost::msg;
10 DeviceManager MoteHost::devices;
11 Configuration MoteHost::config;
13 void MoteHost::lookForServer()
15 while (1) {
16 std::string host = config.vm["serverAddress"].as<std::string>();
17 uint16_t port = config.vm["serverPort"].as<uint16_t>();
18 uint64_t secs = config.vm["serverConnectionRetryInterval"].as<uint64_t>();
20 Log::info("Connecting to %s on port %u...", host.c_str(), port);
21 clientsock = openClientSocket(host, port);
22 if (clientsock >= 0) {
23 Log::info("Connected!");
24 setKeepAlive(clientsock, 3, 120, 30);
26 try {
27 serviceLoop();
28 close(clientsock);
30 } catch (remote::protocols::MMSException e) {
31 Log::error("Exception: %s", e.what());
33 Log::error("Disconnected");
35 } else {
36 Log::error("Connection failed");
39 Log::info("Reconnecting in %llu seconds...", secs);
40 usleep(secs * 1000000);
44 void MoteHost::serviceLoop()
46 std::string eventPipe = config.vm["usbPlugEventPipe"].as<std::string>();
47 fd_set fdset;
48 int res = 0, p;
50 remove(eventPipe.c_str());
51 if (mkfifo(eventPipe.c_str(), 666) == -1) {
52 std::string err = "Failed to make fifo " + eventPipe + ": " + strerror(errno);
53 __THROW__ (err.c_str());
56 plugpipe = open(eventPipe.c_str(), O_RDONLY | O_NONBLOCK);
57 if (plugpipe < 0) {
58 std::string err = "Failed to open fifo " + eventPipe + ": " + strerror(errno);
59 __THROW__ (err.c_str());
62 // the first thing to do is send all current mote information to the server
63 devices.refresh(config.vm["devicePath"].as<std::string>());
64 Log::debug("Sending mote list to server");
65 MsgPlugEvent msgPlugEvent(PLUG_MOTES);
66 if (makeMoteInfoList(devices.motes, msgPlugEvent.getInfoList())) {
67 HostMsg hostMsg(msgPlugEvent);
68 Message msg;
69 msg.sendMsg(clientsock,hostMsg);
72 Log::debug("Entering service loop");
73 while (res > -1) {
74 int maxfd = rebuildFdSet(fdset);
76 // wait for non-blocking reads on the fds
77 res = select(maxfd+1, &fdset, NULL, NULL, NULL);
79 if ( res > -1 )
81 if (FD_ISSET(clientsock,&fdset))
83 handleMessage();
86 if (FD_ISSET(plugpipe,&fdset))
88 handlePlugEvent();
91 motemap_t::const_iterator moteI = devices.motes.begin();
93 while (moteI != devices.motes.end())
95 p = moteI->second->getFd();
96 if (p > 0 && FD_ISSET(p,&fdset))
98 handleMoteData(moteI->second);
100 moteI++;
104 close(plugpipe);
107 int MoteHost::rebuildFdSet(fd_set& fdset)
109 int p,maxp;
110 Mote* pmote;
111 FD_ZERO(&fdset);
112 motemap_t::const_iterator moteI = devices.motes.begin();
114 // put in valid mote file descriptors
115 maxp = 0;
116 while (moteI != devices.motes.end())
118 pmote = moteI->second;
119 p = pmote->getFd();
120 if (p > 0 && pmote->isValid())
122 if (p > maxp) {maxp = p;}
123 FD_SET(p, &fdset);
125 moteI++;
128 // fd for the connected server
129 FD_SET(clientsock, &fdset);
130 if (clientsock > maxp) {maxp = clientsock;}
131 FD_SET(plugpipe, &fdset);
132 if (plugpipe > maxp) {maxp = plugpipe;}
133 return maxp;
136 void MoteHost::handlePlugEvent()
138 Message msg;
139 // for now, just assume that a plug event occured
140 char c;
141 // empty the pipe
142 int i = 1;
143 Log::info("Handling plug event");
144 while ( i == 1 )
146 i = read(plugpipe,&c,1);
147 if ( i <= 0 )
149 close(plugpipe);
150 plugpipe = open(config.vm["usbPlugEventPipe"].as<std::string>().c_str(),O_RDONLY | O_NONBLOCK);
154 devices.refresh(config.vm["devicePath"].as<std::string>());
156 MsgPlugEvent msgUnplugEvent(UNPLUG_MOTES);
157 if (makeMoteInfoList(devices.lostMotes, msgUnplugEvent.getInfoList()))
159 HostMsg hostMsg(msgUnplugEvent);
160 msg.sendMsg(clientsock,hostMsg);
163 MsgPlugEvent msgPlugEvent(PLUG_MOTES);
164 if (makeMoteInfoList(devices.newMotes,msgPlugEvent.getInfoList()))
166 HostMsg hostMsg(msgPlugEvent);
167 msg.sendMsg(clientsock,hostMsg);
171 bool MoteHost::makeMoteInfoList(motemap_t& motelist, MsgMoteConnectionInfoList& infolist)
173 motemap_t::const_iterator moteI;
175 infolist.clear();
177 for (moteI = motelist.begin(); moteI != motelist.end(); moteI++) {
178 Mote *mote = moteI->second;
179 MsgMoteConnectionInfo info(mote->getMac(), mote->getDevicePath(),
180 mote->getPlatform());
182 infolist.addMoteInfo(info);
185 return motelist.size() > 0 ? true : false;
189 void MoteHost::handleMessage()
191 motemap_t::const_iterator moteI;
192 Mote *mote;
194 if (msg.nonBlockingRecv(clientsock))
196 uint8_t* buffer = msg.getData();
197 uint32_t buflen = msg.getLength();
198 HostMsg hostMsg(buffer,buflen);
200 if (hostMsg.getType() != HOSTMSGTYPE_HOSTREQUEST)
202 __THROW__ ("Can only handle hostmote messages!");
204 MsgHostRequest& msgHostRequest = hostMsg.getHostRequest();
205 MsgMoteAddresses& addresses = msgHostRequest.getMoteAddresses();
206 buffer = (uint8_t*)msgHostRequest.getMessage().getData();
207 buflen = msgHostRequest.getMessage().getDataLength();
208 MoteMsg moteMsg(buffer,buflen);
210 moteI = devices.motes.find(addresses.getMac());
212 if (moteI == devices.motes.end())
214 Log::warn("Mote %s unknown!", addresses.getMac().c_str());
215 MsgHostConfirm msgHostConfirm(MSGHOSTCONFIRM_UNKNOWN_MOTE,addresses,msgHostRequest.getMessage());
216 HostMsg msgReply(msgHostConfirm);
217 msg.sendMsg(clientsock,msgReply);
218 return;
221 mote = moteI->second;
223 switch (moteMsg.getType()) {
224 case MOTEMSGTYPE_REQUEST:
225 handleRequest(mote,addresses,moteMsg.getRequest());
226 break;
227 case MOTEMSGTYPE_DATA:
229 MsgPayload payload = moteMsg.getData();
230 mote->writeBuf((const char*)payload.getData(),payload.getDataLength());
231 break;
233 default:
234 __THROW__ ("Invalid message type!");
239 void MoteHost::handleRequest(Mote* mote, MsgMoteAddresses& addresses, MsgRequest& request)
241 uint8_t command = request.getCommand();
242 result_t result;
244 Log::debug("Mote %s got command=%u", addresses.getMac().c_str(), command);
246 switch (command)
248 case MOTECOMMAND_PROGRAM:
249 result = program(mote, addresses, request.getFlashImage());
250 // don't confirm until programming is done
251 if (result == SUCCESS)
252 return;
253 break;
254 case MOTECOMMAND_CANCELPROGRAMMING:
255 Log::info("User cancelling programming");
256 result = mote->cancelProgramming();
257 break;
258 case MOTECOMMAND_STATUS:
259 result = SUCCESS;
260 break;
261 case MOTECOMMAND_RESET:
262 result = mote->reset();
263 break;
264 case MOTECOMMAND_START:
265 result = mote->start();
266 break;
267 case MOTECOMMAND_STOP:
268 result = mote->stop();
269 break;
270 default:
271 Log::error("Unkown command %u", command);
272 return;
276 MsgConfirm msgConfirm(command, result, mote->getStatus());
277 MoteMsg moteMsg(msgConfirm);
278 MsgPayload msgPayload(moteMsg);
279 MsgHostConfirm msgHostConfirm(MSGHOSTCONFIRM_OK,addresses,msgPayload);
280 HostMsg hostMsg(msgHostConfirm);
281 Message msg;
282 msg.sendMsg(clientsock,hostMsg);
286 void MoteHost::handleMoteData(Mote* mote)
288 char buf[1000];
289 ssize_t readlen = sizeof(buf);
291 MsgMoteAddresses msgMoteAddresses(mote->getMac());
293 while (readlen == sizeof(buf)) {
294 readlen = mote->readBuf(buf, sizeof(buf));
295 if (readlen > 0) {
296 Log::debug("'%.*s'", readlen, buf);
297 uint32_t len = readlen;
298 MsgPayload msgData;
299 msgData.setPayload(len,(uint8_t*)buf);
300 MoteMsg moteMsg(msgData);
301 MsgPayload msgPayload(moteMsg);
302 MsgHostConfirm msgHostConfirm(MSGHOSTCONFIRM_OK,msgMoteAddresses,msgPayload);
303 HostMsg hostMsg(msgHostConfirm);
304 Message msg;
305 msg.sendMsg(clientsock,hostMsg);
309 // check if we're done programming
310 if ( readlen <= 0 )
312 result_t result = mote->getChildResult();
314 if (result != NOT_SUPPORTED) {
315 Log::info("Programming done!");
316 remove(mote->getImagePath().c_str());
317 MsgConfirm msgConfirm(MOTECOMMAND_PROGRAM, result, mote->getStatus());
318 MoteMsg moteMsg(msgConfirm);
319 MsgPayload msgPayload(moteMsg);
320 MsgHostConfirm msgHostConfirm(MSGHOSTCONFIRM_OK,msgMoteAddresses,msgPayload);
321 HostMsg hostMsg(msgHostConfirm);
322 Message msg;
323 msg.sendMsg(clientsock,hostMsg);
324 } else {
325 Log::info("Invalidating mote '%s'", mote->getMac().c_str());
326 mote->invalidate();
327 mote->closeTty();
332 result_t MoteHost::program(Mote *mote, MsgMoteAddresses& addresses, MsgPayload& image)
334 std::string filename = mote->getImagePath();
336 if (mote->getStatus() == MOTE_PROGRAMMING)
337 return FAILURE;
339 if (File::writeFile(filename, image.getData(), image.getDataLength())) {
340 std::string mac_env = "macaddress=" + mote->getMac();
341 std::string tos_env = "tosaddress=" + addresses.getTosAddress();
342 char * const args[] = {
343 (char *) mote->getProgrammerPath().c_str(),
344 (char *) mote->getTty().c_str(),
345 (char *) filename.c_str(),
346 NULL
348 char * const envp[] = {
349 (char *) mac_env.c_str(),
350 (char *) tos_env.c_str(),
351 NULL
354 Log::info("Programming TTY %s", mote->getTty().c_str());
356 if (mote->runChild(args, envp))
357 return SUCCESS;
359 remove(filename.c_str());
362 return FAILURE;
366 int MoteHost::main(int argc,char** argv)
368 config.read(argc,argv);
369 Log::open("diku_mch", LOG_INFO);
370 if (config.vm["daemonize"].as<int>()) {
371 switch (fork()) {
372 case -1:
373 Log::error("Failed to fork daemon");
374 exit(EXIT_FAILURE);
376 default:
377 _exit(EXIT_SUCCESS);
379 case 0:
380 Log::info("Running as daemon");
383 setsid();
384 fclose(stdin);
385 fclose(stdout);
386 fclose(stderr);
389 MoteHost::lookForServer();
390 return 0;
395 int main(int argc,char** argv)
397 return remote::diku_mch::MoteHost::main(argc,argv);