1 /* Simulate IO errors after each byte in a stream.
2  * Verifies proper error propagation.
3  */
4 
5 #include <stdio.h>
6 #include <pb_decode.h>
7 #include <pb_encode.h>
8 #include "alltypes.pb.h"
9 #include "test_helpers.h"
10 
11 typedef struct
12 {
13     uint8_t *buffer;
14     size_t fail_after;
15 } faulty_stream_t;
16 
17 bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
18 {
19     faulty_stream_t *state = stream->state;
20 
21     while (count--)
22     {
23         if (state->fail_after == 0)
24             PB_RETURN_ERROR(stream, "simulated");
25         state->fail_after--;
26         *buf++ = *state->buffer++;
27     }
28 
29     return true;
30 }
31 bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
32 {
33     faulty_stream_t *state = stream->state;
34 
35     while (count--)
36     {
37         if (state->fail_after == 0)
38             PB_RETURN_ERROR(stream, "simulated");
39         state->fail_after--;
40         *state->buffer++ = *buf++;
41     }
42 
43     return true;
44 }
45 
46 int main()
47 {
48     uint8_t buffer[2048];
49     size_t msglen;
50     AllTypes msg = AllTypes_init_zero;
51 
52     /* Get some base data to run the tests with */
53     SET_BINARY_MODE(stdin);
54     msglen = fread(buffer, 1, sizeof(buffer), stdin);
55 
56     /* Test IO errors on decoding */
57     {
58         bool status;
59         pb_istream_t stream = {&read_callback, NULL, SIZE_MAX};
60         faulty_stream_t fs;
61         size_t i;
62 
63         for (i = 0; i < msglen; i++)
64         {
65             stream.bytes_left = msglen;
66             stream.state = &fs;
67             fs.buffer = buffer;
68             fs.fail_after = i;
69 
70             status = pb_decode(&stream, AllTypes_fields, &msg);
71             if (status != false)
72             {
73                 fprintf(stderr, "Unexpected success in decode\n");
74                 return 2;
75             }
76             else if (strcmp(stream.errmsg, "simulated") != 0)
77             {
78                 fprintf(stderr, "Wrong error in decode: %s\n", stream.errmsg);
79                 return 3;
80             }
81         }
82 
83         stream.bytes_left = msglen;
84         stream.state = &fs;
85         fs.buffer = buffer;
86         fs.fail_after = msglen;
87         status = pb_decode(&stream, AllTypes_fields, &msg);
88 
89         if (!status)
90         {
91             fprintf(stderr, "Decoding failed: %s\n", stream.errmsg);
92             return 4;
93         }
94     }
95 
96     /* Test IO errors on encoding */
97     {
98         bool status;
99         pb_ostream_t stream = {&write_callback, NULL, SIZE_MAX, 0};
100         faulty_stream_t fs;
101         size_t i;
102 
103         for (i = 0; i < msglen; i++)
104         {
105             stream.max_size = msglen;
106             stream.bytes_written = 0;
107             stream.state = &fs;
108             fs.buffer = buffer;
109             fs.fail_after = i;
110 
111             status = pb_encode(&stream, AllTypes_fields, &msg);
112             if (status != false)
113             {
114                 fprintf(stderr, "Unexpected success in encode\n");
115                 return 5;
116             }
117             else if (strcmp(stream.errmsg, "simulated") != 0)
118             {
119                 fprintf(stderr, "Wrong error in encode: %s\n", stream.errmsg);
120                 return 6;
121             }
122         }
123 
124         stream.max_size = msglen;
125         stream.bytes_written = 0;
126         stream.state = &fs;
127         fs.buffer = buffer;
128         fs.fail_after = msglen;
129         status = pb_encode(&stream, AllTypes_fields, &msg);
130 
131         if (!status)
132         {
133             fprintf(stderr, "Encoding failed: %s\n", stream.errmsg);
134             return 7;
135         }
136     }
137 
138     return 0;
139 }
140 
141