Introduce function write_buffer_to_file
[netsum.git] / buffer.c
1 /*
2  * This file is part of netsum.
3  *
4  * Copyright (C) 2014 Simon Guinot <simon.guinot@sequanux.org>
5  *
6  * netsum 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 3 of the License, or
9  * (at your option) any later version.
10  *
11  * netsum is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with netsum.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #define _GNU_SOURCE
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdbool.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <linux/limits.h>
30
31 #include "netsum.h"
32 #include "crc32/crc32.h"
33 #include "buffer.h"
34
35 int write_buffer_to_file(const char *fname, unsigned char *buff, size_t size)
36 {
37         int fd;
38         int retry;
39         int ret;
40         char fpath[PATH_MAX];
41         char *curr_dir;
42
43         curr_dir = get_current_dir_name();
44         if (curr_dir == NULL) {
45                 fprintf(stderr, "get_current_dir_name() %s failed\n",
46                 strerror(errno));
47                 return -1;
48         }
49         snprintf(fpath, sizeof(fpath), "%s/%s", curr_dir, fname);
50         free(curr_dir);
51
52         fd = open(fpath, O_CREAT|O_TRUNC|O_WRONLY, 0644);
53         if (fd == -1) {
54                 fprintf(stderr, "open() %s failed: %s\n", fpath,
55                         strerror(errno));
56                 return -1;
57         }
58
59         retry = 0;
60         while (size && (retry < 3)) {
61                 ret = write(fd, buff, size);
62                 if (ret == -1) {
63                         if (errno == EAGAIN || errno == EINTR) {
64                                 retry++;
65                                 continue;
66                         }
67                         fprintf(stderr, "write() %s failed: %s\n",
68                                 fpath, strerror(errno));
69                         return -1;
70                 }
71                 buff += ret;
72                 size -= ret;
73         }
74
75         ret = close(fd);
76         if (ret == -1) {
77                 fprintf(stderr, "close() %s failed: %s\n", fpath,
78                         strerror(errno));
79                 return -1;
80         }
81
82         return 0;
83 }
84
85 void dump_buffer(unsigned char *buff, int size)
86 {
87         int i;
88
89         fprintf(stderr, "Buffer (%d bytes):\n", size);
90         for (i = 0; i < size; i++) {
91                 fprintf(stderr, "%02x", buff[i]);
92                 if (i % 16 == 15)
93                         fprintf(stderr, "\n");
94                 else if (i % 2 == 1)
95                         fprintf(stderr, " ");
96         }
97         fprintf(stderr, "\n");
98 }
99
100 /*
101  * Fill buffer with random data and append checksum at the end.
102  */
103 void fill_buffer(unsigned char *buff, int size)
104 {
105         int *rdata = (int *) buff;
106         int rsize = size - 4;
107         uint32_t *crc = (uint32_t *) &buff[rsize];
108         int i;
109
110         for (i = 0; i < rsize / 4; i++)
111                 rdata[i] = rand();
112
113         *crc = crc32_le(0, buff, rsize);
114 }
115
116 /*
117  * Check CRC for the given buffer.
118  */
119 bool buffer_is_valid(unsigned char *buff, int size, bool verbose)
120 {
121         int rsize = size - 4;
122         uint32_t *crc_buff = (uint32_t *) &buff[rsize];
123         uint32_t crc;
124
125         crc = crc32_le(0, buff, rsize);
126
127         if (verbose && *crc_buff != crc) {
128                 fprintf(stderr, "%s: computed crc 0x%08x differs from 0x%08x\n",
129                         __func__, crc, *crc_buff);
130                 dump_buffer(buff, size);
131         }
132         return *crc_buff == crc;
133 }
134
135 /*
136  * Test functions fill_buffer and check_buffer.
137  */
138 int run_buffer_tests(void)
139 {
140         unsigned char *buff;
141         bool crc_match, last_bit_flip;
142         int ret = 0;
143         int buffer_sizes[] =
144                 {    4,    99,   100,  101,    128,
145                    251,   256,   261,  512,   1024,
146                   2048,  4096,  8192, 16384, 32768,
147                  65536, MAX_BUFFER_SIZE };  
148         int s;
149
150         printf("== Buffer and CRC tests ==\n");
151
152         buff = malloc(MAX_BUFFER_SIZE);
153         if (!buff) {
154                 fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
155                 return -1;
156         }
157
158         crc_match = true;
159         last_bit_flip = true;
160
161         for (s = 0; s < ARRAY_SIZE(buffer_sizes); s++) {
162                 unsigned char *flip;
163
164                 fill_buffer(buff, buffer_sizes[s]);
165                 if (!buffer_is_valid(buff, buffer_sizes[s], false))
166                         crc_match = false;
167
168                 flip = &buff[buffer_sizes[s] - 1];
169                 *flip = (*flip & 0xfe) | (~*flip & 1);
170                 if (buffer_is_valid(buff, buffer_sizes[s], false))
171                         last_bit_flip = false;
172         }
173         printf("CRC match: %s\n", crc_match ? "OK" : "KO");
174         printf("Last bit flip: %s\n", last_bit_flip ? "OK" : "KO");
175
176         if (!crc_match || !last_bit_flip)
177                 ret = -1;
178
179         free(buff);
180
181         return ret;
182 }