Adjust to coding style rules
[platform/core/security/vasum.git] / client / vasum-client-impl.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19
20 /**
21  * @file
22  * @author  Mateusz Malicki (m.malicki2@samsung.com)
23  * @brief   This file contains vasum-server's client implementation
24  */
25
26 //TODO: Make dispatcher related function thread-safe.
27 //For now vsm_connect, vsm_get_dispatcher_type, vsm_set_dispatcher_type,
28 //vsm_get_poll_fd, vsm_enter_eventloop can't be used at the same time.
29 //TODO: Make vsm_get_status_message thread-safe version (vsm_get_status_message_r)
30
31 #include "config.hpp"
32 #include "vasum-client-impl.hpp"
33 #include "utils.hpp"
34 #include "exception.hpp"
35 #include "utils/exception.hpp"
36 #include "logger/logger.hpp"
37 #include "host-ipc-definitions.hpp"
38 #include "ipc/client.hpp"
39 #include "api/messages.hpp"
40
41 #include <algorithm>
42 #include <vector>
43 #include <memory>
44 #include <cstring>
45 #include <fstream>
46 #include <arpa/inet.h>
47 #include <linux/if.h>
48
49 #include <boost/algorithm/string/split.hpp>
50 #include <boost/algorithm/string/classification.hpp>
51
52 using namespace std;
53 using namespace utils;
54 using namespace vasum;
55
56 namespace {
57
58 const int TIMEOUT_INFINITE = -1;
59
60 VsmZoneState getZoneState(const char* state)
61 {
62     if (strcmp(state, "STOPPED") == 0) {
63         return STOPPED;
64     } else if (strcmp(state, "STARTING") == 0) {
65         return STARTING;
66     } else if (strcmp(state, "RUNNING") == 0) {
67         return RUNNING;
68     } else if (strcmp(state, "STOPPING") == 0) {
69         return STOPPING;
70     } else if (strcmp(state, "ABORTING") == 0) {
71         return ABORTING;
72     } else if (strcmp(state, "FREEZING") == 0) {
73         return FREEZING;
74     } else if (strcmp(state, "FROZEN") == 0) {
75         return FROZEN;
76     } else if (strcmp(state, "THAWED") == 0) {
77         return THAWED;
78     } else if (strcmp(state, "LOCKED") == 0) {
79         return LOCKED;
80     } else if (strcmp(state, "MAX_STATE") == 0) {
81         return MAX_STATE;
82     } else if (strcmp(state, "ACTIVATING") == 0) {
83         return ACTIVATING;
84     }
85     throw InvalidResponseException("Unknown state");
86 }
87
88 void convert(const api::VectorOfStrings& in, VsmArrayString& out)
89 {
90     out = reinterpret_cast<char**>(calloc(in.values.size() + 1, sizeof(char*)));
91     for (size_t i = 0; i < in.values.size(); ++i) {
92         out[i] = ::strdup(in.values[i].c_str());
93     }
94 }
95
96 void convert(const api::ZoneInfoOut& info, VsmZone& zone)
97 {
98     VsmZone vsmZone = reinterpret_cast<VsmZone>(malloc(sizeof(*vsmZone)));
99     vsmZone->id = ::strdup(info.id.c_str());
100     vsmZone->terminal = info.vt;
101     vsmZone->state = getZoneState(info.state.c_str());
102     vsmZone->rootfs_path = ::strdup(info.rootPath.c_str());
103     zone = vsmZone;
104 }
105
106 string toString(const in_addr* addr)
107 {
108     char buf[INET_ADDRSTRLEN];
109     const char* ret = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
110     if (ret == NULL) {
111         throw InvalidArgumentException(getSystemErrorMessage());
112     }
113     return ret;
114 }
115
116 string toString(const in6_addr* addr)
117 {
118     char buf[INET6_ADDRSTRLEN];
119     const char* ret = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
120     if (ret == NULL) {
121         throw InvalidArgumentException(getSystemErrorMessage());
122     }
123     return ret;
124 }
125
126 bool readFirstLineOfFile(const string& path, string& ret)
127 {
128     ifstream file(path);
129     if (!file) {
130         return false;
131     }
132
133     getline(file, ret);
134     return true;
135 }
136
137 } //namespace
138
139 #define IS_SET(param)                                            \
140     if (!param) {                                                \
141         throw InvalidArgumentException(#param " is not set");    \
142     }
143
144 Client::Status::Status()
145     : mVsmStatus(VSMCLIENT_SUCCESS), mMsg()
146 {
147 }
148
149 Client::Status::Status(VsmStatus status, const string& msg)
150     : mVsmStatus(status), mMsg(msg)
151 {
152 }
153
154 Client::Client() noexcept
155 {
156 }
157
158 Client::~Client() noexcept
159 {
160 }
161
162 bool Client::isConnected() const
163 {
164     return mClient && mClient->isStarted();
165 }
166
167 bool Client::isInternalDispatcherEnabled() const
168 {
169     return static_cast<bool>(mInternalDispatcher);
170 }
171
172 ipc::epoll::EventPoll& Client::getEventPoll() const
173 {
174     if ((mInternalDispatcher && mEventPoll) || (!mInternalDispatcher && !mEventPoll)) {
175         throw OperationFailedException("Can't determine dispatcher method");
176     }
177
178     if (isInternalDispatcherEnabled()) {
179         return mInternalDispatcher->getPoll();
180     } else {
181         return *mEventPoll;
182     }
183 }
184
185 VsmStatus Client::coverException(const function<void(void)>& worker) noexcept
186 {
187     try {
188         worker();
189         mStatusMutex.lock();
190         mStatus = Status(VSMCLIENT_SUCCESS);
191     } catch (const IOException& ex) {
192         mStatus = Status(VSMCLIENT_IO_ERROR, ex.what());
193     } catch (const OperationFailedException& ex) {
194         mStatus = Status(VSMCLIENT_OPERATION_FAILED, ex.what());
195     } catch (const InvalidArgumentException& ex) {
196         mStatus = Status(VSMCLIENT_INVALID_ARGUMENT, ex.what());
197     } catch (const InvalidResponseException& ex) {
198         mStatus = Status(VSMCLIENT_OTHER_ERROR, ex.what());
199     } catch (const ClientException& ex) {
200         mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
201     } catch (const ipc::IPCUserException& ex) {
202         mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
203     } catch (const ipc::IPCException& ex) {
204         mStatus = Status(VSMCLIENT_IO_ERROR, ex.what());
205     } catch (const exception& ex) {
206         mStatus = Status(VSMCLIENT_CUSTOM_ERROR, ex.what());
207     }
208     VsmStatus ret = mStatus.mVsmStatus;
209     mStatusMutex.unlock();
210     return ret;
211 }
212
213 VsmStatus Client::connectSystem() noexcept
214 {
215     return connect(HOST_IPC_SOCKET);
216 }
217
218 VsmStatus Client::connect(const std::string& address) noexcept
219 {
220     return coverException([&] {
221         if (!mInternalDispatcher && !mEventPoll) {
222             vsm_set_dispatcher_type(VSMDISPATCHER_INTERNAL);
223         }
224         mClient.reset(new ipc::Client(getEventPoll(), address));
225         mClient->start();
226     });
227 }
228
229 VsmStatus Client::disconnect() noexcept
230 {
231     return coverException([&] {
232         mClient.reset();
233     });
234 }
235
236 VsmStatus Client::vsm_get_poll_fd(int* fd) noexcept
237 {
238     return coverException([&] {
239         IS_SET(fd);
240         if (isInternalDispatcherEnabled()) {
241             throw OperationFailedException("Can't get event fd from internal dispatcher");
242         }
243         *fd =  mEventPoll->getPollFD();
244     });
245 }
246
247 VsmStatus Client::vsm_enter_eventloop(int /* flags */, int timeout) noexcept
248 {
249     return coverException([&] {
250         if (isInternalDispatcherEnabled()) {
251             throw OperationFailedException("Can't enter to event loop of internal dispatcher");
252         }
253         mEventPoll->dispatchIteration(timeout);
254     });
255 }
256
257 VsmStatus Client::vsm_set_dispatcher_type(VsmDispacherType dispacher) noexcept
258 {
259     return coverException([&] {
260         if (isConnected()) {
261             throw OperationFailedException("Can't change dispacher");
262         }
263         switch (dispacher) {
264             case VSMDISPATCHER_INTERNAL:
265                 mInternalDispatcher.reset(new ipc::epoll::ThreadDispatcher());
266                 mEventPoll.reset();
267                 break;
268             case VSMDISPATCHER_EXTERNAL:
269                 mEventPoll.reset(new ipc::epoll::EventPoll());
270                 mInternalDispatcher.reset();
271                 break;
272             default:
273                 throw OperationFailedException("Unsupported EventDispacher type");
274         }
275     });
276 }
277
278 VsmStatus Client::vsm_get_dispatcher_type(VsmDispacherType* dispacher) noexcept
279 {
280     return coverException([&] {
281         IS_SET(dispacher);
282
283         if (isInternalDispatcherEnabled()) {
284             *dispacher = VSMDISPATCHER_INTERNAL;
285         } else {
286             *dispacher = VSMDISPATCHER_EXTERNAL;
287         }
288     });
289 }
290
291 const char* Client::vsm_get_status_message() const noexcept
292 {
293     return mStatus.mMsg.c_str();
294 }
295
296 VsmStatus Client::vsm_get_status() const noexcept
297 {
298     lock_guard<mutex> lock(mStatusMutex);
299     return mStatus.mVsmStatus;
300 }
301
302 VsmStatus Client::vsm_get_zone_dbuses(VsmArrayString* /*keys*/, VsmArrayString* /*values*/) noexcept
303 {
304     return coverException([&] {
305         //TODO: Remove vsm_get_zone_dbuses from API
306         throw OperationFailedException("Not implemented");
307     });
308 }
309
310 VsmStatus Client::vsm_lock_queue() noexcept
311 {
312     return coverException([&] {
313         *mClient->callSync<api::Void, api::Void>(
314             vasum::api::ipc::METHOD_LOCK_QUEUE,
315             std::make_shared<api::Void>());
316     });
317 }
318
319 VsmStatus Client::vsm_unlock_queue() noexcept
320 {
321     return coverException([&] {
322         *mClient->callSync<api::Void, api::Void>(
323             vasum::api::ipc::METHOD_UNLOCK_QUEUE,
324             std::make_shared<api::Void>());
325     });
326 }
327
328 VsmStatus Client::vsm_get_zone_ids(VsmArrayString* array) noexcept
329 {
330     return coverException([&] {
331         IS_SET(array);
332
333         api::ZoneIds zoneIds = *mClient->callSync<api::Void, api::ZoneIds>(
334             vasum::api::ipc::METHOD_GET_ZONE_ID_LIST,
335             std::make_shared<api::Void>());
336         convert(zoneIds, *array);
337     });
338 }
339
340 VsmStatus Client::vsm_get_active_zone_id(VsmString* id) noexcept
341 {
342     return coverException([&] {
343         IS_SET(id);
344
345         api::ZoneId zoneId = *mClient->callSync<api::Void, api::ZoneId>(
346             api::ipc::METHOD_GET_ACTIVE_ZONE_ID,
347             std::make_shared<api::Void>());
348         *id = ::strdup(zoneId.value.c_str());
349     });
350 }
351
352 VsmStatus Client::vsm_get_zone_rootpath(const char* id, VsmString* rootpath) noexcept
353 {
354     return coverException([&] {
355         IS_SET(id);
356         IS_SET(rootpath);
357
358         api::ZoneInfoOut info = *mClient->callSync<api::ZoneId, api::ZoneInfoOut>(
359             api::ipc::METHOD_GET_ZONE_INFO,
360             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
361         *rootpath = ::strdup(info.rootPath.c_str());
362     });
363 }
364
365 VsmStatus Client::vsm_lookup_zone_by_pid(int pid, VsmString* id) noexcept
366 {
367     return coverException([&] {
368         IS_SET(id);
369
370         const string path = "/proc/" + to_string(pid) + "/cpuset";
371
372         string cpuset;
373         if (!readFirstLineOfFile(path, cpuset)) {
374             throw InvalidArgumentException("Process not found");
375         }
376
377         string zoneId;
378         if (!parseZoneIdFromCpuSet(cpuset, zoneId)) {
379             throw OperationFailedException("unknown format of cpuset");
380         }
381
382         *id = ::strdup(zoneId.c_str());
383     });
384 }
385
386 VsmStatus Client::vsm_lookup_zone_by_id(const char* id, VsmZone* zone) noexcept
387 {
388     return coverException([&] {
389         IS_SET(id);
390         IS_SET(zone);
391
392         api::ZoneInfoOut info = *mClient->callSync<api::ZoneId, api::ZoneInfoOut>(
393             api::ipc::METHOD_GET_ZONE_INFO,
394             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
395         convert(info, *zone);
396     });
397 }
398
399 VsmStatus Client::vsm_lookup_zone_by_terminal_id(int, VsmString*) noexcept
400 {
401     return coverException([&] {
402         //TODO: Implement vsm_lookup_zone_by_terminal_id
403         throw OperationFailedException("Not implemented");
404     });
405 }
406
407 VsmStatus Client::vsm_set_active_zone(const char* id) noexcept
408 {
409     return coverException([&] {
410         IS_SET(id);
411
412         mClient->callSync<api::ZoneId, api::Void>(
413             api::ipc::METHOD_SET_ACTIVE_ZONE,
414             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
415     });
416 }
417
418 VsmStatus Client::vsm_create_zone(const char* id, const char* tname) noexcept
419 {
420     return coverException([&] {
421         IS_SET(id);
422
423         string template_name = tname ? tname : "default";
424         mClient->callSync<api::CreateZoneIn, api::Void>(
425             api::ipc::METHOD_CREATE_ZONE,
426             std::make_shared<api::CreateZoneIn>(api::CreateZoneIn{ id, template_name }),
427             TIMEOUT_INFINITE);
428     });
429 }
430
431 VsmStatus Client::vsm_destroy_zone(const char* id) noexcept
432 {
433     return coverException([&] {
434         IS_SET(id);
435         mClient->callSync<api::ZoneId, api::Void>(
436             api::ipc::METHOD_DESTROY_ZONE,
437             std::make_shared<api::ZoneId>(api::ZoneId{ id }),
438             TIMEOUT_INFINITE);
439     });
440 }
441
442 VsmStatus Client::vsm_shutdown_zone(const char* id) noexcept
443 {
444     return coverException([&] {
445         IS_SET(id);
446         mClient->callSync<api::ZoneId, api::Void>(
447             api::ipc::METHOD_SHUTDOWN_ZONE,
448             std::make_shared<api::ZoneId>(api::ZoneId{ id }),
449             TIMEOUT_INFINITE);
450     });
451 }
452
453 VsmStatus Client::vsm_start_zone(const char* id) noexcept
454 {
455     return coverException([&] {
456         IS_SET(id);
457         mClient->callSync<api::ZoneId, api::Void>(
458             api::ipc::METHOD_START_ZONE,
459             std::make_shared<api::ZoneId>(api::ZoneId{ id }),
460             TIMEOUT_INFINITE);
461     });
462 }
463
464 VsmStatus Client::vsm_lock_zone(const char* id) noexcept
465 {
466     return coverException([&] {
467         IS_SET(id);
468         mClient->callSync<api::ZoneId, api::Void>(
469             api::ipc::METHOD_LOCK_ZONE,
470             std::make_shared<api::ZoneId>(api::ZoneId{ id }),
471             TIMEOUT_INFINITE);
472     });
473 }
474
475 VsmStatus Client::vsm_unlock_zone(const char* id) noexcept
476 {
477     return coverException([&] {
478         IS_SET(id);
479         mClient->callSync<api::ZoneId, api::Void>(
480             api::ipc::METHOD_UNLOCK_ZONE,
481             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
482     });
483 }
484
485 VsmStatus Client::vsm_add_state_callback(VsmZoneDbusStateFunction /* zoneDbusStateCallback */,
486                                     void* /* data */,
487                                     VsmSubscriptionId* /* subscriptionId */) noexcept
488 {
489     return coverException([&] {
490         //TODO: Implement vsm_add_state_callback
491         throw OperationFailedException("Not implemented");
492     });
493 }
494
495 VsmStatus Client::vsm_del_state_callback(VsmSubscriptionId subscriptionId) noexcept
496 {
497     return coverException([&] {
498         mClient->removeMethod(subscriptionId);
499     });
500 }
501
502 VsmStatus Client::vsm_grant_device(const char* id, const char* device, uint32_t flags) noexcept
503 {
504     return coverException([&] {
505         IS_SET(id);
506         IS_SET(device);
507
508         mClient->callSync<api::GrantDeviceIn, api::Void>(
509             api::ipc::METHOD_GRANT_DEVICE,
510             std::make_shared<api::GrantDeviceIn>(api::GrantDeviceIn{ id, device, flags }));
511     });
512 }
513
514 VsmStatus Client::vsm_revoke_device(const char* id, const char* device) noexcept
515 {
516     return coverException([&] {
517         IS_SET(id);
518         IS_SET(device);
519
520         mClient->callSync<api::RevokeDeviceIn, api::Void>(
521             api::ipc::METHOD_REVOKE_DEVICE,
522             std::make_shared<api::RevokeDeviceIn>(api::RevokeDeviceIn{ id, device }));
523     });
524 }
525
526 VsmStatus Client::vsm_zone_get_netdevs(const char* id, VsmArrayString* netdevIds) noexcept
527 {
528     return coverException([&] {
529         IS_SET(id);
530         IS_SET(netdevIds);
531
532         api::NetDevList netdevs = *mClient->callSync<api::ZoneId, api::NetDevList>(
533             api::ipc::METHOD_GET_NETDEV_LIST,
534             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
535         convert(netdevs, *netdevIds);
536     });
537 }
538
539 VsmStatus Client::vsm_netdev_get_ip_addr(const char* id,
540                                          const char* netdevId,
541                                          int type,
542                                          void* addr) noexcept
543 {
544     using namespace boost::algorithm;
545
546     return coverException([&] {
547         IS_SET(id);
548         IS_SET(netdevId);
549         IS_SET(addr);
550
551         api::GetNetDevAttrs attrs = *mClient->callSync<api::GetNetDevAttrsIn, api::GetNetDevAttrs>(
552             api::ipc::METHOD_GET_NETDEV_ATTRS,
553             std::make_shared<api::GetNetDevAttrsIn>(api::GetNetDevAttrsIn{ id, netdevId }));
554
555         auto it = find_if(attrs.values.begin(),
556                           attrs.values.end(),
557                           [type](const api::StringPair& entry) {
558                 return entry.first == (type == AF_INET ? "ipv4" : "ipv6");
559         });
560
561         if (it != attrs.values.end()) {
562             vector<string> addrAttrs;
563             for(auto addrAttr : split(addrAttrs, it->second, is_any_of(","))) {
564                 size_t pos = addrAttr.find(":");
565                 if (addrAttr.substr(0, pos) == "ip") {
566                     if (pos != string::npos && pos < addrAttr.length() &&
567                         inet_pton(type, addrAttr.substr(pos + 1).c_str(), addr) == 1) {
568                         //XXX: return only one address
569                         return;
570                     } else {
571                         throw InvalidResponseException("Wrong address format returned");
572                     }
573                 }
574             }
575         }
576         throw OperationFailedException("Address not found");
577     });
578 }
579
580 VsmStatus Client::vsm_netdev_get_ipv4_addr(const char* id,
581                                       const char* netdevId,
582                                       struct in_addr* addr) noexcept
583 {
584     return vsm_netdev_get_ip_addr(id, netdevId, AF_INET, addr);
585 }
586
587 VsmStatus Client::vsm_netdev_get_ipv6_addr(const char* id,
588                                       const char* netdevId,
589                                       struct in6_addr* addr) noexcept
590 {
591     return vsm_netdev_get_ip_addr(id, netdevId, AF_INET6, addr);
592 }
593
594 VsmStatus Client::vsm_netdev_set_ipv4_addr(const char* id,
595                                       const char* netdevId,
596                                       struct in_addr* addr,
597                                       int prefix) noexcept
598 {
599     return coverException([&] {
600         IS_SET(id);
601         IS_SET(netdevId);
602         IS_SET(addr);
603
604         string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix);
605         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
606             api::ipc::METHOD_SET_NETDEV_ATTRS,
607             std::make_shared<api::SetNetDevAttrsIn>(
608                 api::SetNetDevAttrsIn{ id, netdevId, { { "ipv4", value } }  }));
609     });
610 }
611
612 VsmStatus Client::vsm_netdev_set_ipv6_addr(const char* id,
613                                       const char* netdevId,
614                                       struct in6_addr* addr,
615                                       int prefix) noexcept
616 {
617     return coverException([&] {
618         IS_SET(id);
619         IS_SET(netdevId);
620         IS_SET(addr);
621
622         string value = "ip:" + toString(addr) + ",""prefixlen:" + to_string(prefix);
623         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
624             api::ipc::METHOD_SET_NETDEV_ATTRS,
625             std::make_shared<api::SetNetDevAttrsIn>(
626                 api::SetNetDevAttrsIn{ id, netdevId, { { "ipv6", value } }  }));
627     });
628 }
629
630 VsmStatus Client::vsm_netdev_del_ipv4_addr(const char* id,
631                                       const char* netdevId,
632                                       struct in_addr* addr,
633                                       int prefix) noexcept
634 {
635     return coverException([&] {
636         IS_SET(id);
637         IS_SET(netdevId);
638         IS_SET(addr);
639
640         //CIDR notation
641         string ip = toString(addr) + "/" + to_string(prefix);
642         mClient->callSync<api::DeleteNetdevIpAddressIn, api::Void>(
643             api::ipc::METHOD_DELETE_NETDEV_IP_ADDRESS,
644             std::make_shared<api::DeleteNetdevIpAddressIn>(
645                 api::DeleteNetdevIpAddressIn{ id, netdevId, ip }));
646     });
647 }
648
649 VsmStatus Client::vsm_netdev_del_ipv6_addr(const char* id,
650                                       const char* netdevId,
651                                       struct in6_addr* addr,
652                                       int prefix) noexcept
653 {
654     return coverException([&] {
655         IS_SET(id);
656         IS_SET(netdevId);
657         IS_SET(addr);
658
659         //CIDR notation
660         string ip = toString(addr) + "/" + to_string(prefix);
661         mClient->callSync<api::DeleteNetdevIpAddressIn, api::Void>(
662             api::ipc::METHOD_DELETE_NETDEV_IP_ADDRESS,
663             std::make_shared<api::DeleteNetdevIpAddressIn>(
664                 api::DeleteNetdevIpAddressIn{ id, netdevId, ip }));
665     });
666 }
667
668
669 VsmStatus Client::vsm_netdev_up(const char* id, const char* netdevId) noexcept
670 {
671     return coverException([&] {
672         IS_SET(id);
673         IS_SET(netdevId);
674
675         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
676             api::ipc::METHOD_SET_NETDEV_ATTRS,
677             std::make_shared<api::SetNetDevAttrsIn>(
678                 api::SetNetDevAttrsIn{ id, netdevId, { { "flags", to_string(IFF_UP) },
679                                                        { "change", to_string(IFF_UP) }  }  }));
680     });
681 }
682
683 VsmStatus Client::vsm_netdev_down(const char* id, const char* netdevId) noexcept
684 {
685     return coverException([&] {
686         IS_SET(id);
687         IS_SET(netdevId);
688
689         mClient->callSync<api::SetNetDevAttrsIn, api::Void>(
690             api::ipc::METHOD_SET_NETDEV_ATTRS,
691             std::make_shared<api::SetNetDevAttrsIn>(
692                 api::SetNetDevAttrsIn{ id, netdevId, { { "flags", to_string(~IFF_UP) },
693                                                        { "change", to_string(IFF_UP) }  }  }));
694     });
695 }
696
697 VsmStatus Client::vsm_create_netdev_veth(const char* id,
698                                     const char* zoneDev,
699                                     const char* hostDev) noexcept
700 {
701     return coverException([&] {
702         IS_SET(id);
703         IS_SET(zoneDev);
704         IS_SET(hostDev);
705
706         mClient->callSync<api::CreateNetDevVethIn, api::Void>(
707             api::ipc::METHOD_CREATE_NETDEV_VETH,
708             std::make_shared<api::CreateNetDevVethIn>(
709                 api::CreateNetDevVethIn{ id, zoneDev, hostDev }));
710     });
711 }
712
713 VsmStatus Client::vsm_create_netdev_macvlan(const char* id,
714                                        const char* zoneDev,
715                                        const char* hostDev,
716                                        enum macvlan_mode mode) noexcept
717 {
718     return coverException([&] {
719         IS_SET(id);
720         IS_SET(zoneDev);
721         IS_SET(hostDev);
722
723         mClient->callSync<api::CreateNetDevMacvlanIn, api::Void>(
724             api::ipc::METHOD_CREATE_NETDEV_MACVLAN,
725             std::make_shared<api::CreateNetDevMacvlanIn>(
726                 api::CreateNetDevMacvlanIn{ id, zoneDev, hostDev, mode }));
727     });
728 }
729
730 VsmStatus Client::vsm_create_netdev_phys(const char* id, const char* devId) noexcept
731 {
732     return coverException([&] {
733         IS_SET(id);
734         IS_SET(devId);
735
736         mClient->callSync<api::CreateNetDevPhysIn, api::Void>(
737             api::ipc::METHOD_CREATE_NETDEV_PHYS,
738             std::make_shared<api::CreateNetDevPhysIn>(
739                 api::CreateNetDevPhysIn{ id, devId }));
740     });
741 }
742
743 VsmStatus Client::vsm_lookup_netdev_by_name(const char* id,
744                                        const char* netdevId,
745                                        VsmNetdev* netdev) noexcept
746 {
747     using namespace boost::algorithm;
748
749     return coverException([&] {
750         IS_SET(id);
751         IS_SET(netdevId);
752         IS_SET(netdev);
753
754         api::GetNetDevAttrs attrs = *mClient->callSync<api::GetNetDevAttrsIn, api::GetNetDevAttrs>(
755             api::ipc::METHOD_GET_NETDEV_ATTRS,
756             std::make_shared<api::GetNetDevAttrsIn>(api::GetNetDevAttrsIn{ id, netdevId }));
757         auto it = find_if(attrs.values.begin(),
758                           attrs.values.end(),
759                           [](const api::StringPair& entry) {
760                 return entry.first == "type";
761         });
762
763         VsmNetdevType type;
764         if (it == attrs.values.end()) {
765             throw OperationFailedException("Can't fetch netdev type");
766         }
767
768         switch (stoi(it->second)) {
769             case 1<<0  /*IFF_802_1Q_VLAN*/: type = VSMNETDEV_VETH; break;
770             case 1<<21 /*IFF_MACVLAN*/: type = VSMNETDEV_MACVLAN; break;
771             default:
772                 throw InvalidResponseException("Unknown netdev type: " + it->second);
773         }
774
775         *netdev = reinterpret_cast<VsmNetdev>(malloc(sizeof(**netdev)));
776         (*netdev)->name = ::strdup(id);
777         (*netdev)->type = type;
778     });
779 }
780
781 VsmStatus Client::vsm_destroy_netdev(const char* id, const char* devId) noexcept
782 {
783     return coverException([&] {
784         IS_SET(id);
785         IS_SET(devId);
786
787         mClient->callSync<api::DestroyNetDevIn, api::Void>(
788             api::ipc::METHOD_DESTROY_NETDEV,
789             std::make_shared<api::DestroyNetDevIn>(api::DestroyNetDevIn{ id, devId }));
790     });
791 }
792
793 VsmStatus Client::vsm_declare_file(const char* id,
794                               VsmFileType type,
795                               const char *path,
796                               int32_t flags,
797                               mode_t mode,
798                               VsmString* declarationId) noexcept
799 {
800     return coverException([&] {
801         IS_SET(id);
802         IS_SET(path);
803
804         api::Declaration declaration = *mClient->callSync<api::DeclareFileIn, api::Declaration>(
805             api::ipc::METHOD_DECLARE_FILE,
806             std::make_shared<api::DeclareFileIn>(
807                 api::DeclareFileIn{ id, type, path, flags, (int)mode }));
808         if (declarationId != NULL) {
809             *declarationId = ::strdup(declaration.value.c_str());
810         }
811     });
812 }
813
814 VsmStatus Client::vsm_declare_mount(const char *source,
815                                const char* id,
816                                const char *target,
817                                const char *type,
818                                uint64_t flags,
819                                const char *data,
820                                VsmString* declarationId) noexcept
821 {
822     return coverException([&] {
823         IS_SET(source);
824         IS_SET(id);
825         IS_SET(target);
826         IS_SET(type);
827         if (!data) {
828             data = "";
829         }
830
831         api::Declaration declaration = *mClient->callSync<api::DeclareMountIn, api::Declaration>(
832             api::ipc::METHOD_DECLARE_MOUNT,
833             std::make_shared<api::DeclareMountIn>(
834                 api::DeclareMountIn{ source, id, target, type, flags, data }));
835         if (declarationId != NULL) {
836             *declarationId = ::strdup(declaration.value.c_str());
837         }
838     });
839 }
840
841 VsmStatus Client::vsm_declare_link(const char* source,
842                               const char* id,
843                               const char* target,
844                               VsmString* declarationId) noexcept
845 {
846     return coverException([&] {
847         IS_SET(source);
848         IS_SET(id);
849         IS_SET(target);
850
851         api::Declaration declaration = *mClient->callSync<api::DeclareLinkIn, api::Declaration>(
852             api::ipc::METHOD_DECLARE_LINK,
853             std::make_shared<api::DeclareLinkIn>(api::DeclareLinkIn{ source, id, target }));
854         if (declarationId != NULL) {
855             *declarationId = ::strdup(declaration.value.c_str());
856         }
857     });
858 }
859
860 VsmStatus Client::vsm_list_declarations(const char* id, VsmArrayString* declarations) noexcept
861 {
862     return coverException([&] {
863         IS_SET(id);
864         IS_SET(declarations);
865
866         api::Declarations declarationsOut = *mClient->callSync<api::ZoneId, api::Declarations>(
867             api::ipc::METHOD_GET_DECLARATIONS,
868             std::make_shared<api::ZoneId>(api::ZoneId{ id }));
869         convert(declarationsOut, *declarations);
870     });
871 }
872
873 VsmStatus Client::vsm_remove_declaration(const char* id, VsmString declaration) noexcept
874 {
875     return coverException([&] {
876         IS_SET(id);
877         IS_SET(declaration);
878
879         mClient->callSync<api::RemoveDeclarationIn, api::Void>(
880             api::ipc::METHOD_REMOVE_DECLARATION,
881             std::make_shared<api::RemoveDeclarationIn>(api::RemoveDeclarationIn{ id, declaration }));
882     });
883 }
884
885 VsmStatus Client::vsm_notify_active_zone(const char* /*application*/, const char* /*message*/) noexcept
886 {
887     return coverException([&] {
888         //TODO: Implement vsm_notify_active_zone
889         throw OperationFailedException("Not implemented");
890     });
891 }
892
893 VsmStatus Client::vsm_file_move_request(const char* /*destZone*/, const char* /*path*/) noexcept
894 {
895     return coverException([&] {
896         //TODO: Implement vsm_file_move_request
897         throw OperationFailedException("Not implemented");
898     });
899 }
900
901 VsmStatus Client::vsm_add_notification_callback(VsmNotificationFunction /*notificationCallback*/,
902                                            void* /*data*/,
903                                            VsmSubscriptionId* /*subscriptionId*/) noexcept
904 {
905     return coverException([&] {
906         //TODO: Implement vsm_add_notification_callback
907         throw OperationFailedException("Not implemented");
908     });
909 }
910
911 VsmStatus Client::vsm_del_notification_callback(VsmSubscriptionId subscriptionId) noexcept
912 {
913     return coverException([&] {
914         mClient->removeMethod(subscriptionId);
915     });
916 }
917