common/c-api/util.h (186 lines of code) (raw):

#ifndef SWSS_COMMON_C_API_UTIL_H #define SWSS_COMMON_C_API_UTIL_H // External utilities (c-facing) #ifdef __cplusplus extern "C" { #endif #include <stdint.h> // FFI version of std::string&& // This can be converted to an SWSSStrRef with a standard cast typedef struct SWSSStringOpaque *SWSSString; // FFI version of std::string& // This can be converted to an SWSSString with a standard cast // Functions that take SWSSString will move data out of the underlying string, // but functions that take SWSSStrRef will only view it. typedef struct SWSSStrRefOpaque *SWSSStrRef; // FFI version of swss::FieldValueTuple typedef struct { const char *field; SWSSString value; } SWSSFieldValueTuple; // FFI version of std::vector<swss::FieldValueTuple> typedef struct { uint64_t len; SWSSFieldValueTuple *data; } SWSSFieldValueArray; typedef enum { SWSSKeyOperation_SET, SWSSKeyOperation_DEL, } SWSSKeyOperation; // FFI version of swss::KeyOpFieldValuesTuple typedef struct { const char *key; SWSSKeyOperation operation; SWSSFieldValueArray fieldValues; } SWSSKeyOpFieldValues; // FFI version of std::vector<swss::KeyOpFieldValueTuple> typedef struct { uint64_t len; SWSSKeyOpFieldValues *data; } SWSSKeyOpFieldValuesArray; // FFI version of swss::Select::{OBJECT, TIMEOUT, SIGNALINT}. // swss::Select::ERROR is left out because errors are handled separately typedef enum { // Data is available in the object SWSSSelectResult_DATA = 0, // Timed out waiting for data SWSSSelectResult_TIMEOUT = 1, // Waiting was interrupted by a signal SWSSSelectResult_SIGNAL = 2, } SWSSSelectResult; // data should not include a null terminator SWSSString SWSSString_new(const char *data, uint64_t length); // c_str should include a null terminator SWSSString SWSSString_new_c_str(const char *c_str); // It is safe to pass null to this function (not to any other SWSSString functions). This is // useful to take SWSSStrings from other SWSS structs - you can replace the strs in the // structs with null and still safely free the structs. Then, you can call this function with the // populated SWSSString later. void SWSSString_free(SWSSString s); const char *SWSSStrRef_c_str(SWSSStrRef s); // Returns the length of the string, not including the null terminator that is implicitly added by // SWSSStrRef_c_str. uint64_t SWSSStrRef_length(SWSSStrRef s); // arr.data may be null. This is not recursive - elements must be freed separately (for finer // grained control of ownership). void SWSSFieldValueArray_free(SWSSFieldValueArray arr); // kfvs.data may be null. This is not recursive - elements must be freed separately (for finer // grained control of ownership). void SWSSKeyOpFieldValuesArray_free(SWSSKeyOpFieldValuesArray kfvs); #ifdef __cplusplus } #endif // Internal utilities (used to help define c-facing functions) #ifdef __cplusplus #include <boost/cast.hpp> #include <cstring> #include <exception> #include <iostream> #include <memory> #include <string> #include <tuple> #include <utility> #include <vector> #include "../logger.h" #include "../redisapi.h" #include "../schema.h" #include "../select.h" using boost::numeric_cast; namespace swss { extern bool cApiTestingDisableAbort; // In the catch block, we must abort because passing an exception across an ffi boundary is // undefined behavior. It was also decided that no exceptions in swss-common are recoverable, so // there is no reason to convert exceptions into a returnable type. #define SWSSTry(...) \ if (swss::cApiTestingDisableAbort) { \ { __VA_ARGS__; } \ } else { \ try { \ { __VA_ARGS__; } \ } catch (std::exception & e) { \ std::cerr << "Aborting due to exception: " << e.what() << std::endl; \ SWSS_LOG_ERROR("Aborting due to exception: %s", e.what()); \ std::abort(); \ } \ } static inline SWSSSelectResult selectOne(swss::Selectable *s, uint32_t timeout_ms, uint8_t interrupt_on_signal) { Select select; Selectable *sOut; select.addSelectable(s); int ret = select.select(&sOut, numeric_cast<int>(timeout_ms), interrupt_on_signal); switch (ret) { case Select::OBJECT: return SWSSSelectResult_DATA; case Select::ERROR: throw std::system_error(errno, std::generic_category()); case Select::TIMEOUT: return SWSSSelectResult_TIMEOUT; case Select::SIGNALINT: return SWSSSelectResult_SIGNAL; default: SWSS_LOG_THROW("impossible: unhandled Select::select() return value: %d", ret); } } static inline SWSSString makeString(std::string &&s) { std::string *data_s = new std::string(std::move(s)); return (struct SWSSStringOpaque *)data_s; } // T is anything that has a .size() method and which can be iterated over for pair<string, string> // eg vector<pair<string, string>> template <class T> static inline SWSSFieldValueArray makeFieldValueArray(T &&in) { SWSSFieldValueTuple *data = new SWSSFieldValueTuple[in.size()]; size_t i = 0; for (auto &pair : in) { SWSSFieldValueTuple entry; entry.field = strdup(pair.first.c_str()); entry.value = makeString(std::move(pair.second)); data[i++] = entry; } SWSSFieldValueArray out; out.len = (uint64_t)in.size(); out.data = data; return out; } static inline SWSSKeyOperation makeKeyOperation(std::string &op) { if (strcmp(op.c_str(), SET_COMMAND) == 0) { return SWSSKeyOperation_SET; } else if (strcmp(op.c_str(), DEL_COMMAND) == 0) { return SWSSKeyOperation_DEL; } else { SWSS_LOG_THROW("Invalid key operation %s", op.c_str()); } } static inline SWSSKeyOpFieldValues makeKeyOpFieldValues(swss::KeyOpFieldsValuesTuple &&in) { SWSSKeyOpFieldValues out; out.key = strdup(kfvKey(in).c_str()); out.operation = makeKeyOperation(kfvOp(in)); out.fieldValues = makeFieldValueArray(kfvFieldsValues(in)); return out; } template <class T> static inline T &getReference(T &t) { return t; } template <class T> static inline T &getReference(std::shared_ptr<T> &t) { return *t; } // T is anything that has a .size() method and which can be iterated over for // swss::KeyOpFieldValuesTuple, eg vector or deque template <class T> static inline SWSSKeyOpFieldValuesArray makeKeyOpFieldValuesArray(T &&in) { SWSSKeyOpFieldValues *data = new SWSSKeyOpFieldValues[in.size()]; size_t i = 0; for (auto &kfv : in) data[i++] = makeKeyOpFieldValues(std::move(getReference(kfv))); SWSSKeyOpFieldValuesArray out; out.len = (uint64_t)in.size(); out.data = data; return out; } static inline std::string takeString(SWSSString s) { return std::string(std::move(*((std::string *)s))); } static inline std::string &takeStrRef(SWSSStrRef s) { return *((std::string *)s); } static inline std::vector<swss::FieldValueTuple> takeFieldValueArray(SWSSFieldValueArray in) { std::vector<swss::FieldValueTuple> out; for (uint64_t i = 0; i < in.len; i++) { const char *field = in.data[i].field; SWSSString value = in.data[i].value; auto pair = std::make_pair(std::string(field), takeString(std::move(value))); out.push_back(pair); } return out; } static inline std::string takeKeyOperation(SWSSKeyOperation op) { switch (op) { case SWSSKeyOperation_SET: return SET_COMMAND; case SWSSKeyOperation_DEL: return DEL_COMMAND; default: SWSS_LOG_THROW("Impossible SWSSKeyOperation"); } } static inline swss::KeyOpFieldsValuesTuple takeKeyOpFieldValues(SWSSKeyOpFieldValues in) { std::string key = in.key; std::string op = takeKeyOperation(in.operation); auto fieldValues = takeFieldValueArray(in.fieldValues); return std::make_tuple(key, op, fieldValues); } static inline std::vector<swss::KeyOpFieldsValuesTuple> takeKeyOpFieldValuesArray(SWSSKeyOpFieldValuesArray in) { std::vector<swss::KeyOpFieldsValuesTuple> out; for (uint64_t i = 0; i < in.len; i++) { SWSSKeyOpFieldValues kfv = in.data[i]; out.push_back(takeKeyOpFieldValues(std::move(kfv))); } return out; } } // namespace swss #endif #endif