targets/Linux/plc_Linux_main_retain.c
changeset 2173 976841968d74
child 2178 bd0d13d10b8e
equal deleted inserted replaced
2172:9fa5be79bb77 2173:976841968d74
       
     1 #ifndef HAVE_RETAIN
       
     2 #include <stdio.h>
       
     3 #include <stdint.h>
       
     4 #include <unistd.h>
       
     5 #include "iec_types.h"
       
     6 
       
     7 int GetRetainSize();
       
     8 
       
     9 /* Retain buffer.  */
       
    10 FILE *retain_buffer;
       
    11 const char rb_file[]      = "retain_buffer_file";
       
    12 const char rb_file_bckp[] = "retain_buffer_file.bak";
       
    13 
       
    14 
       
    15 /* Retain header struct.  */
       
    16 struct retain_info_t {
       
    17 	uint32_t retain_size;
       
    18 	uint32_t hash_size;
       
    19 	uint8_t* hash;
       
    20 	uint32_t header_offset;
       
    21 	uint32_t header_crc;
       
    22 };
       
    23 
       
    24 /* Init retain info structure.  */
       
    25 struct retain_info_t retain_info;
       
    26 
       
    27 /* CRC lookup table and initial state.  */
       
    28 uint32_t crc32_table[256];
       
    29 uint32_t retain_crc;
       
    30 
       
    31 
       
    32 /* Generate CRC32 lookup table.  */
       
    33 void GenerateCRC32Table(void)
       
    34 {
       
    35 	unsigned int i, j;
       
    36 	/* Use CRC-32-IEEE 802.3 polynomial 0x04C11DB7 (bit reflected).  */
       
    37 	uint32_t poly = 0xEDB88320;
       
    38 
       
    39 	for (i = 0; i <= 0xFF; i++)
       
    40 	{
       
    41 		uint32_t c = i;
       
    42 		for (j = 0 ; j < 8 ; j++)
       
    43 			c = (c & 1) ? (c >> 1 ) ^ poly : (c >> 1);
       
    44 		crc32_table[i] = c;
       
    45 	}
       
    46 }
       
    47 
       
    48 
       
    49 /* Calculate CRC32 for len bytes from pointer buf with init starting value.  */
       
    50 uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init)
       
    51 {
       
    52 	uint32_t crc = ~init;
       
    53 	unsigned char* current = (unsigned char*) buf;
       
    54 	while (len--)
       
    55 		crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8);
       
    56 	return ~crc;
       
    57 }
       
    58 
       
    59 /* Calc CRC32 for retain file byte by byte.  */
       
    60 int CheckFileCRC(FILE* file_buffer)
       
    61 {
       
    62 	/* Set the magic constant for one-pass CRC calc according to ZIP CRC32.  */
       
    63 	const uint32_t magic_number = 0x2144df1c;
       
    64 
       
    65 	/* CRC initial state.  */
       
    66 	uint32_t calc_crc32 = 0;
       
    67 	char data_block = 0;
       
    68 
       
    69 	while(!feof(file_buffer)){
       
    70 		if (fread(&data_block, sizeof(data_block), 1, file_buffer))
       
    71 			calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32);
       
    72 	}
       
    73 
       
    74 	/* Compare crc result with a magic number.  */
       
    75 	return (calc_crc32 == magic_number) ? 1 : 0;
       
    76 }
       
    77 
       
    78 /* Compare current hash with hash from file byte by byte.  */
       
    79 int CheckFilehash(void)
       
    80 {
       
    81 	int k;
       
    82 	int offset = sizeof(retain_info.retain_size);
       
    83 
       
    84 	rewind(retain_buffer);
       
    85 	fseek(retain_buffer, offset , SEEK_SET);
       
    86 
       
    87 	uint32_t size;
       
    88 	fread(&size, sizeof(size), 1, retain_buffer);
       
    89 	if (size != retain_info.hash_size)
       
    90 		return 0;
       
    91 
       
    92 	for(k = 0; k < retain_info.hash_size; k++){
       
    93 		uint8_t file_digit;
       
    94 		fread(&file_digit, sizeof(char), 1, retain_buffer);
       
    95 		if (file_digit != *(retain_info.hash+k))
       
    96 			return 0;
       
    97 	}
       
    98 
       
    99 	return 1;
       
   100 }
       
   101 
       
   102 void InitRetain(void)
       
   103 {
       
   104 	int i;
       
   105 
       
   106 	/* Generate CRC32 lookup table.  */
       
   107 	GenerateCRC32Table();
       
   108 
       
   109 	/* Get retain size in bytes */
       
   110 	retain_info.retain_size = GetRetainSize();
       
   111 
       
   112 	/* Hash stored in retain file as array of char in hex digits
       
   113 	   (that's why we divide strlen in two).  */
       
   114 	retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0;
       
   115 	//retain_info.hash_size = 0;
       
   116 	retain_info.hash = malloc(retain_info.hash_size);
       
   117 
       
   118 	/* Transform hash string into byte sequence.  */
       
   119 	for (i = 0; i < retain_info.hash_size; i++) {
       
   120 		int byte = 0;
       
   121 		sscanf((PLC_ID + i*2), "%02X", &byte);
       
   122 		retain_info.hash[i] = byte;
       
   123 	}
       
   124 
       
   125 	/* Calc header offset.  */
       
   126 	retain_info.header_offset = sizeof(retain_info.retain_size) + \
       
   127 		sizeof(retain_info.hash_size) + \
       
   128 		retain_info.hash_size;
       
   129 
       
   130 	/*  Set header CRC initial state.  */
       
   131 	retain_info.header_crc = 0;
       
   132 
       
   133 	/* Calc crc for header.  */
       
   134 	retain_info.header_crc = GenerateCRC32Sum(
       
   135 		&retain_info.retain_size,
       
   136 		sizeof(retain_info.retain_size),
       
   137 		retain_info.header_crc);
       
   138 
       
   139 	retain_info.header_crc = GenerateCRC32Sum(
       
   140 		&retain_info.hash_size,
       
   141 		sizeof(retain_info.hash_size),
       
   142 		retain_info.header_crc);
       
   143 
       
   144 	retain_info.header_crc = GenerateCRC32Sum(
       
   145 		retain_info.hash,
       
   146 		retain_info.hash_size,
       
   147 		retain_info.header_crc);
       
   148 }
       
   149 
       
   150 void CleanupRetain(void)
       
   151 {
       
   152 	/* Free hash memory.  */
       
   153 	free(retain_info.hash);
       
   154 }
       
   155 
       
   156 int CheckRetainFile(const char * file)
       
   157 {
       
   158 	retain_buffer = fopen(file, "rb");
       
   159 	if (retain_buffer) {
       
   160 		/* Check CRC32 and hash.  */
       
   161 		if (CheckFileCRC(retain_buffer))
       
   162 			if (CheckFilehash())
       
   163 				return 1;
       
   164 		fclose(retain_buffer);
       
   165 		retain_buffer = NULL;
       
   166 	}
       
   167 	return 0;
       
   168 }
       
   169 
       
   170 int CheckRetainBuffer(void)
       
   171 {
       
   172 	retain_buffer = NULL;
       
   173 	if (!retain_info.retain_size)
       
   174 		return 1;
       
   175 
       
   176 	/* Check latest retain file.  */
       
   177 	if (CheckRetainFile(rb_file))
       
   178 		return 1;
       
   179 
       
   180 	/* Check if we have backup.  */
       
   181 	if (CheckRetainFile(rb_file_bckp))
       
   182 		return 1;
       
   183 
       
   184 	/* We don't have any valid retain buffer - nothing to remind.  */
       
   185 	return 0;
       
   186 }
       
   187 
       
   188 #ifndef FILE_RETAIN_SAVE_PERIOD_S
       
   189 #define FILE_RETAIN_SAVE_PERIOD_S 1.0
       
   190 #endif
       
   191 
       
   192 static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2)
       
   193 {
       
   194 	IEC_TIME dt ={
       
   195 		t1->tv_sec  - t2->tv_sec,
       
   196 		t1->tv_nsec - t2->tv_nsec
       
   197 	};
       
   198 
       
   199 	if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){
       
   200 		dt.tv_sec--;
       
   201 		dt.tv_nsec += 1000000000;
       
   202 	}
       
   203 	if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){
       
   204 		dt.tv_sec++;
       
   205 		dt.tv_nsec -= 1000000000;
       
   206 	}
       
   207 	return dt.tv_sec + 1e-9*dt.tv_nsec;
       
   208 }
       
   209 
       
   210 
       
   211 int RetainSaveNeeded(void)
       
   212 {
       
   213 	int ret = 0;
       
   214 	static IEC_TIME last_save;
       
   215 	IEC_TIME now;
       
   216 	double diff_s;
       
   217 
       
   218 	/* no retain */
       
   219 	if (!retain_info.retain_size)
       
   220 		return 0;
       
   221 
       
   222 	/* periodic retain flush to avoid high I/O load */
       
   223 	PLC_GetTime(&now);
       
   224 
       
   225 	diff_s = CalcDiffSeconds(&now, &last_save);
       
   226 
       
   227 	if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) {
       
   228 		ret = 1;
       
   229 		last_save = now;
       
   230 	}
       
   231 	return ret;
       
   232 }
       
   233 
       
   234 void ValidateRetainBuffer(void)
       
   235 {
       
   236 	if (!retain_buffer)
       
   237 		return;
       
   238 
       
   239 	/* Add retain data CRC to the end of buffer file.  */
       
   240 	fseek(retain_buffer, 0, SEEK_END);
       
   241 	fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer);
       
   242 
       
   243 	/* Sync file buffer and close file.  */
       
   244 #ifdef __WIN32
       
   245 	fflush(retain_buffer);
       
   246 #else
       
   247 	fsync(fileno(retain_buffer));
       
   248 #endif
       
   249 
       
   250 	fclose(retain_buffer);
       
   251 	retain_buffer = NULL;
       
   252 }
       
   253 
       
   254 void InValidateRetainBuffer(void)
       
   255 {
       
   256 	if (!RetainSaveNeeded())
       
   257 		return;
       
   258 
       
   259 	/* Rename old retain file into *.bak if it exists.  */
       
   260 	rename(rb_file, rb_file_bckp);
       
   261 
       
   262 	/* Set file CRC initial value.  */
       
   263 	retain_crc = retain_info.header_crc;
       
   264 
       
   265 	/* Create new retain file.  */
       
   266 	retain_buffer = fopen(rb_file, "wb+");
       
   267 	if (!retain_buffer) {
       
   268 		fprintf(stderr, "Failed to create retain file : %s\n", rb_file);
       
   269 		return;
       
   270 	}
       
   271 
       
   272 	/* Write header to the new file.  */
       
   273 	fwrite(&retain_info.retain_size,
       
   274 		sizeof(retain_info.retain_size), 1, retain_buffer);
       
   275 	fwrite(&retain_info.hash_size,
       
   276 		sizeof(retain_info.hash_size),   1, retain_buffer);
       
   277 	fwrite(retain_info.hash ,
       
   278 		sizeof(char), retain_info.hash_size, retain_buffer);
       
   279 }
       
   280 
       
   281 void Retain(unsigned int offset, unsigned int count, void *p)
       
   282 {
       
   283 	if (!retain_buffer)
       
   284 		return;
       
   285 
       
   286 	/* Generate CRC 32 for each data block.  */
       
   287 	retain_crc = GenerateCRC32Sum(p, count, retain_crc);
       
   288 
       
   289 	/* Save current var in file.  */
       
   290 	fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET);
       
   291 	fwrite(p, count, 1, retain_buffer);
       
   292 }
       
   293 
       
   294 void Remind(unsigned int offset, unsigned int count, void *p)
       
   295 {
       
   296 	/* Remind variable from file.  */
       
   297 	fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET);
       
   298 	fread((void *)p, count, 1, retain_buffer);
       
   299 }
       
   300 #endif // !HAVE_RETAIN