Werner's Miscellanea
Sign in or create your account | Project List | Help
Werner's Miscellanea Git Source Tree
Root/
Source at commit ebb0d2708b542ee20929375d9a22d37d86b100a5 created 10 years 1 month ago. By Werner Almesberger, ircstat/README: change date format from MMYY to YYMM | |
---|---|
1 | /* |
2 | * comm.c - Fakefile IPC functions |
3 | * |
4 | * Copyright 2012 by Werner Almesberger |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | */ |
11 | |
12 | #include <stdint.h> |
13 | #include <stdlib.h> |
14 | #include <stdio.h> |
15 | #include <unistd.h> |
16 | #include <string.h> |
17 | #include <assert.h> |
18 | #include <sys/types.h> |
19 | |
20 | #include "util.h" |
21 | #include "comm.h" |
22 | |
23 | |
24 | #define BUF_SIZE 4096 |
25 | |
26 | |
27 | struct fakefile_peer { |
28 | int in, out; |
29 | uint8_t buf[BUF_SIZE]; |
30 | void *pos; |
31 | const void *end; |
32 | }; |
33 | |
34 | |
35 | struct fakefile_msg { |
36 | struct fakefile_peer *peer; |
37 | void *buf; /* NULL if reading */ |
38 | void *pos; /* current position in buffer; write only */ |
39 | size_t len; /* amount of data read/written so far */ |
40 | size_t msg_size; /* declared size */ |
41 | size_t buf_size; /* allocated size; write only */ |
42 | }; |
43 | |
44 | |
45 | static int master_fd(const char *name) |
46 | { |
47 | const char *s; |
48 | char *end; |
49 | long n; |
50 | |
51 | s = getenv(name); |
52 | if (!s) { |
53 | fprintf(stderr, "%s not set\n", name); |
54 | exit(1); |
55 | } |
56 | n = strtol(s, &end, 0); |
57 | if (*end || n < 0) { |
58 | fprintf(stderr, "invalid fd \"%s\" for %s\n", s, name); |
59 | exit(1); |
60 | } |
61 | return n; |
62 | } |
63 | |
64 | |
65 | static struct fakefile_peer *sanitize_peer(struct fakefile_peer *peer) |
66 | { |
67 | static int have_peer = 0; |
68 | static struct fakefile_peer master; |
69 | |
70 | if (peer) |
71 | return peer; |
72 | if (!have_peer) { |
73 | master.in = master_fd(FAKEFILE_MASTER_OUT_VAR); |
74 | master.out = master_fd(FAKEFILE_MASTER_IN_VAR); |
75 | master.pos = master.buf; |
76 | master.end = master.buf; |
77 | have_peer = 1; |
78 | } |
79 | return &master; |
80 | } |
81 | |
82 | |
83 | struct fakefile_peer *fakefile_peer(int in, int out) |
84 | { |
85 | struct fakefile_peer *peer; |
86 | |
87 | peer = alloc_type(struct fakefile_peer); |
88 | peer->in = in; |
89 | peer->out = out; |
90 | peer->pos = peer->buf; |
91 | peer->end = peer->buf; |
92 | return peer; |
93 | } |
94 | |
95 | |
96 | void fakefile_peer_close(struct fakefile_peer *peer) |
97 | { |
98 | (void) close(peer->in); |
99 | (void) close(peer->out); |
100 | free(peer); |
101 | } |
102 | |
103 | |
104 | int fakefile_peer_fd(const struct fakefile_peer *peer) |
105 | { |
106 | return peer->in; |
107 | } |
108 | |
109 | |
110 | struct fakefile_msg *fakefile_msg_new(struct fakefile_peer *peer, int size) |
111 | { |
112 | struct fakefile_msg *msg; |
113 | size_t buf_size; |
114 | |
115 | size += sizeof(int); |
116 | buf_size = size > BUF_SIZE ? BUF_SIZE : size; |
117 | msg = alloc_size(sizeof(struct fakefile_msg)+buf_size); |
118 | msg->peer = sanitize_peer(peer); |
119 | msg->buf = msg->pos = msg+1; |
120 | msg->len = 0; |
121 | msg->msg_size = size; |
122 | msg->buf_size = buf_size; |
123 | fakefile_msg_add_int(msg, size); |
124 | return msg; |
125 | } |
126 | |
127 | |
128 | static void flush_out(struct fakefile_msg *msg) |
129 | { |
130 | const void *p; |
131 | ssize_t len; |
132 | |
133 | if (msg->pos == msg->buf) |
134 | return; |
135 | for (p = msg->buf; p != msg->pos; p += len) { |
136 | len = write(msg->peer->out, p, msg->pos-p); |
137 | if (len <= 0) { |
138 | perror("fakefile IPC write"); |
139 | exit(1); |
140 | } |
141 | } |
142 | } |
143 | |
144 | |
145 | struct fakefile_msg *fakefile_msg_recv(struct fakefile_peer *peer) |
146 | { |
147 | struct fakefile_msg *msg; |
148 | |
149 | msg = alloc_type(struct fakefile_msg); |
150 | msg->peer = sanitize_peer(peer); |
151 | msg->buf = NULL; |
152 | msg->len = 0; |
153 | msg->msg_size = sizeof(int); |
154 | msg->msg_size = fakefile_msg_get_int(msg); |
155 | return msg; |
156 | } |
157 | |
158 | |
159 | void fakefile_msg_end(struct fakefile_msg *msg) |
160 | { |
161 | #if 0 |
162 | fprintf(stderr, "end: len %d size %d (%p)\n", |
163 | (int) msg->len, (int) msg->msg_size, msg->buf); |
164 | #endif |
165 | assert(msg->len == msg->msg_size); |
166 | if (msg->buf) |
167 | flush_out(msg); |
168 | free(msg); |
169 | } |
170 | |
171 | |
172 | static void add_chunk(struct fakefile_msg *msg, const void *buf, size_t len) |
173 | { |
174 | memcpy(msg->pos, buf, len); |
175 | msg->pos += len; |
176 | if (msg->pos == msg->buf+msg->buf_size) { |
177 | flush_out(msg); |
178 | msg->pos = msg->buf; |
179 | } |
180 | } |
181 | |
182 | |
183 | void fakefile_msg_add(struct fakefile_msg *msg, const void *buf, size_t len) |
184 | { |
185 | size_t chunk; |
186 | |
187 | #if 0 |
188 | fprintf(stderr, "add: %d+%d/%d (%p)\n", |
189 | (int) msg->len, (int) len, (int) msg->msg_size, msg->buf); |
190 | #endif |
191 | assert(msg->len+len <= msg->msg_size); |
192 | while (len && msg->pos+len > msg->buf+msg->buf_size) { |
193 | chunk = msg->buf+msg->buf_size-msg->pos; |
194 | if (chunk > len) |
195 | chunk = len; |
196 | add_chunk(msg, buf, chunk); |
197 | buf += chunk; |
198 | len -= chunk; |
199 | msg->len += chunk; |
200 | } |
201 | if (len) { |
202 | add_chunk(msg, buf, len); |
203 | msg->len += len; |
204 | } |
205 | } |
206 | |
207 | |
208 | static size_t get_chunk(struct fakefile_peer *peer, void *buf, size_t len) |
209 | { |
210 | ssize_t got; |
211 | |
212 | got = read(peer->in, buf, len); |
213 | if (got < 0) { |
214 | perror("fakefile IPC read"); |
215 | exit(1); |
216 | } |
217 | if (!got) { |
218 | fprintf(stderr, "fakefile EOF\n"); |
219 | exit(1); |
220 | } |
221 | return got; |
222 | } |
223 | |
224 | |
225 | void fakefile_msg_get(struct fakefile_msg *msg, void *buf, size_t len) |
226 | { |
227 | struct fakefile_peer *peer = msg->peer; |
228 | size_t chunk, got; |
229 | |
230 | assert(msg->len+len <= msg->msg_size); |
231 | if (!len) |
232 | return; |
233 | if (peer->pos != peer->end) { |
234 | chunk = peer->end-peer->pos; |
235 | if (chunk > len) |
236 | chunk = len; |
237 | memcpy(buf, peer->pos, chunk); |
238 | peer->pos += chunk; |
239 | buf += chunk; |
240 | len -= chunk; |
241 | msg->len += chunk; |
242 | } |
243 | while (len >= BUF_SIZE) { |
244 | got = get_chunk(peer, buf, BUF_SIZE); |
245 | buf += got; |
246 | len -= got; |
247 | msg->len += got; |
248 | } |
249 | if (!len) |
250 | return; |
251 | peer->pos = peer->buf; |
252 | peer->end = peer->buf+get_chunk(peer, peer->buf, BUF_SIZE); |
253 | fakefile_msg_get(msg, buf, len); |
254 | } |
255 |
Branches:
master