Related
Given a byte array buff of length n:
unsigned char buff[n] = "....." // len n
I want to delete m characters at position pos,
0 < pos, m, pos + m < n
I tried using memmove:
memmove(buff + pos, buff + pos + m, n - (pos + m) + 1);
But this doesn't work for byte array as we don't have '\0' terminator for this buff (but we know its length)
How do I delete bytes in between? Anyone please help
Edit: Sample input,
Pos Data
0000 03 00 02 ef 02 f0 80 64 00 08 03 eb 70 82 e0 40
0010 00 ff 30 00 00 00 00 b3 47 43 00 00 00 00 00 00
0020 00 1e 00 c4 00 00 00 00 00 00 00 44 00 65 00 66
0030 00 61 00 75 00 6c 00 74 00 41 00 6c 00 74 00 53
Say I want to delete the highlighted bytes from packet.
New paket,
Pos Data
0000 03 00 02 ef 02 f0 80 64 00 08 03 00 00 00 00 00
0010 00 00 44 00 65 00 66 00 61 00 75 00 6c 00 74 00
0020 41 00 6c 00 74 00 53
This would erase m chars in an array without terminating null character.
int main()
{
int pos = 1, m = 3;
unsigned char arr[8] = {1,2,3,4,5,6,7,8};
memmove(arr + pos, arr + pos + m, sizeof(arr)/sizeof(arr[0]) - pos - m);
// if required to zero-out the remaining elements
memset(arr + sizeof(arr)/sizeof(arr[0]) - m, 0, m);
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
printf("%hhu ", arr[i]);
return 0;
}
Output: 1 5 6 7 8 0 0 0
You probably want something like this:
#include <stdio.h>
#include <string.h>
void Display(const char buff[], int nb)
{
for (int i = 0; i < nb; i++)
printf("%d ", buff[i]);
printf("\n");
}
int main()
{
unsigned char buff[20] = { 0,1,2,3,4,5 };
// buff has room for 20 elements
int nbelements = 6; // but there are only 6 meaningful elements
Display(buff, nbelements);
int pos = 1; // delete from element 1
int nbtodelete = 2; // delete 2 elements
memmove(buff + pos, buff + pos + nbtodelete, nbelements - pos - 1);
nbelements -= nbtodelete;
Display(buff, nbelements);
}
Output:
0 1 2 3 4 5
0 3 4 5
It's pretty self explanatory.
I'm trying to understand the OpenSSL library in more detail. So rather than using the set of higher-level EVP functions, I've been trying to use the AES_* functions. Following the general set of calls in this question (though I'm using CBC instead of counter mode), I've come up with this code:
void ctr(log_t* log)
{
unsigned char ivec[16];
/* Out buffer for ciphertext */
unsigned char outBuf[16];
blockReader_t* br = blockReaderInit(log, "./input.txt", 128);
int outFD;
if ((outFD = open("out.bin", O_WRONLY)) == -1)
{
logPrint(br->log, LOG_ARGS, LOG_ERR, "open: %s", strerror(errno));
logExit(br->log, LOG_ARGS, EXIT_FAILURE);
}
memset(ivec, 0, 16);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
{
logPrint(log, LOG_ARGS, LOG_ERR, "AES_set_encrypt_key: returned %d", res);
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
unsigned char* buf;
while ((buf = blockReaderGet(br)) != NULL)
{
logPrint(log, LOG_ARGS, LOG_INFO, "ivec =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) ivec, 16);
logPrint(log, LOG_ARGS, LOG_INFO, "buf =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) buf, 16);
AES_cbc_encrypt(buf, outBuf, 16, &aesKey, ivec, 1);
logPrint(log, LOG_ARGS, LOG_INFO, "outBuf =");
logHexdump(log, LOG_ARGS, LOG_INFO, (char*) outBuf, 16);
int res = write(outFD, outBuf, 16);
if (res == -1)
{
logPrint(log, LOG_ARGS, LOG_ERR, "write: %s", strerror(errno));
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
else if (res < 16)
{
logPrint(log, LOG_ARGS, LOG_WARN, "Unexpectedly wrote < 16 bytes");
}
}
if ((close(outFD)) == -1)
{
logPrint(log, LOG_ARGS, LOG_ERR, "close: %s", strerror(errno));
logExit(log, LOG_ARGS, EXIT_FAILURE);
}
}
The log_t struct and calls to log*() are my own logging framework which I am using to help debug this code. blockReader_t is another framework for reading files in sets of bytes. blockReaderGet() simply fills the destination buffer with the predetermined number of bytes of data (in this case 128 bits/16 bytes).
Contents of input.txt:
$ hexdump -C input.txt
00000000 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 |Midnight_Marlin.|
00000010 52 69 63 68 61 72 64 52 69 63 68 61 72 64 06 07 |RichardRichard..|
00000020
Output (ran in GDB):
(gdb) run
Starting program: /home/adam/crypto/openssl/aes/aes_128
[ 0.000020] <aes_128.c:83> "main" INFO: Log library started (v1.9.0)
...
[ 0.000054] <aes_128.c:50> "ctr" INFO: ivec =
[ 0.000057] <aes_128.c:51> "ctr" INFO: HEX (16 bytes)
---BEGIN_HEX---
00000000 00 00 00 00 00 00 00 00 d0 0f 00 00 00 00 00 00 |................|
00000010
---END_HEX---
[ 0.000069] <aes_128.c:53> "ctr" INFO: buf =
[ 0.000071] <aes_128.c:54> "ctr" INFO: HEX (16 bytes)
---BEGIN_HEX---
00000000 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 |Midnight_Marlin.|
00000010
---END_HEX---
Program received signal SIGSEGV, Segmentation fault.
_x86_64_AES_encrypt_compact () at aes-x86_64.s:170
170 xorl 0(%r15),%eax
I'm using an OpenSSL from GitHub that I've built myself and linked against locally; specifically the OpenSSL_1_0_2e tag, which I gather is the latest stable version.
The Perl file that generates this assembly file uses the $key variable to name what r15 represents. But given that AES_set_encrypt_key() returns success, I'm not sure what's wrong.
Could anyone please offer any pointers to what might be wrong here?
EDIT:
Despite compiling OpenSSL with -g3 instead of -O3, the backtrace isn't useful:
(gdb) bt
#0 _x86_64_AES_encrypt_compact () at aes-x86_64.s:170
#1 0x0000000000402b6b in AES_cbc_encrypt () at aes-x86_64.s:1614
#2 0x00007fffffffe0a0 in ?? ()
#3 0x000080007dfc19a0 in ?? ()
#4 0x00007fffffffe050 in ?? ()
#5 0x0000000000635080 in ?? ()
#6 0x00007fffffffe1a0 in ?? ()
#7 0x0000000000000010 in ?? ()
#8 0x00007ffff7bdf9a0 in ?? ()
#9 0x00007fffffffe1b0 in ?? ()
#10 0x00007fff00000001 in ?? ()
#11 0x00007ffff7bdf4c8 in ?? ()
#12 0x00007fffffffda40 in ?? ()
#13 0x0000000000000000 in ?? ()
EDIT 2:
CFLAG has been changed:
CFLAG= -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -m64 -DL_ENDIAN -O0 -ggdb -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
Note the -O0 -ggdb. Backtrace is the same:
(gdb) bt
#0 _x86_64_AES_encrypt_compact () at aes-x86_64.s:170
#1 0x0000000000402b6b in AES_cbc_encrypt () at aes-x86_64.s:1614
#2 0x00007fffffffe0a0 in ?? ()
#3 0x000080007dfc19a0 in ?? ()
#4 0x00007fffffffe050 in ?? ()
#5 0x0000000000635080 in ?? ()
#6 0x00007fffffffe1a0 in ?? ()
#7 0x0000000000000010 in ?? ()
#8 0x00007ffff7bdf9a0 in ?? ()
#9 0x00007fffffffe1b0 in ?? ()
#10 0x00007fff00000001 in ?? ()
#11 0x00007ffff7bdf4c8 in ?? ()
#12 0x00007fffffffda40 in ?? ()
#13 0x0000000000000000 in ?? ()
EDIT: MCVE example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/aes.h>
unsigned char input[] = {0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};
int main()
{
unsigned char ivec[16];
/* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
unsigned char outBuf[16];
int outFD;
if ((outFD = open("out.bin", O_WRONLY)) == -1)
{
perror("open");
return EXIT_FAILURE;
}
memset(ivec, 0, 16);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if (!(res = AES_set_encrypt_key((unsigned char*) myKey, 16, &aesKey)))
{
fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
return EXIT_FAILURE;
}
for (int i = 0; i < 32; i += 16)
{
printf("ivec = ");
for (int j = 0; j < 16; j++)
printf("%.02hhx ", ivec[j]);
putchar('\n');
printf("input = ");
for (int j = i; j < (i + 16); j++)
printf("%.02hhx ", input[j]);
putchar('\n');
AES_cbc_encrypt(&input[i], outBuf, 16, &aesKey, ivec, 1);
printf("outBuf = ");
for (int j = 0; j < 16; j++)
printf("%.02hhx ", outBuf[j]);
putchar('\n');
int res = write(outFD, outBuf, 16);
if (res == -1)
{
perror("write");
return EXIT_FAILURE;
}
else if (res < 16)
{
printf("Warning: unexpectedly wrote < 16 bytes");
}
}
if ((close(outFD)) == -1)
{
perror("close");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
So there are several major bugs here. I'll go through all the ones I caught, but there may be more, as I didn't do a thorough code review.
You are using sentinel values everywhere (ie: the 16 integer literals. Swap these out with a preprocessor macro, or even better, a const int).
The output buffer needs to be at least as big as your input buffer, and should be rounded up the the nearest multiple of the block size, plus one more block.
You are looping through each element of the the input data and trying to encrypt one byte at a time. Unless you are implementing some obscure layer on top of AES, this is wrong. You iterate over blocks of data, not individual bytes. The loop is completely unnecessary.
Your input data buffer appears to be bigger than your output data buffer. With your current implementation, the last 16 bytes I think will be truncated/lost, since the input buffer has 32 bytes of data, but the output buffer is 16 bytes. In your specific example, input should be 32 bytes, output should be 32+1.
In addition to the loop being unnecessary, with some modifications it would run (incorrectly, corrupting data), and eventually access invalid memory (ie: pointing to near the end of the input buffer, and telling the encrypt function to ask for 16 bytes of data after that point).
I've provided an updated code listing and sample output that should get you on the right track. Here's a working example that should also guide you along.
Good luck!
Modified Code Listing
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <openssl/aes.h>
#define BLOCK_SIZE (128)
unsigned char input[BLOCK_SIZE] = {
0x4du, 0x69u, 0x64u, 0x6eu, 0x69u, 0x67u, 0x68u, 0x74u,
0x5fu, 0x4du, 0x61u, 0x72u, 0x6cu, 0x69u, 0x6eu, 0x05u,
0x52u, 0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x52u,
0x69u, 0x63u, 0x68u, 0x61u, 0x72u, 0x64u, 0x06u, 0x07u};
int main()
{
unsigned char ivec[BLOCK_SIZE];
/* ivec[0..7] is the IV, ivec[8..15] is the big endian counter. */
unsigned char outBuf[BLOCK_SIZE+1];
int outFD;
if ((outFD = open("out.bin", O_CREAT | O_RDWR)) == -1)
{
perror("open");
return EXIT_FAILURE;
}
memset(ivec, 0, BLOCK_SIZE);
unsigned char* ivec2 = ivec + 8;
unsigned long* ivec3 = (unsigned long*) ivec2;
*ivec3 = (unsigned long) 0xfd0;
AES_KEY aesKey;
char* myKey = "Pampers baby-dry";
int res;
if ((res = AES_set_encrypt_key((unsigned char*) myKey, BLOCK_SIZE, &aesKey)) < 0)
{
fprintf(stderr, "AES_set_encrypt_key: returned %d", res);
return EXIT_FAILURE;
}
int i = 0;
//for (int i = 0; i < 32; i += BLOCK_SIZE)
{
printf("ivec = ");
for (int j = 0; j < BLOCK_SIZE; j++)
printf("%.02hhx ", ivec[j]);
putchar('\n');
printf("input = ");
for (int j = i; j < (i + BLOCK_SIZE); j++)
printf("%.02hhx ", input[j]);
putchar('\n');
putchar('\n');
putchar('\n');
putchar('\n');
AES_cbc_encrypt(input, outBuf, BLOCK_SIZE, &aesKey, ivec, AES_ENCRYPT);
printf("outBuf = ");
for (int j = 0; j < BLOCK_SIZE; j++)
printf("%.02hhx ", outBuf[j]);
putchar('\n');
int res = write(outFD, outBuf, BLOCK_SIZE);
if (res == -1)
{
perror("write");
return EXIT_FAILURE;
}
else if (res < BLOCK_SIZE)
{
printf("Warning: unexpectedly wrote < %d bytes.\n", BLOCK_SIZE);
}
}
if ((close(outFD)) == -1)
{
perror("close");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Build Command
gcc -O0 -ggdb test.c --std=c99 -lssl -lcrypto && ./a.out
Sample Output
ivec = 00 00 00 00 00 00 00 00 d0 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
input = 4d 69 64 6e 69 67 68 74 5f 4d 61 72 6c 69 6e 05 52 69 63 68 61 72 64 52 69 63 68 61 72 64 06 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
outBuf = 81 ee 91 c0 9f f6 40 db 3c 6d 32 dd 5e 86 6f f8 4e 7b aa 15 38 36 b8 20 bc 04 bd 4f 6c 53 0e 02 72 c2 b7 e8 79 35 f2 b2 e1 c1 6e 1e 3b 1e 75 81 6a 56 43 d8 9d 9c 4c 1e 04 bd 99 29 3a 55 c9 a4 90 48 20 13 5e 51 4a 0c 4b 35 bc db da 54 f1 2b 66 f6 1b 1a 42 25 33 30 0e 35 87 9d 4b 1f d5 3a 5d 3a 8e 8c c8 48 c0 52 72 c0 4e b3 b8 f5 37 03 1c 87 15 61 3b 64 2b 06 5e 12 8f c7 b5 21 98 06
I need to put structs from a binary file into an array of structs, one struct per key.
Here is my struct:
struct candidate{
char inscr[10];
char name[44];
int year;
int position;
char curse[30];
};
typedef struct candidate Candidate;
Here's what I tried to do:
void ordenafile(char fname[13]){
FILE *f = fopen (fname, "rb");
if(f==NULL){
printf("Error.");
return;
}
fseek(f, 0, SEEK_END);
int sz = ftell(f);
Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
arr[i]=p;
i++;
}
Having found the end of the file with fseek(), you need to rewind before reading from it.
This part of the code doesn't do what you want:
Candidate *p, *aux,*arr[sz/sizeof(Candidate)];
p=(Candidate*)malloc(sizeof(Candidate));
int i = 0;
while(fread(p,sizeof(candidate),1,f)>0){
arr[i]=p;
i++;
}
You have an array of structure pointers, and you allocate one structure, pointed at by p. Your loop then reads a value into the one structure, and copies the pointer into an element of the array of pointers. So, all the elements of the array point to the same structure. The variable aux is also unused.
You need one of two solutions:
Candidate arr[sz/sizeof(Candidate)];
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
;
This assumes you are going to be able to use the array in the current function and functions it calls, and don't need to return it to the calling code.
Alternatively:
Candidate *arr = malloc(sz);
if (arr == 0)
return 0;
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, f) == 1; i++)
;
return arr;
You can return this array from the function.
Working code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct candidate
{
char inscr[10];
char name[44];
int year;
int position;
char curse[30];
};
typedef struct candidate Candidate;
int write_sample_data(const char *filename);
Candidate *read_sample_data(const char *filename, int *number);
void print_sample_data(int num, Candidate *candidates);
int main(void)
{
const char filename[] = "practice.data";
if (write_sample_data(filename) != 0)
fprintf(stderr, "Failed to write sample data\n");
else
{
int number = 0;
Candidate *clist = read_sample_data(filename, &number);
if (number == 0)
fprintf(stderr, "Failed to read sample data\n");
else
{
print_sample_data(number, clist);
free(clist);
}
}
return 0;
}
int write_sample_data(const char *filename)
{
FILE *fp = fopen(filename, "wb");
if (fp == NULL)
{
fprintf(stderr, "Failed to open file %s for writing\n", filename);
return -1;
}
Candidate c;
for (int i = 0; i < 5; i++)
{
char inscr[10];
char name[40];
char curse[30];
sprintf(inscr, "I-%.4d", i);
sprintf(name, "Name %.4d Surname %.4d", rand() % 1000, rand() % 1000);
sprintf(curse, "Curse %.2d", rand() % 100);
// Using null-filling property of strncpy()
strncpy(c.inscr, inscr, sizeof(c.inscr));
strncpy(c.name, name, sizeof(c.name));
strncpy(c.curse, curse, sizeof(c.curse));
c.year = 2010 + i;
c.position = 1000 * i + (99 - i);
if (fwrite(&c, sizeof(Candidate), 1, fp) != 1)
{
fclose(fp);
fprintf(stderr, "Failed to write candidate %d\n", i);
return -1;
}
}
fclose(fp);
return 0;
}
Candidate *read_sample_data(const char *filename, int *number)
{
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
return 0;
}
fseek(fp, 0, SEEK_END);
size_t sz = ftell(fp);
rewind(fp);
Candidate *arr = malloc(sz);
if (arr == 0)
{
fprintf(stderr, "Failed to allocate %zu bytes memory\n", sz);
return 0;
}
int i;
for (i = 0; fread(&arr[i], sizeof(Candidate), 1, fp) == 1; i++)
;
*number = i;
return arr;
}
void print_sample_data(int number, Candidate *clist)
{
for (int i = 0; i < number; i++)
{
printf("%-10s %-30s %.4d %.4d %s\n",
clist[i].inscr, clist[i].name, clist[i].year,
clist[i].position, clist[i].curse);
}
}
Note that this produces the same data each time it is run, despite using the pseudo-random numbers from rand(). Note too that the code deliberately exploits the behaviour of strncpy() that pads a field with null bytes to the full length so that the data in the file doesn't have any extraneous matter.
Sample output:
I-0000 Name 0249 Surname 0807 2010 0099 Curse 73
I-0001 Name 0930 Surname 0658 2011 1098 Curse 72
I-0002 Name 0878 Surname 0544 2012 2097 Curse 23
I-0003 Name 0440 Surname 0709 2013 3096 Curse 65
I-0004 Name 0042 Surname 0492 2014 4095 Curse 87
Hex dump of data file:
0x0000: 49 2D 30 30 30 30 00 00 00 00 4E 61 6D 65 20 30 I-0000....Name 0
0x0010: 32 34 39 20 53 75 72 6E 61 6D 65 20 30 38 30 37 249 Surname 0807
0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030: 00 00 00 00 00 00 00 00 DA 07 00 00 63 00 00 00 ............c...
0x0040: 43 75 72 73 65 20 37 33 00 00 00 00 00 00 00 00 Curse 73........
0x0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0060: 49 2D 30 30 30 31 00 00 00 00 4E 61 6D 65 20 30 I-0001....Name 0
0x0070: 39 33 30 20 53 75 72 6E 61 6D 65 20 30 36 35 38 930 Surname 0658
0x0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0090: 00 00 00 00 00 00 00 00 DB 07 00 00 4A 04 00 00 ............J...
0x00A0: 43 75 72 73 65 20 37 32 00 00 00 00 00 00 00 00 Curse 72........
0x00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00C0: 49 2D 30 30 30 32 00 00 00 00 4E 61 6D 65 20 30 I-0002....Name 0
0x00D0: 38 37 38 20 53 75 72 6E 61 6D 65 20 30 35 34 34 878 Surname 0544
0x00E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00F0: 00 00 00 00 00 00 00 00 DC 07 00 00 31 08 00 00 ............1...
0x0100: 43 75 72 73 65 20 32 33 00 00 00 00 00 00 00 00 Curse 23........
0x0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0120: 49 2D 30 30 30 33 00 00 00 00 4E 61 6D 65 20 30 I-0003....Name 0
0x0130: 34 34 30 20 53 75 72 6E 61 6D 65 20 30 37 30 39 440 Surname 0709
0x0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0150: 00 00 00 00 00 00 00 00 DD 07 00 00 18 0C 00 00 ................
0x0160: 43 75 72 73 65 20 36 35 00 00 00 00 00 00 00 00 Curse 65........
0x0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0180: 49 2D 30 30 30 34 00 00 00 00 4E 61 6D 65 20 30 I-0004....Name 0
0x0190: 30 34 32 20 53 75 72 6E 61 6D 65 20 30 34 39 32 042 Surname 0492
0x01A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01B0: 00 00 00 00 00 00 00 00 DE 07 00 00 FF 0F 00 00 ................
0x01C0: 43 75 72 73 65 20 38 37 00 00 00 00 00 00 00 00 Curse 87........
0x01D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01E0:
There are 4 bytes of padding in the structures; 2 after the name and 2 at the end, so its length is a convenient 96 bytes, which just happens to be a multiple of 16, so the hex dump aligns nicely.
I am trying to write a program that will talk to a XBee Pro S2B over serial from a PIC16 and I have some odd memory stuff going on...
I am a bit weak when it comes to pointers in C so I have been writing a test program using GCC to get it to work before I move it over to the PIC microcontroller. The biggest thing to note with the PIC is the memory constraints. So for this I would like to avoid adding any external libraries unless I absolutely have to (and avoid having to use malloc/free).
Here is my code:
#include <stdio.h>
#define FALSE 0
#define TRUE 1
void printPacketArray(unsigned char *packetArray, int packetSize){
printf("OUTPUT PACKET: ");
for(int i = 0; i < packetSize; i++){
printf("%02X ", packetArray[i]);
}
printf("\n");
}
/**
* This function builds all of the frames to be wrapped into a packet
*/
int buildFrame(
unsigned char frameType,
unsigned char requestResponse,
unsigned char *destinationAddress64Bit,
unsigned char *destinationAddress16Bit,
unsigned char *rfPacketData,
int destinationAddress64BitSize,
int destinationAddress16BitSize,
int rfDataSize,
unsigned char **frameArray,
int **frameArraySize){
// printf("Entering buildFrame\n");
// FT RESP (Optional Dest Addr x64) + (Optional Dest Addr x16) Packet
int outputPacketSize = (1 + 1 + destinationAddress64BitSize + destinationAddress16BitSize + rfDataSize);
// printf("Packet Size: %d\n", outputPacketSize);
unsigned char outputPacketArray[outputPacketSize];
// Add the frame type
outputPacketArray[0] = frameType;
// printf("Frame type: %02X\n", frameType);
// Request response
outputPacketArray[1] = requestResponse;
// printf("Response: %02X\n", requestResponse);
int arrayCount = 2;
// Add the destination address (64 bit)
if(destinationAddress64Bit != 0x00){
for(int i = 0; i < 8; i++){
outputPacketArray[arrayCount] = destinationAddress64Bit[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, destinationAddress64Bit[i]);
arrayCount++;
}
}
// Ad the destination address (16 bit)
if(destinationAddress16Bit != 0x00){
for(int i = 0; i < 2; i++){
outputPacketArray[arrayCount] = destinationAddress16Bit[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, destinationAddress16Bit[i]);
arrayCount++;
}
}
// Add the packet data
for(int i = 0; i < rfDataSize; i++){
outputPacketArray[arrayCount] = rfPacketData[i];
// printf("outputPacketArray[%d] = %02X\n", arrayCount, rfPacketData[i]);
arrayCount++;
}
*frameArray = outputPacketArray;
// printf("*frameArray = %p\n", outputPacketArray);
*frameArraySize = &outputPacketSize;
// printf("*frameArraySize = %p\n", &outputPacketSize);
// printf("Packet: ");
// for(int i = 0; i < outputPacketSize; i++){
// printf("%02X ", outputPacketArray[i]);
// }
// printf("\n");
// printf("Exiting buildFrame\n");
return TRUE;
}
/**
* This function wraps the frame data into the packet.
*/
int buildPacket(
unsigned char *frameData,
int frameDataSize,
unsigned char **packetArrayPtr,
int **packetArraySizePtr){
// 7E MSB LSB Packet Checksum
int outputPacketSize = (1 + 1 + 1 + frameDataSize + 1);
int checksum = 0;
unsigned char outputPacketArray[outputPacketSize];
// Add the start delimiter
outputPacketArray[0] = 0x7E;
// Add the MSB (should always be 0x00)
outputPacketArray[1] = 0x00;
// Add the LSB (size of frameData)
outputPacketArray[2] = frameDataSize;
// Add the frame data
int arrayCount = 3;
for(int i = 0; i < frameDataSize; i++){
// printf("CNT: %d\n", arrayCount);
outputPacketArray[arrayCount] = frameData[i];
checksum += frameData[i];
arrayCount++;
}
// Add the checksum
outputPacketArray[arrayCount] = (0xFF - (checksum & 0xFF));
// printf("CNT: %d\n", arrayCount);
// printf("Packet: ");
// for(int i = 0; i < outputPacketSize; i++){
// printf("%02X ", outputPacketArray[i]);
// }
// printf("\n");
*packetArrayPtr = outputPacketArray;
*packetArraySizePtr = &outputPacketSize;
return TRUE;
}
int sendAPICommand(unsigned char* inputFrameData, int inputFrameDataLength){
unsigned char destinationAddress64Bit[] = {0x00, 0x13, 0xA2, 0x00, 0x40, 0x9C, 0x26, 0xE1};
unsigned char destinationAddress16Bit[] = {0xFF, 0xFE};
unsigned char *frameArrayPtr = 0x00;
int *frameArraySizePtr = 0x00;
// printf("COMPARE: 7E 00 13 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05 4A\n");
// We need to add in the radius and options before the data
unsigned char frameData[(inputFrameDataLength + 2)];
frameData[0] = 0x00; // Radius
frameData[1] = 0x00; // Options
for(int i = 0; i < inputFrameDataLength; i++){
frameData[(i + 2)] = inputFrameData[i];
}
if(buildFrame(0x10, 0x01, destinationAddress64Bit, destinationAddress16Bit, frameData, 8, 2, (inputFrameDataLength + 2), &frameArrayPtr, &frameArraySizePtr) == TRUE){
printf("COMPARE: 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05\n");
printPacketArray(frameArrayPtr, *frameArraySizePtr);
// The building of the frame was a success
if(buildPacket(frameArrayPtr, *frameArraySizePtr, &frameArrayPtr, &frameArraySizePtr) == TRUE){
printf("COMPARE: 7E 00 13 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05 4A\n");
printPacketArray(frameArrayPtr, *frameArraySizePtr);
return TRUE;
}
}
return FALSE;
}
int main(){
unsigned char packetData[] = {0x01, 0x02, 0x03, 0x04, 0x05};
sendAPICommand(packetData, 5);
return 0;
}
When I run it, I cannot seem to find out why the results are not consistent. Using the Eclipse debugger, I get the following error:
frameData.15 Error: Multiple errors reported.\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Failed to execute MI command: -data-evaluate-expression frameData.15 Error message from debugger back end: No symbol "frameData" in current context.\ Failed to execute MI command: -var-create - * frameData.15 Error message from debugger back end: mi_cmd_var_create: unable to create variable object\ Unable to create variable object
on this line of code:
if(buildFrame(0x10, 0x01, destinationAddress64Bit, destinationAddress16Bit, frameData, 8, 2, (inputFrameDataLength + 2), &frameArrayPtr, &frameArraySizePtr) == TRUE){
When I run the program completely (it silently fails) and this is my text output:
COMPARE: 10 01 00 13 A2 00 40 9C 26 E1 FF FE 00 00 01 02 03 04 05
OUTPUT PACKET: 01 00 00 00 00 00 00 00 D8 8C 28 03 01 00 00 00 B0 8A 97 5C FF 7F 00 00 08 00 00 00 00 00 00 00 00 8A 97 5C 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 30 00 00 00 90 8A 97 5C FF 7F 00 00 90 89 97 5C FF 7F 00 00 00 00 00 00 00 00 00 00
I suspect the problem is I have a bad pointer (or pointers) in returning the size or the pointer to the character array but I don't know that for sure (or know how to get the program to fail in a way I can determine it).
In buildFrame:
unsigned char outputPacketArray[outputPacketSize];
outputPacketArray is a local variable. Its lifetime ends when you leave the function. However you assign a pointer to it to an output parameter of the function:
*frameArray = outputPacketArray;
(Same for outputPacketSize)
These pointers do not point to valid memory anymore when you leave the function. You need to dynamically allocate the array:
unsigned char* outputPacketArray = malloc(outputPacketSize);
and then free it later. Alternatively you could provide an appropriately sized array to the function, but then you would need to calculate the size already in main.
For the size you don't need a pointer to pointer at all, just return it from the function, or use a simple pointer (instead of double pointer) as output parameter.
I have a question on filling an array with values in C. I have a string that I want to split into an array of new strings each 14 'sections' long.
int main(int argc , char *argv[])
{
char string[]="50 09 00 00 98 30 e0 b1 0d 01 00 00 00 00 4f 09 00 00 98 30 c6 b1 0d 01 01 01 01 50 09 00 00 98 30 e0 b1 0d 01 00 00 00 00 4f 09 00 00 98 30 c6 b1 0d 01 01 01 01";
char delim[] = " ";
char *result = NULL;
char *strArray[1440] = {0};
int i = 0;
result = strtok(string, " ");
while (result)
{
strArray[i] = result;
result = strtok( NULL, delim );
i++;
}
// Now I have each 'section' of the original string in strArray[xx]
int z = 1022;
int c;
char arr[5000];
char *finalarr[100] = {0};
char buff[100];
int l = 0;
for(c=0;c<z;++c)
{
strcat(arr,strArray[c]);
if (c % 14 == 13)
{
// print the value so far for check, this gives an output of 28 chars
puts(arr);
// copy value of arr to buff
ret = sprintf(buff,"%s", arr);
// copy value of buff to instance of finalarr
finalarr[l] = buff;
// empty arr
strcpy(arr," ");
l++;
}
}
// both have the same value (last value of arr)
printf("finalarr1 = %s\n",finalarr[1]);
printf("finalarr20 = %s\n",finalarr[20]);
}
Perhaps I'm trying to solve it in a too complex way (I hope). Anyway some directions to help would be highly appreciated.
#include <stdio.h>
#include <string.h>
int main(int argc , char *argv[])
{
int i;
int fcount=0;
int acount=0;
char string[]="50 09 00 00 98 30 e0 b1 0d 01 00 00 00 00 4f 09 00 00 98 30 c6 b1 0d 01 01 01 01 50 09 00 00 98 30 e0 b1 0d 01 00 00 00 00 4f 09 00 00 98 30 c6 b1 0d 01 01 01 01";
char *finalarr[100];
char arr[29]="\0";
for (i=0;i<(strlen(string));i++)
{
if ((i+1)%3!=0)
{
strncpy(&arr[acount],&string[i],1);
acount++;
if (acount==28)
{
acount=0;
arr[29]="\0";
finalarr[fcount]=strdup(arr);
fcount++;
}
}
}
printf("finalarr1 = %s\n",finalarr[0]);
printf("finalarr1 = %s\n",finalarr[1]);
printf("finalarr1 = %s\n",finalarr[2]);
return 0;
}
result:
finalarr1 = 500900009830e0b10d0100000000
finalarr1 = 4f0900009830c6b10d0101010150
finalarr1 = 0900009830e0b10d01000000004f
You should replace the lines:
// copy value of arr to buff
ret = sprintf(buff,"%s", arr);
// copy value of buff to instance of finalarr
finalarr[l] = buff;
with:
finalarr[l] = strdup(arr);
because you only need to duplicate the string stored in arr. The variable buff should not be needed.
And the line:
// empty arr
strcpy(arr," ");
with:
*arr = '\0';
Because you only need to "reset" the string arr. With your original line, you only "replaced " former text with a 'lonely' space.