UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
ipc_frame_unix.cpp
Go to the documentation of this file.
1#include <unistd.h>
2#include <stdlib.h>
3#include <string.h>
4#include <stdio.h>
5#include <array>
6#include <string>
7#include <memory>
8
9#ifndef _WIN32
10#include <sys/types.h>
11#include <sys/time.h>
12#include <sys/socket.h>
13#include <sys/un.h>
14#include <netinet/in.h>
15#define CLOSESOCKET close
16#define INVALID_SOCKET -1
17#define UNLINK unlink
18typedef int fd_t;
19#else
20#include <winsock2.h>
21#include <afunix.h>
22#define CLOSESOCKET closesocket
23#define UNLINK DeleteFileA
24typedef SOCKET fd_t;
25#endif
26
27#include <cerrno>
28#include "ipc_frame_unix.h"
29
30#ifndef MSG_NOSIGNAL
31#define MSG_NOSIGNAL 0
32#endif
33
34namespace{
35struct Wsa_guard{
36 Wsa_guard(){
37#ifdef _WIN32
38 WSAData wsadata;
39 WSAStartup(MAKEWORD(2,2), &wsadata);
40#endif
41 }
42 ~Wsa_guard(){
43#ifdef _WIN32
44 WSACleanup();
45#endif
46 }
47 Wsa_guard& operator=(Wsa_guard&&) = delete; //Make class unmovable and uncopyable
48};
49} //anon namespace
50
51
53 Wsa_guard guard;
56 std::string path;
57};
58
60 auto reader = std::make_unique<Ipc_frame_reader>();
61 reader->path = path;
62 reader->data_fd = INVALID_SOCKET;
63
64 reader->listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
65 if(reader->listen_fd == INVALID_SOCKET){
66 return nullptr;
67 }
68
69 sockaddr_un addr;
70 memset(&addr, 0, sizeof(addr));
71 addr.sun_family = AF_UNIX;
72 strncpy(addr.sun_path, path, sizeof(addr.sun_path));
73 addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
74 UNLINK(path);
75
76 int ret = 0;
77 ret = bind(reader->listen_fd, (const sockaddr *) &addr, sizeof(addr.sun_path));
78 if(ret == -1){
79 CLOSESOCKET(reader->listen_fd);
80 return nullptr;
81 }
82
83 ret = listen(reader->listen_fd, 5);
84 if(ret == -1){
85 CLOSESOCKET(reader->listen_fd);
86 return nullptr;
87 }
88
89 return reader.release();
90}
91
93 if(reader->data_fd != INVALID_SOCKET)
94 CLOSESOCKET(reader->data_fd);
95 if(reader->listen_fd != INVALID_SOCKET)
96 CLOSESOCKET(reader->listen_fd);
97
98 UNLINK(reader->path.c_str());
99
100 delete reader;
101}
102
103static size_t blocking_read(fd_t fd, char *dst, size_t size){
104 size_t bytes_read = 0;
105
106 while(bytes_read < size){
107 int read_now = recv(fd, dst + bytes_read, size - bytes_read, 0);
108 if(read_now <= 0)
109 break;
110
111 bytes_read += read_now;
112 }
113
114 return bytes_read;
115}
116
117static bool socket_read_avail(fd_t fd){
118 if(fd == INVALID_SOCKET)
119 return false;
120
121 fd_set fds;
122 FD_ZERO(&fds);
123 FD_SET(fd, &fds);
124
125 struct timeval tv;
126 tv.tv_sec = 0;
127 tv.tv_usec = 0;
128
129 int ret = select(fd + 1, &fds, nullptr, nullptr, &tv);
130
131 return ret > 0;
132}
133
134static bool try_accept(struct Ipc_frame_reader *reader){
135 if(!socket_read_avail(reader->listen_fd))
136 return false;
137
138 reader->data_fd = accept(reader->listen_fd, nullptr, 0);
139 return true;
140}
141
144 return false;
145
146 return socket_read_avail(reader->data_fd);
147}
148
150 return reader->data_fd != INVALID_SOCKET || try_accept(reader);
151}
152
154 if(reader->data_fd != INVALID_SOCKET)
155 return;
156
157 reader->data_fd = accept(reader->listen_fd, nullptr, 0);
158}
159
160static bool do_frame_read(Ipc_frame_reader *reader, Ipc_frame *dst){
161 char header_buf[IPC_FRAME_HEADER_LEN];
162
164 return false;
165
166 if(!ipc_frame_parse_header(&dst->header, header_buf))
167 return false;
168
169 if(!ipc_frame_reserve(dst, dst->header.data_len))
170 return false;
171
172 int read_data = blocking_read(reader->data_fd, dst->data, dst->header.data_len);
173
174 return read_data == dst->header.data_len;
175}
176
178 bool ret = do_frame_read(reader, dst);
179 if(!ret){
180 CLOSESOCKET(reader->data_fd);
181 reader->data_fd = INVALID_SOCKET;
182 }
183
184 return ret;
185}
186
190
192 auto writer = std::make_unique<Ipc_frame_writer>();
193 writer->data_fd = INVALID_SOCKET;
194
195 sockaddr_un addr;
196 memset(&addr, 0, sizeof(addr));
197 addr.sun_family = AF_UNIX;
198 strncpy(addr.sun_path, path, sizeof(addr.sun_path));
199 addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
200
201 writer->data_fd = socket(AF_UNIX, SOCK_STREAM, 0);
202 if(writer->data_fd == INVALID_SOCKET){
203 perror("ipc_frame_writer_new socket");
204 return nullptr;
205 }
206
207 int ret = connect(writer->data_fd, (const struct sockaddr *) &addr, sizeof(addr));
208 if(ret == -1){
209 perror("ipc_frame_writer_new connect");
210 CLOSESOCKET(writer->data_fd);
211 return nullptr;
212 }
213
214 return writer.release();
215}
216
218 if(writer->data_fd != INVALID_SOCKET)
219 CLOSESOCKET(writer->data_fd);
220
221 delete writer;
222}
223
224namespace{
225
226void block_write(fd_t fd, void *buf, size_t size){
227 size_t written = 0;
228 char *src = static_cast<char *>(buf);
229
230 while(written < size){
231 int ret = send(fd, src + written, size - written, MSG_NOSIGNAL);
232 if(ret == -1)
233 return;
234 written += ret;
235 }
236}
237
238} //anon namespace
239
241 std::array<char, IPC_FRAME_HEADER_LEN> header;
242
243 ipc_frame_write_header(&f->header, header.data());
244
245 errno = 0;
246 block_write(writer->data_fd, header.data(), header.size());
247 block_write(writer->data_fd, f->data, f->header.data_len);
248
249 return errno == 0;
250}
251
int fd_t
static void * writer(void *arg)
Definition hd-rum.c:129
bool ipc_frame_parse_header(Ipc_frame_header *hdr, const char *buf)
Definition ipc_frame.cpp:31
void ipc_frame_write_header(const struct Ipc_frame_header *hdr, char *dst)
Definition ipc_frame.cpp:40
bool ipc_frame_reserve(Ipc_frame *frame, size_t size)
Definition ipc_frame.cpp:66
#define IPC_FRAME_HEADER_LEN
Definition ipc_frame.h:7
void ipc_frame_reader_wait_connect(struct Ipc_frame_reader *reader)
bool ipc_frame_reader_has_frame(struct Ipc_frame_reader *reader)
bool ipc_frame_writer_write(struct Ipc_frame_writer *writer, const struct Ipc_frame *f)
#define INVALID_SOCKET
void ipc_frame_reader_free(struct Ipc_frame_reader *reader)
Ipc_frame_reader * ipc_frame_reader_new(const char *path)
#define CLOSESOCKET
#define UNLINK
bool ipc_frame_reader_is_connected(struct Ipc_frame_reader *reader)
bool ipc_frame_reader_read(Ipc_frame_reader *reader, Ipc_frame *dst)
static bool do_frame_read(Ipc_frame_reader *reader, Ipc_frame *dst)
#define MSG_NOSIGNAL
static size_t blocking_read(fd_t fd, char *dst, size_t size)
static bool try_accept(struct Ipc_frame_reader *reader)
static bool socket_read_avail(fd_t fd)
void ipc_frame_writer_free(struct Ipc_frame_writer *writer)
Ipc_frame_writer * ipc_frame_writer_new(const char *path)
Ipc_frame_header header
Definition ipc_frame.h:24
char * data
Definition ipc_frame.h:25