1 /*
2  * Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS 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, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <time.h>
30 #include <errno.h>
31 #include <syslog.h>
32 
33 #include "MFSCommunication.h"
34 #include "sockets.h"
35 #include "datapack.h"
36 #include "strerr.h"
37 #include "mfsstrerr.h"
38 #include "crc.h"
39 
40 #define CSMSECTIMEOUT 5000
41 
cs_readblock(int fd,uint64_t chunkid,uint32_t version,uint32_t offset,uint32_t size,uint8_t * buff)42 int cs_readblock(int fd,uint64_t chunkid,uint32_t version,uint32_t offset,uint32_t size,uint8_t *buff) {
43 	uint8_t *wptr,ibuff[28];
44 	const uint8_t *rptr;
45 
46 	wptr = ibuff;
47 	put32bit(&wptr,CLTOCS_READ);
48 	put32bit(&wptr,20);
49 	put64bit(&wptr,chunkid);
50 	put32bit(&wptr,version);
51 	put32bit(&wptr,offset);
52 	put32bit(&wptr,size);
53 	if (tcptowrite(fd,ibuff,28,CSMSECTIMEOUT)!=28) {
54 		syslog(LOG_NOTICE,"readblock; tcpwrite error: %s",strerr(errno));
55 		return -1;
56 	}
57 	for (;;) {
58 		uint32_t cmd,l;
59 		uint64_t t64;
60 		uint16_t blockno,blockoffset;
61 		uint32_t breq,blocksize,blockcrc;
62 		if (tcptoread(fd,ibuff,8,CSMSECTIMEOUT)!=8) {
63 			syslog(LOG_NOTICE,"readblock; tcpread error: %s",strerr(errno));
64 			return -1;
65 		}
66 		rptr = ibuff;
67 		cmd = get32bit(&rptr);
68 		l = get32bit(&rptr);
69 		if (cmd==CSTOCL_READ_STATUS) {
70 			if (l!=9) {
71 				syslog(LOG_NOTICE,"readblock; READ_STATUS incorrect message size (%"PRIu32"/9)",l);
72 				return -1;
73 			}
74 			if (tcptoread(fd,ibuff,9,CSMSECTIMEOUT)!=9) {
75 				syslog(LOG_NOTICE,"readblock; READ_STATUS tcpread error: %s",strerr(errno));
76 				return -1;
77 			}
78 			rptr = ibuff;
79 			t64 = get64bit(&rptr);
80 			if (*rptr!=0) {
81 				syslog(LOG_NOTICE,"readblock; READ_STATUS status: %s",mfsstrerr(*rptr));
82 				return -1;
83 			}
84 			if (t64!=chunkid) {
85 				syslog(LOG_NOTICE,"readblock; READ_STATUS incorrect chunkid (got:%"PRIu64" expected:%"PRIu64")",t64,chunkid);
86 				return -1;
87 			}
88 			if (size!=0) {
89 				syslog(LOG_NOTICE,"readblock; READ_STATUS incorrect data size (left: %"PRIu32")",size);
90 				return -1;
91 			}
92 			return 0;
93 		} else if (cmd==CSTOCL_READ_DATA) {
94 			if (l<20) {
95 				syslog(LOG_NOTICE,"readblock; READ_DATA incorrect message size (%"PRIu32"/>=20)",l);
96 				return -1;
97 			}
98 			if (tcptoread(fd,ibuff,20,CSMSECTIMEOUT)!=20) {
99 				syslog(LOG_NOTICE,"readblock; READ_DATA tcpread error: %s",strerr(errno));
100 				return -1;
101 			}
102 			rptr = ibuff;
103 			t64 = get64bit(&rptr);
104 			if (t64!=chunkid) {
105 				syslog(LOG_NOTICE,"readblock; READ_DATA incorrect chunkid (got:%"PRIu64" expected:%"PRIu64")",t64,chunkid);
106 				return -1;
107 			}
108 			blockno = get16bit(&rptr);
109 			blockoffset = get16bit(&rptr);
110 			blocksize = get32bit(&rptr);
111 			blockcrc = get32bit(&rptr);
112 			if (l!=20+blocksize) {
113 				syslog(LOG_NOTICE,"readblock; READ_DATA incorrect message size (%"PRIu32"/%"PRIu32")",l,20+blocksize);
114 				return -1;
115 			}
116 			if (blocksize==0) {
117 				syslog(LOG_NOTICE,"readblock; READ_DATA empty block");
118 				return -1;
119 			}
120 			if (blockno!=(offset>>MFSBLOCKBITS)) {
121 				syslog(LOG_NOTICE,"readblock; READ_DATA incorrect block number (got:%"PRIu16" expected:%"PRIu32")",blockno,(offset>>MFSBLOCKBITS));
122 				return -1;
123 			}
124 			if (blockoffset!=(offset&MFSBLOCKMASK)) {
125 				syslog(LOG_NOTICE,"readblock; READ_DATA incorrect block offset (got:%"PRIu16" expected:%"PRIu32")",blockoffset,(offset&MFSBLOCKMASK));
126 				return -1;
127 			}
128 			breq = MFSBLOCKSIZE - (uint32_t)blockoffset;
129 			if (size<breq) {
130 				breq=size;
131 			}
132 			if (blocksize!=breq) {
133 				syslog(LOG_NOTICE,"readblock; READ_DATA incorrect block size (got:%"PRIu32" expected:%"PRIu32")",blocksize,breq);
134 				return -1;
135 			}
136 			if (tcptoread(fd,buff,blocksize,CSMSECTIMEOUT)!=(int32_t)blocksize) {
137 				syslog(LOG_NOTICE,"readblock; READ_DATA tcpread error: %s",strerr(errno));
138 				return -1;
139 			}
140 			if (blockcrc!=mycrc32(0,buff,blocksize)) {
141 				syslog(LOG_NOTICE,"readblock; READ_DATA crc checksum error");
142 				return -1;
143 			}
144 			offset+=blocksize;
145 			size-=blocksize;
146 			buff+=blocksize;
147 		} else if (cmd==ANTOAN_NOP) {
148 			if (l!=0) {
149 				syslog(LOG_NOTICE,"readblock; NOP incorrect message size (%"PRIu32"/0)",l);
150 				return -1;
151 			}
152 		} else if (cmd==ANTOAN_UNKNOWN_COMMAND || cmd==ANTOAN_BAD_COMMAND_SIZE) {
153 			syslog(LOG_NOTICE,"readblock; got UNKNOWN_COMMAND/BAD_COMMAND_SIZE !!!");
154 			return -1;
155 		} else {
156 			syslog(LOG_NOTICE,"readblock; unknown message");
157 			return -1;
158 		}
159 	}
160 	return 0;
161 }
162 /*
163 int cs_writestatus(int fd,uint64_t chunkid,uint32_t writeid) {
164 	uint8_t ibuff[21];
165 	const uint8_t *ptr;
166 	uint32_t t32;
167 	uint64_t t64;
168 	if (tcptoread(fd,ibuff,21,CSMSECTIMEOUT)!=21) {
169 		syslog(LOG_NOTICE,"writestatus; WRITE_STATUS tcpread error: %s",strerr(errno));
170 		return -1;
171 	}
172 	ptr = ibuff;
173 	t32 = get32bit(&ptr);
174 	if (t32!=CSTOCL_WRITE_STATUS) {
175 		syslog(LOG_NOTICE,"writestatus; WRITE_STATUS unknown message (%"PRIu32")",t32);
176 		return -1;
177 	}
178 	t32 = get32bit(&ptr);
179 	if (t32!=13) {
180 		syslog(LOG_NOTICE,"writestatus; WRITE_STATUS incorrect message size (%"PRIu32"/13)",t32);
181 		return -1;
182 	}
183 	t64 = get64bit(&ptr);
184 	t32 = get32bit(&ptr);
185 	if (*ptr!=0) {
186 		syslog(LOG_NOTICE,"writestatus; WRITE_STATUS status: %s",mfsstrerr(*ptr));
187 		return -1;
188 	}
189 	if (t64!=chunkid) {
190 		syslog(LOG_NOTICE,"writestatus; WRITE_STATUS incorrect chunkid (got:%"PRIu64" expected:%"PRIu64")",t64,chunkid);
191 		return -1;
192 	}
193 	if (t32!=writeid) {
194 		syslog(LOG_NOTICE,"writestatus; WRITE_STATUS incorrect writeid (got:%"PRIu32" expected:%"PRIu32")",t32,writeid);
195 		return -1;
196 	}
197 	return 0;
198 }
199 
200 int cs_writeinit(int fd,const uint8_t *chain,uint32_t chainsize,uint64_t chunkid,uint32_t version) {
201 	uint8_t *ptr,*ibuff;
202 	uint32_t psize;
203 	psize = 12+chainsize;
204 	ibuff = malloc(8+psize);
205 	if (ibuff==NULL) {
206 		syslog(LOG_NOTICE,"writestatus; WRITE_INIT out of memory");
207 		return -1;
208 	}
209 	ptr = ibuff;
210 	put32bit(&ptr,CLTOCS_WRITE);
211 	put32bit(&ptr,psize);
212 	put64bit(&ptr,chunkid);
213 	put32bit(&ptr,version);
214 	memcpy(ptr,chain,chainsize);
215 	psize+=8;
216 	if (tcptowrite(fd,ibuff,psize,CSMSECTIMEOUT)!=(int32_t)psize) {
217 		free(ibuff);
218 		syslog(LOG_NOTICE,"writestatus; WRITE_INIT tcpwrite error: %s",strerr(errno));
219 		return -1;
220 	}
221 	free(ibuff);
222 	return cs_writestatus(fd,chunkid,0);	// wait for connect status
223 }
224 
225 int cs_writeblock(int fd,uint64_t chunkid,uint32_t writeid,uint16_t blockno,uint16_t offset,uint32_t size,uint8_t *buff) {
226 	uint8_t *ptr,ibuff[32];
227 	uint32_t crc,psize;
228 	ptr = ibuff;
229 	put32bit(&ptr,CLTOCS_WRITE_DATA);
230 	psize = 24+size;
231 	put32bit(&ptr,psize);
232 	put64bit(&ptr,chunkid);
233 	put32bit(&ptr,writeid);
234 	put16bit(&ptr,blockno);
235 	put16bit(&ptr,offset);
236 	put32bit(&ptr,size);
237 	crc = mycrc32(0,buff,size);
238 	put32bit(&ptr,crc);
239 	if (tcptowrite(fd,ibuff,32,CSMSECTIMEOUT)!=32) {
240 		syslog(LOG_NOTICE,"writestatus; WRITE_DATA tcpwrite error: %s",strerr(errno));
241 		return -1;
242 	}
243 	if (tcptowrite(fd,buff,size,CSMSECTIMEOUT)!=(int32_t)size) {
244 		syslog(LOG_NOTICE,"writestatus; WRITE_DATA tcpwrite error: %s",strerr(errno));
245 		return -1;
246 	}
247 	return 0;
248 }
249 */
250