what is wrong with the following while loop? - c

I have a c winsock code section where a client receives a comma delimited stream of file fingerprints as shown below. I need to extract the fingerprints from the stream using strtok_s() in a while loop. My problem is most of the time the client does not extract the exact number of fingerprints sent from the server, even though the data received(observed by debugging) is exactly what the server sent.
What am I missing here?
recv_size = recv(clnt_sock, fp_buf, BUF_LEN, 0);
received_fp_size += recv_size;
if (0 != (last_string_len = recv_size % 33))
strncpy(last_string, &fp_buf[(recv_size - last_string_len)], last_string_len);//
while (recv_size > 0)
{
unique_fp = strtok_s(fp_buf, ",", &strtk);
k:
while (unique_fp != NULL)
{
memcpy(unique_fp_buf[unique_files_count], unique_fp, 32);
unique_fp = strtok_s(NULL, ",", &strtk);
unique_files_count++;
}
recv_size = recv(clnt_sock, fp_buf, BUF_LEN, 0);
received_fp_size += recv_size;
if (last_string_len > 0)
{
unique_fp = strtok_s(fp_buf, ",", &strtk);
strncat_s(last_string, unique_fp, strlen(unique_fp));
memcpy(unique_fp, last_string, 32);
last_string_len = 0;
goto k;
}
}
The reason behind the if (0 != (last_string_len = recv_size % 33)) line is; The server sends a multiple of 33 byte strings(32 for the fingerprint and 1 for the coma demlimiter)

One problem is that you never check that fp_buf actually contains a complete token. For instance if the first call only receives 20 bytes, your code will fail by copying a partial fingerprint.
I think another problem is here:
memcpy(unique_fp, last_string, 32);
Seems you are copying into the receive buffer and therefore overwrites some data that you haven't processed yet. Further, you may overwrite a token.
Maybe you actually wanted:
memcpy(unique_fp_buf[unique_files_count], last_string, 32);
^^^^^^^^^^^
unique_fp = strtok_s(NULL, ",", &strtk);
unique_files_count++;
Besides that I think you are making the code much more complicated than needed. The use of a goto kind of tell you that your design is wrong.
Instead of using a last_string you could do:
1) Call recv
2) Process all complete fingerprints
3) Copy the remainder (i.e. the last partial fingerprint) to the start of `fp_buf`
4) Call `recv` with an offset into `fp_buf`
5) Repeat from step 2 (i.e. use a while loop - don't use goto
Step 3 could be something like:
recv_size = recv(clnt_sock, fp_buf + length_of_remainder , BUF_LEN - length_of_remainder, 0);
In that way you don't have to handle the last_string stuff

Related

Unable to send characters after null from a file to the server in c

OS: Ubuntu(20.04)
MCU: ESP WROOM 32
Coding language: C
I have a file of 120KB with lot of null characters in between. For example:
char[50] = "welcome\0 my name\0 is";
is my string, I am trying to send entire text(including \0) to server via GSM module. I am sending this data to GSM via UART and sending the data to server using AT command "AT+HTTPDATA" and later doing HTTPPOST. The problem that I am facing now is, I am able to send the data only till first null character is encountered.
For ex:
In the above string "welcome\0 my name\0 is"
I am able to send only till "welcome", but nothing after that.
the sample code is given here:
sent_bytes = uart_write_bytes(UART_NUM_1, dummy_data, size_of_data); /*data that I am sending
with '\0' in between*/
sent_bytes = uart_write_bytes(UART_NUM_1, "\x1A", 2); //ctrl+z for httpdata to terminate
I have tried different ways of sending it, but no luck till now.
For example:
for(int f=0;f<=500;f++){
char_ptr = dummy_data[f];
int l=0;
if(char_ptr != '\0' && f <= 500){
printf("char_ptr is %c\n", char_ptr);
temp[f] = char_ptr;
sent_bytes = uart_write_bytes(UART_NUM_1, temp, sizeof(temp));
printf("temp value inside condition is %s\n", temp);
temp[1000] = "";
l++;
if(l == 500){
printf("500 reached \n");
goto c2;
}else{
printf("500 has not reached, going to c1\n");
// goto c1;
}
}
}
Still this code doesn't work and I am able to receive only the string till the first null
i.e., till "welcome" in the above case.
So, if anyone knows the solution for this please let me know. Thanks in advance for any leads.

Read from a certain part of a file PIC32MX

I am using PIC32MX in a design made by myself and everything is working perfectly.
Now I am trying to implement a feature which is basically read from a file sequentially until I found a certain frame of characters, so I am doing:
while( (readedBytes = FSfread((void *)&c,sizeof(char),1,ephpubData->filetouart) != 0) && G_RUNNING && ephpubData->readedBytes < 2520){
privData->txBuffer[privData->txBufferPos++] = c;
ephpubData->readedBytes = ephpubData->readedBytes + readedBytes;
if (privData->txBufferPos == TX_BUFFER_SIZE){
if (verifyDate (task) == 1){
*gpsState = GPS_STATE_VERIFY;
ephpubData->count++;
break;
}
FSfseek(ephpubData->filetouart , ephpubData->readedBytes , SEEK_SET);
privData->txBufferPos = 0;
}
}
For the first time when it finds the frame (using the verifyDate function) everything is ok and it goes to break sentence.
When it comes to read the second time in the while loop (after close/reopen the file and doing other things in the code) it goes to the first position again.
So I want to save the the latest position found until the break sentence. I already tried to use the seek function for every while iteration
while( (readedBytes = FSfread((void *)&c,sizeof(char),1,ephpubData->filetouart->seek) != 0) && G_RUNNING && ephpubData->readedBytes < 2520)
but it gave me an error.
Sorry folks but I found the bug.
Somewhere in the code I was doing:
FSfseek( ephpubData->filetouart , 0 , SEEK_SET );
Which sets the reading position to 0.

How to Match a URL in UDP payload using POSIX regexec and libpcap in C

I'm trying to capture the URL from an UDP payload using Libpcap in C with POSIX regex. I have tried all the methods but nothing returns a hit.
I have pasted the part of my code here where im trying to capture the URL that comes with UDP payload.
size_udp = 8;
udp = (struct sniff_udp*)(pktptr + ETHER_HDRLEN + size_udp);
payload_udp = (u_char *)(pktptr + ETHER_HDRLEN + size_ip + size_udp);
size_payload_udp = ntohs(ip->ip_len) - (size_ip + size_udp);
int reg,sh;
regex_t re;
regmatch_t pm;
char *hit;
reg = regcomp(&re, ( "\.youtube\.com", "\.googlevideo\.com","ytimg"), REG_EXTENDED);
sh = regexec(&re, &payload_udp, 2, &pm, REG_EXTENDED);
strcpy(hit, payload_udp + (pm.rm_so - pm.rm_eo));
if(
(strstr(hit,"youtube") != NULL)
|| (strstr(hit,"googlevideo") != NULL)
|| (strstr(hit,"video") != NULL)
|| (strstr(hit,"ytimg") != NULL)
)
{
//Writing to dump file
pcap_dump(usr, pkthdr, pktptr - lnkhdrlen);
}
This is my code. I would like to know why the regex doens't match the URL of Youtube in the UDP Payload.
Thank You for your suggestion
One possible reason is this line:
reg = regcomp(&re, ( "\.youtube\.com", "\.googlevideo\.com","ytimg"), REG_EXTENDED);
In your second argument the expressions concerning youtube and googlevideo are unsed. That is, what is actually compiled is this:
reg = regcomp(&re, "ytimg", REG_EXTENDED);
Your compiler should have warned about this...
Moreover, in
sh = regexec(&re, &payload_udp, 2, &pm, REG_EXTENDED);
some of the arguments do not make sense. pm is only one match structure, yet you tell regexec that it can save 2. &payload_udp is the address of the pointer your payload, not a pointer in the string your are searching for. REG_EXTENDED is not needed for executing only for compiling the regex.
sh (the return value) already tells you whether there was a match (if it returns 0) or not (if it returns REG_NOMATCH). No need to copy and strstr. Btw, your strcpy will copy (without limit) to wherever arbitrary memory location hit happens to point, and it will copy as long as it does not find a '0'-byte.
Finally, if your udp payload is not a null-terminated string (or at least starts with the null-terminated string you want to match against) the approach with regexec will not help.

Missing characters from input stream from fastcgi request

I'm trying to develop simple RESTful api using FastCGI (and restcgi). When I tried to implement POST method I noticed that the input stream (representing request body) is wrong. I did a little test and looks like when I try to read the stream only every other character is received.
Body sent: name=john&surname=smith
Received: aejh&unm=mt
I've tried more clients just to make sure it's not the client messing with the data.
My code is:
int main(int argc, char* argv[]) {
// FastCGI initialization.
FCGX_Init();
FCGX_Request request;
FCGX_InitRequest(&request, 0, 0);
while (FCGX_Accept_r(&request) >= 0) {
// FastCGI request setup.
fcgi_streambuf fisbuf(request.in);
std::istream is(&fisbuf);
fcgi_streambuf fosbuf(request.out);
std::ostream os(&fosbuf);
std::string str;
is >> str;
std::cerr << str; // this way I can see it in apache error log
// restcgi code here
}
return 0;
}
I'm using fast_cgi module with apache (not sure if that makes any difference).
Any idea what am I doing wrong?
The problem is in fcgio.cpp
The fcgi_steambuf class is defined using char_type, but the int underflow() method downcasts its return value to (unsigned char), it should cast to (char_type).
I encountered this problem as well, on an unmodified Debian install.
I found that the problem went away if I supplied a buffer to the fcgi_streambuf constructor:
const size_t LEN = ... // whatever, it doesn't have to be big.
vector<char> v (LEN);
fcgi_streambuf buf (request.in, &v[0], v.size());
iostream in (&buf);
string s;
getline(in, s); // s now holds the correct data.
After finding no answer anywhere (not even FastCGI mailing list) I dumped the original fastcgi libraries and tried using fastcgi++ libraries instead. The problem disappeared. There are also other benefits - c++, more features, easier to use.
Use is.read() not is >> ...
Sample from restcgi documentation:
clen = strtol(clenstr, &clenstr, 10);
if (*clenstr)
{
cerr << "can't parse \"CONTENT_LENGTH="
<< FCGX_GetParam("CONTENT_LENGTH", request->envp)
<< "\"\n";
clen = STDIN_MAX;
}
// *always* put a cap on the amount of data that will be read
if (clen > STDIN_MAX) clen = STDIN_MAX;
*content = new char[clen];
is.read(*content, clen);
clen = is.gcount();

HTTP protocol: end of a message body

I built a program that parses the header and I would like to read the message body in case I receive a POST.
For headers, I have been able to look for to determine when the header ends. I am having more issues for the message body. Am I supposed to look at "Content-Length" field to know when to stop reading input? In my current code (below), it will not stop until I hit the red cross (stop loading page) in Firefox.
Here is the code:
size_t n;
unsigned char newChar;
int index = 0;
int capacity = 50;
char *option = (char *) malloc(sizeof(char) * capacity);
while ( ( n = read( req->socket, &newChar, sizeof(newChar) ) ) > 0 ) {
if (newChar == '\0' || newChar == '\n') break; // This is not working
if (index == capacity) {
capacity *= 2;
option = (char *) realloc(option, sizeof(char) * capacity);
assert(option != NULL);
}
option[index++] = newChar;
fprintf(stderr, "%c", newChar);
}
if (index == capacity) {
capacity *= 2;
option = (char *) realloc(option, sizeof(char) * capacity);
assert(option != NULL);
}
option[index] = '\0';
The correct input gets printed, but I wonder why it won't stop until the stop loading button get pressed. I'd like to know if there is any other solution or if I please need to use the "Content-Length" field in the header.
Thank you very much,
Jary
There are a few things to consider. You'll want to consider how you want to handle all of these cases perhaps?
For HTTP protocol 1.0 the connection closing was used to signal the end of data.
This was improved in HTTP 1.1 which supports persistant connections. For HTTP 1.1 typically you set or read the Content-Length header to know how much data to expect.
Finally with HTTP 1.1 there is also the possibility of "Chunked" mode, you get the size as they come and you know you've reached the end when a chunk Size == 0 is found.
Also do you know about libcurl? It will certainly help you having to re-implement the wheel.
This code blocks on the read() waiting for another character which never comes.
Additionally, RFC2616, 3.7.1 states "HTTP applications MUST accept CRLF, bare CR, and bare LF as being representative of a line break in text media received via HTTP. In addition, if the text is represented in a character set that does not use octets 13 and 10 for CR and LF respectively, as is the case for some multi-byte character sets, HTTP allows the use of whatever octet sequences are defined by that character set to represent the equivalent of CR and LF for line breaks."
So you're going to need to catch more than just "\n".

Resources