├── .gitignore ├── clean-dir ├── samples ├── msg-server.c ├── hello.c └── msg-client.c ├── LICENSE ├── README.md ├── CMakeLists.txt ├── ipc.h └── ipc.c /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles/ 3 | Makefile 4 | cmake_install.cmake 5 | libipc.a 6 | libipc.so 7 | sample-client 8 | sample-server 9 | sample-hello 10 | -------------------------------------------------------------------------------- /clean-dir: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make clean 4 | rm -rf ./CMakeFiles 5 | rm -rf ./CMakeCache.txt 6 | rm -rf ./Makefile 7 | rm -rf ./cmake_install.cmake 8 | rm -rf ./compile_commands.json 9 | rm -rf ./*out* 10 | rm -rf ./ex 11 | -------------------------------------------------------------------------------- /samples/msg-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | printf("\n[Server] - Started\n"); 8 | 9 | int ch = ipc_create_channel("./ex", ipcSock, ipcMessage, ipcNonblock); 10 | int i; 11 | for (i = 0; i < 50; i++) 12 | { 13 | printf("[Server] - %d [%s]\n", i, ipc_read_message(ch)); 14 | sleep(3); 15 | ipc_write_message(ch, "responce"); 16 | } 17 | ipc_close_channel(ch); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /samples/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct person 5 | { 6 | char name[128]; 7 | char address[256]; 8 | int isMarried; 9 | }; 10 | 11 | static struct person adam = { "Adam Smith", "Current address is unknown", 1 }; 12 | static const char* CH_NAME = "ch_hello"; 13 | 14 | int main() 15 | { 16 | struct person got_person; 17 | 18 | printf("IPC Hello World\n"); 19 | 20 | int ch_consumer = ipc_create_channel(CH_NAME, ipcFifo, ipcObject, ipcBlock); 21 | int ch_producer = ipc_connect_channel(CH_NAME, ipcFifo, ipcObject, ipcNonblock); 22 | 23 | ipc_write_object(ch_producer, &adam, sizeof(struct person)); 24 | 25 | ipc_read_object(ch_consumer, &got_person, sizeof(struct person)); 26 | printf("From channel[%s] got person[%s] with address[%s] is married[%d]\n", CH_NAME, got_person.name, got_person.address, got_person.isMarried); 27 | 28 | ipc_close_channel(ch_producer); 29 | ipc_close_channel(ch_consumer); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /samples/msg-client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | printf("\n[Client] - Started\n"); 8 | 9 | int ch = ipc_connect_channel("./ex", ipcSock, ipcMessage, ipcBlock); 10 | if (ch < 0) 11 | { 12 | printf("[Client] - Error, could not connect to the channel `ex` [%d]\n", ch); 13 | } else 14 | { 15 | int i = 0; 16 | int written = 0; 17 | for (i = 0; i < 5; i++) 18 | { 19 | char buf[1024]; 20 | snprintf(buf, 1024, "===client=test[%d]===", i); 21 | written = ipc_write_message(ch, buf); 22 | if ( written < 0) 23 | { 24 | printf("[Client] - Error at iter[%d] written[%d]\n", i, written); 25 | break; 26 | } else 27 | printf("[Client] - Msg send[%d]\n", i); 28 | sleep(1); 29 | printf("[Client] - Got back [%s]\n", ipc_read_message(ch)); 30 | sleep(1); 31 | } 32 | printf("[Client] - Done[%d] times for client\n", i); 33 | ipc_close_channel(ch); 34 | } 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2016, Dimonija - dimonija@gmail.com 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libipc ver. 0.0.8 2 | Simple lightweight and productive zero-copy IPC library. Written on pure C, based on Unix Named Pipes and Unix Domain Sockets. Library is intended to exchange text messages and structures/objects between processes 3 | 4 | # Transport 5 | * Unix Named pipes: One-to-many unidirectional channel. Server side creates a channel and could receive messages from multiple clients through it. Other side connects to a channel and send messages. You also able to create object channel that allow you to send/receive structures and other objects 6 | * Unix Domain Sockets: One-to-one biderectional channel. Server process requests from one client at a time. 7 | 8 | # Features 9 | * Fast: 10K messages (~250K of data) written for 0.009s on i5-4250U CPU 10 | * Lite: 12k .so size 11 | * Zero-copy: No overhead over Unix transport, no memcpy() / strcpy() performed for your provided object / message buffer 12 | * No messages are dropped on overflow: if you receive a success from ipc_write_message() you guaranteed that consumer could receive the message by ipc_read_message() 13 | 14 | # Configure as shared library: 15 | cmake . 16 | 17 | # Configure as static library: 18 | cmake . -DBUILD_SHARED_LIBS=OFF 19 | 20 | # Configure with debug info: 21 | cmake . -DCMAKE_BUILD_TYPE=Debug 22 | 23 | # Compile library: 24 | cmake --build . 25 | 26 | # Compile library and samples: 27 | cmake --build . --target samples 28 | 29 | # Run client/server samples: 30 | > ./sample-server & 31 | > ./sample-client 32 | 33 | # Run hello sample 34 | > ./sample-hello 35 | 36 | # Limitations 37 | * Communication within single machine only 38 | * Maximum number of channels - 128 39 | * Maximum not consumed data could remain in a channel - 64Kb (if you try to produce more messages, but 64k is not consumed, ipc_write_message() will return an error) 40 | * Multi-thread - ipc_create_channel(), ipc_connect_channel() and ipc_close_channel() must be protected by mutexes 41 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project (libipc-project C) 3 | 4 | if(POLICY CMP0065) 5 | cmake_policy(SET CMP0065 NEW) 6 | endif() 7 | 8 | option(BUILD_SHARED_LIBS "Default build library as shared" ON) 9 | if (NOT CMAKE_BUILD_TYPE) 10 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Set Release as default build type" FORCE) 11 | endif() 12 | 13 | message(STATUS "------------------------------------------------------------------------------------") 14 | message(STATUS "Project name (PROJECT_NAME) : " ${PROJECT_NAME}) 15 | message(STATUS "Project dir (PROJECT_SOURCE_DIR) : " ${PROJECT_SOURCE_DIR}) 16 | message(STATUS "Build type (CMAKE_BUILD_TYPE) : " ${CMAKE_BUILD_TYPE}) 17 | message(STATUS "Build shared (BUILD_SHARED_LIBS) : " ${BUILD_SHARED_LIBS}) 18 | message(STATUS "Install prefix (CMAKE_INSTALL_PREFIX) : " ${CMAKE_INSTALL_PREFIX}) 19 | message(STATUS "Install lib (CMAKE_INSTALL_LIBDIR) : " ${CMAKE_INSTALL_LIBDIR}) 20 | message(STATUS "Install include (CMAKE_INSTALL_INCLUDEDIR) : " ${CMAKE_INSTALL_INCLUDEDIR}) 21 | message(STATUS "------------------------------------------------------------------------------------") 22 | 23 | # Sources 24 | file(GLOB sources ipc*.c) 25 | file(GLOB headers ipc.h) 26 | file(GLOB sample-server-src samples/msg-server.c) 27 | file(GLOB sample-client-src samples/msg-client.c) 28 | file(GLOB sample-hello-src samples/hello.c) 29 | 30 | # Targets 31 | add_library(ipc ${sources}) 32 | add_custom_target(samples) 33 | add_executable(sample-server EXCLUDE_FROM_ALL ${sample-server-src}) 34 | add_executable(sample-client EXCLUDE_FROM_ALL ${sample-client-src}) 35 | add_executable(sample-hello EXCLUDE_FROM_ALL ${sample-hello-src}) 36 | add_dependencies(samples sample-server sample-client sample-hello ipc) 37 | 38 | # Options 39 | # Additional: -march=core-avx2 -mtune=core-avx2 40 | set(_COMPILE_OPT -pipe -ftree-vectorize -ffast-math -flto -Wall -Wextra -Wpedantic) 41 | set(_LINK_OPT "-flto -fuse-ld=gold") 42 | set(_COMPILE_DEF -D_POSIX_C_SOURCE=199309L) 43 | 44 | if (CMAKE_BUILD_TYPE EQUAL "Debug") 45 | set(_COMPILE_OPT ${_COMPILE_OPT} -g) 46 | set(_LINK_OPT "${_LINK_OPT} -g") 47 | endif() 48 | 49 | # ipc 50 | set_target_properties(ipc PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON C_EXTENSIONS OFF) 51 | target_compile_options(ipc PRIVATE ${_COMPILE_OPT}) 52 | set_target_properties(ipc PROPERTIES LINK_FLAGS ${_LINK_OPT}) 53 | set_target_properties(ipc PROPERTIES PUBLIC_HEADER ${headers}) 54 | target_compile_definitions(ipc PRIVATE ${_COMPILE_DEF}) 55 | target_include_directories(ipc PUBLIC $) 56 | 57 | # sample-server 58 | set_target_properties(sample-server PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON C_EXTENSIONS OFF) 59 | target_compile_options(sample-server PRIVATE ${_COMPILE_OPT}) 60 | set_target_properties(sample-server PROPERTIES LINK_FLAGS ${_LINK_OPT}) 61 | target_compile_definitions(sample-server PRIVATE ${_COMPILE_DEF}) 62 | target_link_libraries(sample-server ipc) 63 | 64 | # sample-client 65 | set_target_properties(sample-client PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON C_EXTENSIONS OFF) 66 | target_compile_options(sample-client PRIVATE ${_COMPILE_OPT}) 67 | set_target_properties(sample-client PROPERTIES LINK_FLAGS ${_LINK_OPT}) 68 | target_compile_definitions(sample-client PRIVATE ${_COMPILE_DEF}) 69 | target_link_libraries(sample-client ipc) 70 | 71 | # sample-hello 72 | set_target_properties(sample-hello PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON C_EXTENSIONS OFF) 73 | target_compile_options(sample-hello PRIVATE ${_COMPILE_OPT}) 74 | set_target_properties(sample-hello PROPERTIES LINK_FLAGS ${_LINK_OPT}) 75 | target_compile_definitions(sample-hello PRIVATE ${_COMPILE_DEF}) 76 | target_link_libraries(sample-hello ipc) 77 | 78 | # Install 79 | install(TARGETS ipc LIBRARY) 80 | install(TARGETS ipc PUBLIC_HEADER) 81 | -------------------------------------------------------------------------------- /ipc.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_IPC_H_ 2 | #define _LIB_IPC_H_ 3 | 4 | 5 | // === IPC error codes ========================================================= 6 | 7 | /** No free channels are available */ 8 | #define IPC_NOFREE -101 9 | 10 | /** Not valid descriptor */ 11 | #define IPC_DSCERR -102 12 | 13 | /** Incorrect object size */ 14 | #define IPC_OBJERR -103 15 | 16 | /** Incorrect channel type */ 17 | #define IPC_TYPEERR -104 18 | 19 | /** Incorrect or closed socket */ 20 | #define IPC_SOCKERR -105 21 | 22 | 23 | // === Public types ============================================================ 24 | 25 | /** 26 | * Channel transport type 27 | */ 28 | enum ipc_transport 29 | { 30 | ipcFifo = 1, /**< Unix Named Pipes: Unidirectional transport, many client could send to one server */ 31 | ipcSock = 2 /**< Unix Domain Sockets: Bidirectional transport, one client at a time to one server */ 32 | }; 33 | 34 | /** 35 | * Channel message type 36 | */ 37 | enum ipc_msg 38 | { 39 | ipcFree = 0, /**< No message type, free channel */ 40 | ipcMessage = 1, /**< Channel exchanges with null terminated messages */ 41 | ipcObject = 2 /**< Channel exchanges with objects/structures */ 42 | }; 43 | 44 | /** 45 | * Channel blocking mode 46 | */ 47 | enum ipc_block 48 | { 49 | ipcBlock = 1, /**< Synchronous read/write to channel */ 50 | ipcNonblock = 2 /**< Asynchronous read/write to channel */ 51 | }; 52 | 53 | 54 | // === Public API ============================================================== 55 | 56 | /** @brief Create new listening channel 57 | * 58 | * @param chName Channel name 59 | * @param transportType Channel transport 60 | * @param msgType Channel message type (message or object) 61 | * @param blockMode Channel blocking mode for read/write operation 62 | * 63 | * @return non-negative - channel descriptor; negative - IPC error code or negative errno 64 | */ 65 | extern int ipc_create_channel(const char* chName, enum ipc_transport transportType, enum ipc_msg msgType, enum ipc_block blockMode); 66 | 67 | /** @brief Connects to existing channel 68 | * 69 | * Channel must be created with ipc_create_channel() on another side. 70 | * 71 | * @param chName Channel name 72 | * @param transportType Channel transport 73 | * @param msgType Channel message type (must be same as passed to ipc_create_channel()) 74 | * @param blockMode Channel blocking mode for read/write operation 75 | * 76 | * @return non-negative - channel descriptor; negative - IPC error code or negative errno 77 | */ 78 | extern int ipc_connect_channel(const char* chName, enum ipc_transport transportType, enum ipc_msg msgType, enum ipc_block blockMode); 79 | 80 | /** @brief Close created or connected channel 81 | * 82 | * @param chId Channel descriptor from ipc_create_channel() or ipc_connect_channel() 83 | * 84 | * @return zero - channel closed; negative - IPC error code 85 | */ 86 | extern int ipc_close_channel(int chId); 87 | 88 | /** @brief Write message to the channel 89 | * 90 | * @param chId Channel descriptor 91 | * @param msgText Text message 92 | * 93 | * @return non-negative - number of bytes written; negative - IPC error code or negative errno 94 | */ 95 | extern int ipc_write_message(int chId, const char* msgText); 96 | 97 | /** @brief Read message from the channel 98 | * 99 | * @param chId Channel descriptor 100 | * 101 | * @return non-null - message; null - no message for non-blocking operation or error 102 | */ 103 | extern const char* ipc_read_message(int chId); 104 | 105 | /** @brief Write object to the channel 106 | * 107 | * @param chId Channel descriptor 108 | * @param obj Pointer to object to be written 109 | * @param objSize Size of object 110 | * 111 | * @return non-negative - number of bytes written; negative - IPC error code or negative errno 112 | */ 113 | extern int ipc_write_object(int chId, const void* obj, int objSize); 114 | 115 | /** @brief Read object from the channel 116 | * 117 | * @param chId Channel descriptor 118 | * @param obj Pointer to object to read to 119 | * @param objSize Size of object 120 | * 121 | * @return positive - ok; negative - IPC error code or negative errno 122 | */ 123 | extern int ipc_read_object(int chId, void* obj, int objSize); 124 | 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /ipc.c: -------------------------------------------------------------------------------- 1 | #include // fcntl() 2 | #include // read() / write() 3 | #include // mkfifo() 4 | #include // strncpy() / strlen() 5 | #include // malloc() / free() 6 | #include // socket() / bind() / listen() / connect() / send() 7 | #include // sockaddr_un 8 | #include // errno 9 | 10 | #include "ipc.h" 11 | 12 | 13 | // === Private defines ========================================================= 14 | 15 | #define MSG_BUFF_SIZE (64 * 1024) 16 | #define MAX_CHANNELS 128 17 | #define MAX_LISTENERS 1 18 | 19 | 20 | // === Internal channel structure ============================================== 21 | 22 | struct ipc_channel 23 | { 24 | char* mName; 25 | int mCreated; 26 | int mFileHdl; 27 | int mListener; 28 | char* mMsgBuff; 29 | int mMsgBuffSize; 30 | char* mMsgBuffPtr; 31 | enum ipc_msg mMsgType; 32 | enum ipc_transport mTransport; 33 | enum ipc_block mBlock; 34 | }; 35 | 36 | static struct ipc_channel g_channels[MAX_CHANNELS]; 37 | 38 | 39 | // === Private functions ======================================================= 40 | 41 | static int _find_free_channel() 42 | { 43 | int result = -1; 44 | int i; 45 | for (i = 0; i < MAX_CHANNELS; i++) 46 | { 47 | if (g_channels[i].mMsgType == ipcFree) 48 | { 49 | result = i; 50 | break; 51 | } 52 | } 53 | 54 | return result; 55 | } 56 | 57 | static const char *_message_from_buff(struct ipc_channel *ch) 58 | { 59 | char *result = NULL; 60 | 61 | if ((ch->mMsgBuffSize > 0) && (ch->mMsgBuffPtr) && (ch->mMsgBuffPtr < (ch->mMsgBuff + ch->mMsgBuffSize))) 62 | { 63 | result = ch->mMsgBuffPtr; 64 | ch->mMsgBuffPtr = strchr(ch->mMsgBuffPtr, 0); 65 | if (ch->mMsgBuffPtr) 66 | ch->mMsgBuffPtr++; 67 | } 68 | 69 | return result; 70 | } 71 | 72 | static void _sock_set_block_mode(int fd, enum ipc_block blockMode) 73 | { 74 | int flags = fcntl(fd, F_GETFL, 0); 75 | flags = (blockMode == ipcBlock) ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); 76 | fcntl(fd, F_SETFL, flags); 77 | } 78 | 79 | static int _read_transport(struct ipc_channel *ch, void *buffer, size_t size) 80 | { 81 | int result = IPC_SOCKERR; 82 | 83 | if ((ch->mTransport == ipcSock) && (ch->mFileHdl == -1)) 84 | { 85 | ch->mFileHdl = accept(ch->mListener, NULL, NULL); 86 | _sock_set_block_mode(ch->mFileHdl, ch->mBlock); 87 | } 88 | 89 | if (ch->mFileHdl != -1) 90 | { 91 | result = read(ch->mFileHdl, buffer, size); 92 | 93 | if (result == 0) 94 | { 95 | result = IPC_SOCKERR; 96 | close(ch->mFileHdl); 97 | ch->mFileHdl = -1; 98 | } else if (result == -1) 99 | result = -errno; 100 | } 101 | 102 | return result; 103 | } 104 | 105 | static int _open_sock(const char* chName, enum ipc_msg msgType, int createMode, enum ipc_block blockMode) 106 | { 107 | int ch_id, fd, name_len; 108 | struct sockaddr_un addr; 109 | struct ipc_channel *ch = NULL; 110 | int result = IPC_NOFREE; 111 | 112 | ch_id = _find_free_channel(); 113 | if (ch_id >= 0) 114 | { 115 | ch = &g_channels[ch_id]; 116 | fd = socket(PF_LOCAL, SOCK_STREAM, 0); 117 | 118 | if (fd != -1) 119 | { 120 | name_len = strlen(chName); 121 | memset(&addr, 0, sizeof(addr)); 122 | addr.sun_family = AF_LOCAL; 123 | strncpy(addr.sun_path, chName, 107); 124 | 125 | if (createMode) 126 | { 127 | unlink(chName); 128 | result = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); 129 | if (result == 0) 130 | result = listen(fd, MAX_LISTENERS); 131 | } 132 | else 133 | result = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); 134 | 135 | if (result == 0) 136 | { 137 | _sock_set_block_mode(fd, blockMode); 138 | 139 | ch->mName = malloc(name_len); 140 | strncpy(ch->mName, chName, name_len); 141 | ch->mMsgBuff = malloc(MSG_BUFF_SIZE + 64); 142 | ch->mCreated = createMode; 143 | if (createMode) 144 | ch->mFileHdl = -1; 145 | else 146 | ch->mFileHdl = fd; 147 | ch->mListener = fd; 148 | ch->mMsgType = msgType; 149 | ch->mTransport = ipcSock; 150 | ch->mBlock = blockMode; 151 | result = ch_id; 152 | } else 153 | result = -errno; 154 | } else 155 | result = -errno; 156 | } 157 | 158 | return result; 159 | } 160 | 161 | static int _open_fifo(const char* chName, enum ipc_msg msgType, int createMode, enum ipc_block blockMode) 162 | { 163 | int ch_id; 164 | int flags = 0; 165 | int result = IPC_NOFREE; 166 | struct ipc_channel *ch = NULL; 167 | int name_len = 0; 168 | int is_nonblock = 0; 169 | 170 | ch_id = _find_free_channel(); 171 | if (ch_id >= 0) 172 | { 173 | ch = &g_channels[ch_id]; 174 | 175 | if (blockMode == ipcNonblock) 176 | is_nonblock = O_NONBLOCK; 177 | 178 | if (createMode) 179 | { 180 | unlink(chName); 181 | mkfifo(chName, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 182 | flags = O_RDWR; 183 | } else 184 | flags = O_WRONLY; 185 | 186 | result = open(chName, flags | is_nonblock); 187 | 188 | if (result != -1) 189 | { 190 | name_len = strlen(chName); 191 | ch->mName = malloc(name_len); 192 | if ((msgType == ipcMessage) && (createMode)) 193 | ch->mMsgBuff = malloc(MSG_BUFF_SIZE + 64); 194 | else 195 | ch->mMsgBuff = NULL; 196 | strncpy(ch->mName, chName, name_len); 197 | ch->mCreated = createMode; 198 | ch->mFileHdl = result; 199 | ch->mListener = -1; 200 | ch->mMsgType = msgType; 201 | ch->mTransport = ipcFifo; 202 | ch->mBlock = blockMode; 203 | result = ch_id; 204 | } else 205 | result = -errno; 206 | } 207 | 208 | return result; 209 | } 210 | 211 | static int _write_object(int chId, const void* obj, int objSize, enum ipc_msg msgType) 212 | { 213 | int result = IPC_DSCERR; 214 | 215 | if (chId >= 0) 216 | { 217 | struct ipc_channel *ch = &g_channels[chId]; 218 | result = IPC_TYPEERR; 219 | 220 | if (ch->mMsgType == msgType) 221 | { 222 | result = IPC_SOCKERR; 223 | if (ch->mFileHdl != -1) 224 | { 225 | if (ch->mTransport == ipcSock) 226 | result = send(ch->mFileHdl, obj, objSize, MSG_NOSIGNAL); 227 | else 228 | result = write(ch->mFileHdl, obj, objSize); 229 | 230 | if (result == -1) 231 | { 232 | result = -errno; 233 | if (result == -EPIPE) 234 | { 235 | result = IPC_SOCKERR; 236 | close(ch->mFileHdl); 237 | ch->mFileHdl = -1; 238 | } 239 | } 240 | } 241 | } 242 | } 243 | 244 | return result; 245 | } 246 | 247 | 248 | // === Public functions ======================================================== 249 | 250 | int ipc_create_channel(const char* chName, enum ipc_transport transportType, enum ipc_msg msgType, enum ipc_block blockMode) 251 | { 252 | const int CREATE_MODE = 1; 253 | 254 | if (transportType == ipcFifo) 255 | return _open_fifo(chName, msgType, CREATE_MODE, blockMode); 256 | else 257 | return _open_sock(chName, msgType, CREATE_MODE, blockMode); 258 | } 259 | 260 | int ipc_connect_channel(const char* chName, enum ipc_transport transportType, enum ipc_msg msgType, enum ipc_block blockMode) 261 | { 262 | const int OPEN_MODE = 0; 263 | 264 | if (transportType == ipcFifo) 265 | return _open_fifo(chName, msgType, OPEN_MODE, blockMode); 266 | else 267 | return _open_sock(chName, msgType, OPEN_MODE, blockMode); 268 | } 269 | 270 | int ipc_close_channel(int chId) 271 | { 272 | int result = IPC_DSCERR; 273 | 274 | if (chId >= 0) 275 | { 276 | result = 0; 277 | struct ipc_channel *ch = &g_channels[chId]; 278 | 279 | if (ch->mMsgType != ipcFree) 280 | { 281 | if (ch->mFileHdl != -1) 282 | close(ch->mFileHdl); 283 | if (ch->mCreated) 284 | unlink(ch->mName); 285 | if (ch->mListener != -1) 286 | close(ch->mListener); 287 | free(ch->mName); 288 | free(ch->mMsgBuff); 289 | ch->mFileHdl = -1; 290 | ch->mListener = -1; 291 | ch->mMsgType = ipcFree; 292 | } 293 | ch->mName = NULL; 294 | ch->mMsgBuff = NULL; 295 | ch->mMsgBuffPtr = NULL; 296 | } 297 | 298 | return result; 299 | } 300 | 301 | int ipc_write_message(int chId, const char* msgText) 302 | { 303 | return _write_object(chId, msgText, strlen(msgText) + 1, ipcMessage); 304 | } 305 | 306 | const char* ipc_read_message(int chId) 307 | { 308 | const char *result = NULL; 309 | 310 | if (chId >= 0) 311 | { 312 | struct ipc_channel *ch = &g_channels[chId]; 313 | 314 | if (ch->mMsgType == ipcMessage) 315 | { 316 | result = _message_from_buff(ch); 317 | if (!result) 318 | { 319 | ch->mMsgBuffSize = _read_transport(ch, ch->mMsgBuff, MSG_BUFF_SIZE); 320 | 321 | if (ch->mMsgBuffSize > 0) 322 | { 323 | ch->mMsgBuffPtr = ch->mMsgBuff; 324 | ch->mMsgBuff[ch->mMsgBuffSize] = '\0'; 325 | result = _message_from_buff(ch); 326 | } 327 | } 328 | } 329 | } 330 | 331 | return result; 332 | } 333 | 334 | int ipc_write_object(int chId, const void* obj, int objSize) 335 | { 336 | return _write_object(chId, obj, objSize, ipcObject); 337 | } 338 | 339 | int ipc_read_object(int chId, void* obj, int objSize) 340 | { 341 | int result = IPC_DSCERR; 342 | 343 | if (chId >= 0) 344 | { 345 | struct ipc_channel *ch = &g_channels[chId]; 346 | 347 | result = IPC_TYPEERR; 348 | if (ch->mMsgType == ipcObject) 349 | { 350 | result = _read_transport(ch, obj, objSize); 351 | 352 | if ((result > 0) && (objSize != result)) 353 | result = IPC_OBJERR; 354 | } 355 | } 356 | 357 | return result; 358 | } 359 | --------------------------------------------------------------------------------