My program cannot read and display contents in a file - c

I have an assignment that I need to create a program to read (in binary mode) a file and then display them out on the screen. I run it in the command line mode. Here is my source code:
#include <stdio.h>
#include <stdlib.h>
#define MAXWORD 130
typedef struct Node node;
struct Node
{
int stt;
char name[50];
char phonenumber[20];
char email[50];
};
int checktoread(FILE *datain)
{
return (datain == NULL);
}
int readfile(FILE *datain, node *item)
{
int i = 0;
while(fread(&item[i], sizeof(node), 1, datain)>0)
{
i++;
}
return i;
}
void display(node *item, int max)
{
int i = 0;
for(; i < max; i++)
{
printf("%-3d%-30s%-20s%-30s\n", item[i].stt, item[i].name, item[i].phonenumber, item[i].email);
}
}
int main(int argv, char *argc[])
{
if (argv != 2)
{
printf("Wrong syntax\nCorrect Syntax: readfile <source file>\n");
exit(1);
}
FILE *fp = fopen(argc[1], "rb");
if(checktoread(fp))
{
printf("The source file is unable to be opened\n");
exit(1);
}
node *person = (node*) malloc(30*sizeof(person));
int maxline = readfile(fp, person);
printf("%d\n", maxline);
display(person, maxline);
fclose(fp);
free(person);
return 0;
}
My problem is this file do not return or display anything. There is no syntax error here, I confirm. I don't know where I get wrong. Actually, I think it get wrong in the step that convert data from a file into an array.
The file starts like this
0 1 2 3 4 5 6 7 8 9 A B C D E F
0000:0000 01 00 00 00 4A 6F 65 79 4D 61 74 68 65 6C 00 00
0000:0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:0060 00 00 00 00 00 00 00 00 30 33 38 35 37 38 38 30
0000:0070 36 30 00 00 00 00 00 00 00 00 00 00 6A 6F 65 79
0000:0080 6D 61 74 68 65 6C 40 67 6D 61 69 6C 2E 63 6F 6D
0000:0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000:00E0 02 00 00 00 53 63 6F 74 74 79 4A 61 63 6B 00 00
0000:00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Related

C hexadecimal formatting giving me extra digits

I've been working on a small program to dump the hex values of a file, similar to od or hexdump, and I've ran into an issue when printing the values. For certain hex values, mostly ones with alphabetical characters as their second digit, it prints with 6 extra f digits before printing the actual number, instead of just printing a 2-width value like I had specified. I have confirmed that the values themselves are not unexpected in any way, it's the printing that's messing it up.
Code:
int main(int argc, char* argv[]) {
FILE* dataFile = fopen(argv[1], "rb");
int byteCount = 0;
char currentByte = fgetc(dataFile);
while (currentByte != EOF) {
printf("%08d", byteCount);
do {
//print as hex
printf(" %02x ", currentByte);
//set up for next loop
currentByte = fgetc(dataFile);
byteCount++;
} while (currentByte != EOF && (byteCount) % 16 != 0);
printf("\n");
}
printf("%08d\n", byteCount);
}
Output:
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
00000016 03 00 3e 00 01 00 00 00 10 6b 00 00 00 00 00 00
00000032 40 00 00 00 00 00 00 00 08 23 02 00 00 00 00 00
00000048 00 00 00 00 40 00 38 00 0d 00 40 00 1f 00 1e 00
00000064 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00
00000080 40 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00000096 ffffffd8 02 00 00 00 00 00 00 ffffffd8 02 00 00 00 00 00 00
00000112 08 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00
00000128 18 03 00 00 00 00 00 00 18 03 00 00 00 00 00 00
00000144 18 03 00 00 00 00 00 00 1c 00 00 00 00 00 00 00
00000160 1c 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
00000176 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00
00000192 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000208 fffffff8 34 00 00 00 00 00 00 fffffff8 34 00 00 00 00 00 00
Does anyone know what's going on here?
There are several problems here.
char is entirely unsuitable to hold raw binary data, because it has implementation-defined signedness and it often a signed type, see Is char signed or unsigned by default?. In fact char should only ever be used for text strings. Instead, you would normally use uint8_t. However... :
The EOF constant is of type int, so if you intend to compare something against EOF, it must be type int. fgetc is guaranteed to return characters as if they were unsigned char but converted to int - as it happens, int is large enough to hold all values of an unsigned char so int can be used here.
%x specifier for printf expects an unsigned int.
Fixes:
char currentByte -> int currentByte
printf(" %02x ", currentByte); -> printf(" %02x ", (unsigned int)currentByte);.
You must always check if fopen was successful and also fclose the file pointer when done. Also note that calling fopen directly on argv with no input sanitation is not acceptable in a professional program. You don't even know if argv[1] exists - the program needs a whole lot more error handling overall.

AF_XDP: `BPF_MAP_TYPE_XSKMAP` only has entries with `Operation not supported`

This is all my XDP / BPF kernel code:
struct bpf_map_def SEC("maps") xsks_map = {
.type = BPF_MAP_TYPE_XSKMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};
struct bpf_map_def SEC("maps") rx_queue_pckt_counter_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(unsigned long),
.max_entries = 48,
};
SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx) {
int index = ctx->rx_queue_index;
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
void *pos = data;
struct ethhdr *eth = (struct ethhdr*)(pos);
if(eth + sizeof(struct ethhdr) <= data_end) {
if(bpf_ntohs(eth->h_proto) == ETH_P_IP) {
struct iphdr *iph = (struct iphdr*)(pos + sizeof(struct ethhdr));
if(iph + sizeof(struct iphdr) <= data_end) {
if(iph->protocol == IPPROTO_UDP) {
const __u16 iph_sz_in_bytes = iph->ihl * 4;
if(iph + iph_sz_in_bytes <= data_end) {
struct udphdr *udh = (struct udphdr*)(pos + sizeof(struct ethhdr) + iph_sz_in_bytes);
if(udh + sizeof(struct udphdr) <= data_end) {
void *rec = bpf_map_lookup_elem(&rx_queue_pckt_counter_map, &index);
if(rec) {
long *pckt_counter_val = (long*)(rec);
*pckt_counter_val += 1;
} else {
return XDP_PASS;
}
if (bpf_map_lookup_elem(&xsks_map, &index)) {
const int ret_val = bpf_redirect_map(&xsks_map, index, 0);
bpf_printk("RET-VAL: %d\n", ret_val);
return ret_val;
}
}
}
}
}
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
I am trying to filter all IP-UDP packets and send them into user-space. I also count the number of packets arriving for each RX-Queue (indicated by ctx->rx_queue_index).
My program compiles fine but for whatever reason I don't receive any packets in my user-space program. I already talked about this in another post of mine: AF_XDP: No packets from multicast although steered on RX-Queue 0
I executed sudo ethtool -N eth20 flow-type udp4 action 0 beforehand to steer all packets onto RX-Queue 0.
I can see all bpf maps currently active via
$ sudo bpftool map list
32: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
33: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
34: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
35: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
36: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
37: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
125: array name rx_queue_pckt_c flags 0x0
key 4B value 8B max_entries 48 memlock 4096B
126: xskmap name xsks_map flags 0x0
key 4B value 4B max_entries 64 memlock 4096B
But I think only 125 and 126 are related to my program.
The queue-steering works because with sudo bpftool map dump id 125 I get:
key: 00 00 00 00 value: 99 1a cc 04 00 00 00 00
key: 01 00 00 00 value: 00 00 00 00 00 00 00 00
key: 02 00 00 00 value: 00 00 00 00 00 00 00 00
key: 03 00 00 00 value: 00 00 00 00 00 00 00 00
key: 04 00 00 00 value: 00 00 00 00 00 00 00 00
key: 05 00 00 00 value: 00 00 00 00 00 00 00 00
key: 06 00 00 00 value: 00 00 00 00 00 00 00 00
key: 07 00 00 00 value: 00 00 00 00 00 00 00 00
key: 08 00 00 00 value: 00 00 00 00 00 00 00 00
key: 09 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0f 00 00 00 value: 00 00 00 00 00 00 00 00
key: 10 00 00 00 value: 00 00 00 00 00 00 00 00
key: 11 00 00 00 value: 00 00 00 00 00 00 00 00
key: 12 00 00 00 value: 00 00 00 00 00 00 00 00
key: 13 00 00 00 value: 00 00 00 00 00 00 00 00
key: 14 00 00 00 value: 00 00 00 00 00 00 00 00
key: 15 00 00 00 value: 00 00 00 00 00 00 00 00
key: 16 00 00 00 value: 00 00 00 00 00 00 00 00
key: 17 00 00 00 value: 00 00 00 00 00 00 00 00
key: 18 00 00 00 value: 00 00 00 00 00 00 00 00
key: 19 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1f 00 00 00 value: 00 00 00 00 00 00 00 00
key: 20 00 00 00 value: 00 00 00 00 00 00 00 00
key: 21 00 00 00 value: 00 00 00 00 00 00 00 00
key: 22 00 00 00 value: 00 00 00 00 00 00 00 00
key: 23 00 00 00 value: 00 00 00 00 00 00 00 00
key: 24 00 00 00 value: 00 00 00 00 00 00 00 00
key: 25 00 00 00 value: 00 00 00 00 00 00 00 00
key: 26 00 00 00 value: 00 00 00 00 00 00 00 00
key: 27 00 00 00 value: 00 00 00 00 00 00 00 00
key: 28 00 00 00 value: 00 00 00 00 00 00 00 00
key: 29 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2f 00 00 00 value: 00 00 00 00 00 00 00 00
Found 48 elements
As you can see, only the counter for RX-Queue 0 is greater than 0.
But, if I take a look at the BPF_MAP_TYPE_XSKMAP (which is used to transfer packets into user-space), I get:
$ sudo bpftool map dump id 126
key:
00 00 00 00
value:
Operation not supported
key:
01 00 00 00
value:
Operation not supported
key:
02 00 00 00
value:
Operation not supported
key:
03 00 00 00
value:
Operation not supported
key:
04 00 00 00
value:
Operation not supported
...
key:
3e 00 00 00
value:
Operation not supported
key:
3f 00 00 00
value:
Operation not supported
Found 0 elements
Is the message Operation not supported an indicator why I don't receive any packets in my user-space program? Or is it just not possible to receive the value during runtime? I also find it strange to see Found 0 elements.
Any ideas what is wrong here?
This is simply because maps of type BPF_MAP_TYPE_XSKMAP do not support lookup from user space (you'd get addresses from kernel space, which does not make sense from user space point of view and might be a security issue).
So because attempting the lookup returns -EOPNOTSUPP, bpftool is unable to show the values. It could error out and print nothing, but instead we made it print the keys it finds, and print the error messages we get for the values.
As for the Found 0 elements, the count is for the elements that bpftool could retrieve without any error, so it's only logical that it remains at zero in this case.
So nothing seems wrong in your case, I do not believe this output is related to your issue with the missing packets.

Cannot read struct from binary file

I am trying to read the contents of a binary file into a struct, but each time I print out the contents of my struct, I get a pretty strange output. Below is the struct I am trying to set:
struct student {
char name[32];
unsigned int age;
SEX sex;
float gpa;
struct course *courses;
struct student *next;
}
With the course struct defined as:
struct course {
char grade;
unsigned int number;
struct course *next;
}
And SEX defined as:
typedef enum _SEX {MALE = 'M', FEMALE = 'F', OTHER = 'O'} SEX;
Right now, my function is as follows:
void read_bin(char *filename){
FILE *file;
struct student myStudent;
file = fopen(filename, "rb");
if(file == NULL){
printf("Unable to open file!");
return;
}
fread(&myStudent, sizeof(struct student), 1, file);
printf("\nName: %s, Age: %d", myStudent.name, myStudent.age);
fclose(file);
}
But I keep on getting this strange output:
Age: 0
With name not even showing up and age set to an incorrect number. I thought this might be due to padding, so I tried using
fread(&myStudent.name, sizeof myStudent.name, 1, file);
fread(&myStudent.age, sizeof myStudent.age, 1, file);
So that it reads each individual element and pads as needed. However, I get the same output. When I ran hexdump to see what exactly I was dealing with, this is what came out:
f0 0d 03 00 00 00 46 72 65 64 00 00 00 00 00 00 |......Fred......|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00 00 00 00 00 00 1d 00 00 00 4d 00 00 00 cd cc |..........M.....|
4c 40 01 00 00 00 44 02 00 00 41 4a 6f 65 00 00 |L#....D...AJoe..|
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 16 00 00 00 4d |...............M|
00 00 00 33 33 73 40 03 00 00 00 6e 00 00 00 42 |...33s#....n...B|
dc 00 00 00 41 54 01 00 00 41 53 61 72 61 68 00 |....AT...ASarah.|
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 16 00 00 00 46 00 |..............F.|
00 00 00 00 40 40 03 00 00 00 78 00 00 00 42 dc |....##....x...B.|
00 00 00 41 4a 01 00 00 43 |...AJ...C|
Any help would be greatly appreciated -- I've been stuck on this function for awhile.
Depending on the filetype the first few bytes can be a fileheader, here information can be stored like version numbers, length of the data etc.
As for the pointers, that won't work like others pointed out since pointers are adresses, not actual relevant data.
You want to fseek to sizeof(fileheader), before you start reading the file.
Also be wary that structs are padded in C and that the order in which you declared the elements in the struct might not be the order the compiler decided for it.

Linker adds extra padding in section?

I am using GCC and am trying to get the linker to create an array of data objects from different files in a custom section. I have added this section to the linker script:
.mydata :
{
__mydata_start = .;
KEEP (*(.mydata))
__mydata_end = .;
}
Here is my data structure:
struct my_type_t {
unsigned char a;
size_t b;
void *c;
const void *d;
const void *e;
const char *f;
};
I am on a 64-bit platform, and sizeof(struct my_type_t) gives 48. However, the linker seems to want to align these structures to 64-bytes.
My declarations:
struct my_type_t a1 __attribute__((section(".mydata"))) = {
1, 2, (void *)3, (void *)4, (void *)5, (void *)6,
};
struct my_type_t a2 __attribute__((section(".mydata"))) = {
7, 8, (void *)9, (void *)10, (void *)11, (void *)12,
};
Linker output:
$ gcc -o ldtest ldtest.c -Wl,-Tlink.ld
$ objcopy -Obinary -j .mydata ldtest mydata
$ hd mydata
00000000 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|
00000010 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000020 05 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 07 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 |................|
00000050 09 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 |................|
00000060 0b 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 |................|
If I instead declare it as an array:
struct my_type_t a1[2] __attribute__((section(".mydata"))) = {
{
1, 2, (void *)3, (void *)4, (void *)5, (void *)6,
},
{
7, 8, (void *)9, (void *)10, (void *)11, (void *)12,
},
};
There is no padding, as expected:
00000000 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|
00000010 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000020 05 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |................|
00000030 07 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 |................|
00000040 09 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 |................|
00000050 0b 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 |................|
Why is the linker adding extra padding beyond what the compiler thinks is necessary, and how can I get rid of it?
I don't know why it wants it aligned on 64-byte, but you can do:
struct my_type_t {
unsigned char a;
size_t b;
void *c;
const void *d;
const void *e;
const char *f;
} __attribute__ ((aligned (64)));
To make gcc automatically pad each struct to the nearest higher 64-byte address and make sizeof(struct my_type_t) also include the padding. This makes operations like this work correctly:
struct my_type_t *s = &__mydata_start;
s++; // Jump to next entry
s[0]; // First entry
s[1]; // Second entry

Save audio stream in file using C libwebsockets

I have a C server that uses libwebsockets and I want to save a received audio stream in a file on disk.
Here is my code snippet:
#define FILENAME "/home/ubuntu/Desktop/file.wav"
FILE *received_file;
struct lws_context *Audiocontext;
static int callback_audio(
struct lws *wsi,
enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
{
printf("client is connected\n");
received_file = fopen(FILENAME, "w+");
if (received_file == NULL)
{
printf("Failed to open file\n");
exit(EXIT_FAILURE);
}
}
break;
case LWS_CALLBACK_RECEIVE: {
if(strcmp((char*)in,"EOS")==0)
{
printf("End of stream!\n");
fclose(received_file);
}
else
{
fwrite(in, 1, len, received_file);
}
}
}
}
I got the message "client is connected" and also the file, but the content isn't ok, I cannot play it. I think there is a problem regarding the way I save the stream on file using fwrite().
The client is sending audio chunks encoded as wav, 16Khz, mono. Here is a snippet from client (it's a javascript client, the full code is here:http://kaljurand.github.io/dictate.js/).
if (recorder) {
recorder.stop();
config.onEvent(MSG_STOP, 'Stopped recording');
// Push the remaining audio to the server
recorder.export16kMono(function(blob) {
socketSend(blob);
socketSend(TAG_END_OF_SENTENCE);
recorder.clear();
}, 'export16kMono');
config.onEndOfSpeech();
} else {
config.onError(ERR_AUDIO, "Recorder undefined");
}
The client is working well, I use it for exactly the same task, but using a Java server. I would appreciate if someone could indicate me how to save these audio chunks in a valid file.
I think that you do not write header in your wav file. To do so,
you can write some function to do so see specification here
or you can use a dedicaded library, like libsndfile, which is not so complicated to use:
// instead of fopen, write something like
SF_INFO info;
SNDFILE * sf;
info.samplerate = sample_rate;
info.channels = 1;
info.sections = 1;
info.seekable = 0;
info.frames = 0;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
sf = sf_open(filename, SFM_WRITE, &info);
// instead of fwrite, something like
sf_write_short(sf, in, len / sizeof(short));
// and instead of fclose
sf_close(sf);
I didn't use libsndfile, but I change something on the client side. This is the current hexdump output:
00000000 52 49 46 46 20 60 00 00 57 41 56 45 66 6d 74 20 |RIFF `..WAVEfmt |
00000010 10 00 00 00 01 00 02 00 44 ac 00 00 10 b1 02 00 |........D.......|
00000020 04 00 10 00 64 61 74 61 00 60 00 00 00 00 00 00 |....data.`......|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00006020 00 00 00 00 00 00 00 00 00 00 00 00 52 49 46 46 |............RIFF|
00006030 20 60 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 | `..WAVEfmt ....|
00006040 01 00 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 |....D...........|
00006050 64 61 74 61 00 60 00 00 00 00 00 00 00 00 00 00 |data.`..........|
00006060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
0000c050 00 00 00 00 00 00 00 00 52 49 46 46 20 60 00 00 |........RIFF `..|
0000c060 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00 |WAVEfmt ........|
0000c070 44 ac 00 00 10 b1 02 00 04 00 10 00 64 61 74 61 |D...........data|
0000c080 00 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.`..............|
0000c090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
It seems to be wav encoded, but i don't have a content.

Resources