]>
Commit | Line | Data |
---|---|---|
92658f56 PR |
1 | #include <errno.h> |
2 | #include <stdio.h> | |
3 | #include <malloc.h> | |
4 | #include <string.h> | |
6e4e3082 | 5 | #include <unistd.h> |
aac236f4 | 6 | #include <assert.h> |
4fcbeed6 | 7 | #include "daemon-shared.h" |
92658f56 PR |
8 | |
9 | /* | |
10 | * Read a single message from a (socket) filedescriptor. Messages are delimited | |
11 | * by blank lines. This call will block until all of a message is received. The | |
12 | * memory will be allocated from heap. Upon error, all memory is freed and the | |
13 | * buffer pointer is set to NULL. | |
4fcbeed6 PR |
14 | * |
15 | * See also write_buffer about blocking (read_buffer has identical behaviour). | |
92658f56 PR |
16 | */ |
17 | int read_buffer(int fd, char **buffer) { | |
18 | int bytes = 0; | |
19 | int buffersize = 32; | |
6d404585 | 20 | char *new; |
92658f56 PR |
21 | *buffer = malloc(buffersize + 1); |
22 | ||
23 | while (1) { | |
24 | int result = read(fd, (*buffer) + bytes, buffersize - bytes); | |
25 | if (result > 0) | |
26 | bytes += result; | |
98b4241b PR |
27 | if (result == 0) { |
28 | errno = ECONNRESET; | |
92658f56 | 29 | goto fail; /* we should never encounter EOF here */ |
98b4241b | 30 | } |
92658f56 PR |
31 | if (result < 0 && errno != EAGAIN && errno != EWOULDBLOCK) |
32 | goto fail; | |
33 | ||
98b4241b | 34 | if (!strncmp((*buffer) + bytes - 4, "\n##\n", 4)) { |
3556560b PR |
35 | *(*buffer + bytes - 4) = 0; |
36 | break; /* success, we have the full message now */ | |
37 | } | |
38 | ||
92658f56 PR |
39 | if (bytes == buffersize) { |
40 | buffersize += 1024; | |
6d404585 | 41 | if (!(new = realloc(*buffer, buffersize + 1))) |
92658f56 | 42 | goto fail; |
6d404585 ZK |
43 | |
44 | *buffer = new; | |
92658f56 | 45 | } |
3556560b | 46 | /* TODO call select here if we encountered EAGAIN/EWOULDBLOCK */ |
92658f56 PR |
47 | } |
48 | return 1; | |
49 | fail: | |
50 | free(*buffer); | |
51 | *buffer = NULL; | |
52 | return 0; | |
53 | } | |
54 | ||
55 | /* | |
56 | * Write a buffer to a filedescriptor. Keep trying. Blocks (even on | |
57 | * SOCK_NONBLOCK) until all of the write went through. | |
58 | * | |
59 | * TODO use select on EWOULDBLOCK/EAGAIN to avoid useless spinning | |
60 | */ | |
f43c89bf | 61 | int write_buffer(int fd, const char *buffer, int length) { |
a16915cb | 62 | static const char terminate[] = "\n##\n"; |
f43c89bf | 63 | int done = 0; |
92658f56 | 64 | int written = 0; |
f43c89bf | 65 | write: |
92658f56 PR |
66 | while (1) { |
67 | int result = write(fd, buffer + written, length - written); | |
68 | if (result > 0) | |
69 | written += result; | |
70 | if (result < 0 && errno != EWOULDBLOCK && errno != EAGAIN) | |
f43c89bf PR |
71 | return 0; /* too bad */ |
72 | if (written == length) { | |
73 | if (done) | |
74 | return 1; | |
75 | else | |
76 | break; /* done */ | |
77 | } | |
92658f56 | 78 | } |
a16915cb | 79 | |
f43c89bf PR |
80 | buffer = terminate; |
81 | length = 4; | |
82 | written = 0; | |
83 | done = 1; | |
84 | goto write; | |
92658f56 | 85 | } |
4fcbeed6 | 86 | |
14e01287 | 87 | char *format_buffer(const char *what, const char *id, va_list ap) |
4fcbeed6 PR |
88 | { |
89 | char *buffer, *old; | |
90 | char *next; | |
aac236f4 | 91 | int keylen; |
4fcbeed6 | 92 | |
14e01287 | 93 | dm_asprintf(&buffer, "%s = \"%s\"\n", what, id); |
4fcbeed6 PR |
94 | if (!buffer) goto fail; |
95 | ||
6e4e3082 | 96 | while ((next = va_arg(ap, char *))) { |
4fcbeed6 | 97 | old = buffer; |
aac236f4 PR |
98 | assert(strchr(next, '=')); |
99 | keylen = strchr(next, '=') - next; | |
100 | if (strstr(next, "%d")) { | |
101 | int value = va_arg(ap, int); | |
102 | dm_asprintf(&buffer, "%s%.*s= %d\n", buffer, keylen, next, value); | |
103 | dm_free(old); | |
104 | } else if (strstr(next, "%s")) { | |
105 | char *value = va_arg(ap, char *); | |
106 | dm_asprintf(&buffer, "%s%.*s= \"%s\"\n", buffer, keylen, next, value); | |
107 | dm_free(old); | |
108 | } else if (strstr(next, "%b")) { | |
109 | char *block = va_arg(ap, char *); | |
110 | if (!block) | |
111 | continue; | |
112 | dm_asprintf(&buffer, "%s%.*s%s", buffer, keylen, next, block); | |
4fcbeed6 | 113 | dm_free(old); |
4fcbeed6 PR |
114 | } else { |
115 | dm_asprintf(&buffer, "%s%s", buffer, next); | |
116 | dm_free(old); | |
4fcbeed6 | 117 | } |
aac236f4 | 118 | if (!buffer) goto fail; |
4fcbeed6 PR |
119 | } |
120 | ||
4fcbeed6 PR |
121 | return buffer; |
122 | fail: | |
123 | dm_free(buffer); | |
124 | return NULL; | |
125 | } |