Passing wav file samples through socket in c - c

I'm (unsuccessfully) trying to pass a .wav file through a socket in C.
The following code reads the .wav file and assigns it to the short samples variable (num_samples being its size).
char* filename = "./test.wav";
FILE* f;
short* samples; // stored signal
int num_samples, curr_samples; // count of signal samples
if ((f = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "cannot open %s\n", filename);
return;
}
/* reads the .wav file into memory (samples) */
if (read_wav(f, &samples, &num_samples) < 0) {
return;
}
fclose(f);
Then, the samples are loaded iteratively into buffers and passed through the socket
int buffer_size = 320;
unsigned char buffer[buffer_size];
short bufferSamples[buffer_size/2];
int curr_samples = 0;
while(curr_samples < num_samples) {
bzero(buffer,buffer_size);
bzero(bufferSamples,buffer_size/2);
// Store samples in short array
for (i = curr_samples; i < buffer_size/2 + curr_samples; i++) {
bufferSamples[i-curr_samples] = *(samples + i);
}
// assign to buffer
for (i = 0; i < buffer_size; i+=2) {
unsigned char upper = bufferSamples[i/2] & 0xFF;
unsigned char lower = bufferSamples[i/2] >> 8;
buffer[i] = lower;
buffer[i+1] = upper;
}
n = write(sockfd,buffer,strlen(buffer));
if (n < 0) error("ERROR writing to socket");
// sleep and increment
usleep(10000);
curr_samples += buffer_size/2;
}
For the sake of simplicity, I have not posted the entire code (socket definitions etc)
I believe I have confirmed that bufferSamples correctly stores the signal in shorts for each iteration (by comparing its prints with the output of the command "od -s test.wav"), so I suspect that the problem occurs when I assign the short array to the char buffer. I have tried altering the endianess to no avail.
The server also reads input from another client I have no access to, but it handles its inputs correctly, so the problem lies in this client.
I have little experience with sockets and byte conversions, so I would be grateful if you provided me with some insight. Hopefully the solution with be quite obvious for the experienced.
EDIT: As it turns out, the problem lies in the interface used to pass the signal to this code. So, apart from the strlen() function, it seems ok after all. Nevertheless, thank you for your educating tips!

Mostly this looks ok. The code could be tidier, more functions to convert between Short and 2x char etc... to improve readability, but what you have written looks correct at a glance.
There is one problem however.
n = write(sockfd,buffer,strlen(buffer));
strlen() is for counting the length of a null terminated string.
If your buffer has any byte which is 0, strlen will stop counting. You probably want to send the size of the buffer each time sizeof(buffer)

I agree with the other answer that the use of strlen is definitely going to cause you a problem. I'm answering in addition to point out that you are doing a lot of unnecessary work that may also be bug prone. Copying the samples into another short buffer and then copying that short buffer into a buffer of chars can both be skipped. Another issue you're going to have is when you reach the end of your buffer. If its not a multiple of 320 bytes then you'll just read right past the end of the buffer.
int numBytesRemaining = num_samples * 2;
int numBytesToSend = 0;
int numBytesSent = 0;
unsigned char* pBuf = (unsigned char*)samples;
while (numBytesRemaining)
{
numBytesThisTime = 320;
// don't read past the end of the buffer.
if (numBytesThisTime > numBytesRemaining)
numBytesThisTime = numBytesRemaining;
// just in case fewer bytes were written than requested.
// 0 is an example.
numBytesWritten = write(sockfd,pBuf,numBytesThisTime);
if (numBytesWritten < 0) error("ERROR writing to socket");
// sleep and increment
usleep(10000);
// only advance by numBytesWritten
numBytesRemaining -= numBytesWritten;
pBuf += numBytesWritten; // advance the pointer.
}

Related

Initialize C array to custom character

I have built a Winsock2 server. Part of that program has a function that receives data from clients. Originally the receive function I built would peek at the incoming data and determine if there was any additional data to be read before allowing recv() to pull the data from the buffer. This worked fine in the beginning of the project but I am now working on improving performance.
Here is a portion of the code I've written to eliminate the use of peek:
unsigned char recv_buffer[4096];
unsigned char *pComplete_buffer = malloc(sizeof(recv_buffer) * sizeof(unsigned char*));
int offset = 0;
int i = 0;
...
for (i; i <= sizeof(recv_buffer); i++) {
if (recv_buffer[i] == NULL) {
break;
}
pComplete_buffer[offset] = recv_buffer[i];
offset++;
}
...
This code would work great but the problem is that NULL == 0. If the client happens to send a 0 this loop will break prematurely. I thought I would be clever and leave the data uninitialized to 0xcc and use that to determine the end of recv_buffer but it seems that clients sometimes send that as part of their data as well.
Question:
Is there a character I can initialize recv_buffer to and reliably break on?
If not, is there another way I can eliminate the use of peek?
The correct solution is to keep track of how many bytes you store in recv_buffer to begin with. sizeof() gives you the TOTAL POSSIBLE size of the buffer, but it does not tell you HOW MANY bytes actually contain valid data.
recv() tells you how many bytes it returns to you. When you recv() data into recv_buffer, use that return value to increment a variable you define to indicate the number of valid bytes in recv_buffer.
For example:
unsigned char recv_buffer[4096];
int num_read, recv_buffer_size = 0;
const int max_cbuffer_size = sizeof(recv_buffer) * sizeof(unsigned char*);
unsigned char *pComplete_buffer = malloc(max_cbuffer_size);
...
num_read = recv(..., recv_buffer, sizeof(recv_buffer), ...);
if (num_read <= 0) {
// error handling...
return;
}
recv_buffer_size = num_read;
...
int available = max_cbuffer_size - offset;
int num_to_copy = min(recv_buffer_size, available);
memcpy(pComplete_buffer + offset, recv_buffer, num_to_copy);
offset += num_to_copy;
memmove(recv_buffer, recv_buffer + num_to_copy, recv_buffer_size - num_to_copy);
recv_buffer_size -= num_to_copy;
...
Is there a character I can initialize recv_buffer to and reliably break on?
Nope. If the other side can send any character at any time, you'll have to examine them.
If you know the sender will never send two NULs in a row (\0\0), you could check for that. But then some day the sender will decide to do that.
If you can change the message structure, I'd send the message length first (as a byte, network-ordered short or int depending on your protocol). Then, after parsing that length, the receiver will know exactly how long to keep reading.
Also if you're using select, that will block until there's something to read or the socket closes (mostly -- read the docs).

c: incomplete read into int

I have program which allocates a 32-bit int and subsequently tries to read 4 bytes from a socket into the int using read(2)
Sometimes the read is incomplete and returns having read say 2 bytes. Is there any way of recovering from this? I suppose I have to produce a pointer halfway into the int to be able to perform another read.
How are you supposed to handle this situation? I can imagine a couple of ugly ways, but no elegant one.
You will first need to ensure to have read the 4 bytes. You do this using function similar to this one (slightly modified):
#include <sys/types.h>
#include <sys/socket.h>
int readall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've read
int bytesleft = *len; // how many we have left to read
int n = -1;
while(total < *len) {
n = read(s, buf+total, bytesleft, 0);
if (n <= 0) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually read here
return (n<=0)?-1:0; // return -1 on failure, 0 on success
}
And afterwards you can assemble an integer using these four bytes.
Disclaimer: this is bad code. Don't do it.
int value = 0;
int bytes = 0;
while ( (bytes += read(((char*)&value)+bytes, 4-bytes)) < 4 );
So with the information here and at What's the correct way to add 1 byte to a pointer in C/C++? I concluded that:
Addressing into an int can cause alignment problems on some architectures.
You can try to circumvent this by using type punning (a union between an int and a char[]), but in practice this technique seems no more reliable than 1.
The only truly portable way of doing byte pointer arithmetic is using a char* into a char[]. Consequently the correct way of handling this situation is to read all the bytes into the array and construct the int afterwards.
Reconstruction into an int can be done by ntohl or bit-shifting. Bitshifting is portable between host machine endianness since it is defined in terms of multiplication.
So, where does that leave us? Well, the portable option is to read into a char[] and reconstruct with bitshifting or ntohl. The non-portable way is to point a char * into your int as #Patrick87 suggested.
I went down the pragmatic road and just created a char* into my int. Worked fine on my target platform.

fseek creates infinite loop at run time

WHAT THE CODE DOES: I read a binary file and sort it. I use a frequency array in order to do so.
UPDATES:it does do the loop, but it doesn`t write the numbers correctly...
That is the code. I want to write on file after reading from it. I will suprascript what is already written, and that is okey. The problem is I have no error on compiling, but at run time it seems I have an infinite loop.
The file is binary. I read it byte by byte and that`s also the way I want to write it.
while(fread(readChar, sizeof(readChar)/2, 1, inFile)){
bit = atoi(readChar);
array[bit] = array[bit] + 1;
}
fseek(inFile, 0, SEEK_SET);
for( i = 0; i < 256; i++)
while(array[i] > 0){
writeChar[0] = array[i]; //do I correctly convert int to char?
fwite(writeChar, sizeof(readChar)/2, 1, inFile);
array[i] = array[i] -1;
}
The inFile file declaration is:
FILE* inFile = fopen (readFile, "rb+");
It reads from the file, but does not write!
Undefined behavior:
fread() is used to read a binary representation of data. atoi() takes a textual represetation of data: a string (a pointer to an array of char that is terminated with a '\0'.
Unless the data read into readChar has one of its bytes set to 0, calling atoi() may access data outside readChar.
fread(readChar, sizeof(readChar)/2, 1, inFile);
bit = atoi(readChar);
Code it not reading data "bit by bit" At #Jens comments: "The smallest unit is a byte." and that is at least 8 bits.
The only possible reason for an infinite loop I see is, that your array is not initialized.
After declaration with:
int array[256];
the elements can have any integer value, also very large ones.
So there are no infinite loops, but some loops can have very much iterations.
You should initialize your array with zeros:
int array[256]={0};
I don't know the count of elements in your array and if this is the way you declare it, but if you declare your array like shown, than ={0} will initialize all members with 0. You also can use a loop:
for(int i=0; i < COUNT_OF_ELEMENTS;i++) array[i] = 0;
EDIT: I forgot to mention, that your code is only able to sort files with only numbers within.
For that, you have also to change the conversion while writing:
char writeChar[2]={0};
for( int i = 0; i < 256; i++)
while(array[i] > 0){
_itoa(i,writeChar,10);
fwrite(writeChar, sizeof(char), 1, inFile);
array[i] = array[i] -1;
}
File content before:
12345735280735612385478504873457835489
File content after:
00112223333334444455555556777778888889
Is that what you want?

Sending ints and chars through sockets

I'm writing code for an application using sockets where I have to send integers and strings over the network, but I'm having trouble packing the data into a buffer for transmission. I tried doing this:
sendline[0] = htons(3);
sendline[1] = htons(strlen(argv[3]));
for(int i = 0; i < strlen(argv[3]); i++)
{
sendline[i + 2] = argv[3][i];
}
sendline[2 + strlen(argv[3])] = htons(atoi(argv[4]));
sendline[3 + strlen(argv[3])] = '\0';
but it doesn't work.
Where am I going wrong here? Also, what would be the best way to serialize this kind of data?
This is my deserialization code :
case '3': // switching on the value of buf[0]
{
int i;
int len = ntohs(buf[1]);
char* ch = (char*)malloc(len * sizeof(char));
for(i = 0; i < len; i++)
{
ch[i] = buf[i + 2];
}
}
You should user htonl()and ntohl(), if you are serializing 32 bit (4 byte) integers.
send:
int my_integer = INT32_MAX;
uint32_t data = htonl(my_integer);
write(s, &data, sizeof(data));
recv:
uint32_t data;
read(s, &data, sizeof(data));
int my_integer = ntohl(data);
There are many questions on SO already describing serialization and the htonl()/ntohl() functions, but beware of those omitting endianess. Remember to check return values of read() and write().
As for the "strings", do not serialize them, if they are char data describing ASCII text. UTF8 also works without serialization, but beware of UTF-16. The important thing to grasp about endianess early on is that it refers to byte order and not the order of bits within a byte. IIRC C guarantees that the presentation form of a single byte, so it appears the same on all C platforms.
Buffer sent/received via sockets consists of char, which is 1 byte long. Integer/uint16_t type is longer.
So what you really do, when you try to assign?
sendline[0] = htons(3);
sendline[0] is 1 byte long, but htons(3) is 2 bytes long, so you truncate it. Similarly you use sendline[1] by:
sendline[1] = htons(strlen(argv[3]));
Obviously your buffer gets corrupted.
Send integer numbers in one socket and strings in other, convert integers to strings or do not overwrite your buffer (so you have to use sizeof(int) on some places)

Why does printing an unsigned char sometimes work and sometimes not? In C

For a school project, I'm writing a blowfish encryption (just the encryption, not the decryption). I've finished the encryption itself, and I decided I would do the decryption for fun (it's easy enough in Blowfish).
I used unsigned chars to represent bytes (although I suppose uint8_t would have been more portable). The question I have comes in when I am attempting to print out the decrypted bytes. I am encrypting plain text messages. I've been able to print out the actual text message that I encrypted, but only at a very specific spot. The same exact code seems not to work anywhere else. Here it is:
int n;
for(n = 0; n < numBlocks; n++) // Blocks are 32-bit unsigned ints (unsigned long)
{
// uchar is just a typedef for unsigned char
// message is an array of uchars
message[n] = (uchar) ((blocks[n]>>24));
message[n+1] = (uchar) ((blocks[n]>>16));
message[n+2] = (uchar) ((blocks[n]>>8));
message[n+3] = (uchar) ((blocks[n]));
// Printing works here; exact message comes back
printf("%c%c%c%c", message[n], message[n+1], message[n+2], message[n+3]);
}
But when I try to use the exact same code two lines later, it doesn't work.
for(n = 0; n < numBlocks; n++)
{
// Printing doesn't work here.
// Actually, the first letter works, but none of the others
printf("%c%c%c%c", message[n], message[n+1], message[n+2], message[n+3]);
}
I have tried printing out the characters in number format as well, and I can see that they have in fact changed.
What exactly is going on here? Is this undefined behavior? Does anyone have any reliable solutions? I'm not doing anything to change the value of the message array in between the two calls.
I'm running and compiling this on Sun 5.10 with a sparc processor.
for(n = 0; n < numBlocks; n++) // Blocks are 32-bit unsigned ints (unsigned long)
{
message[n] = (uchar) ((blocks[n]>>24));
message[n+1] = (uchar) ((blocks[n]>>16));
message[n+2] = (uchar) ((blocks[n]>>8));
message[n+3] = (uchar) ((blocks[n]));
}
Every time you go through this loop, you set message[n] to message[n+3], then increment n by 1. This means that your first iteration sets message[0], message[1], message[2] and message[3], then your second sets message[1], message[2], message[3] and message[4]. So basically, you overwrite all but the first char in your message on every iteration.
Most likely you need to make message 4x larger and then do:
message[n*4] = ...
message[n*4 + 1] = ...

Resources