Sorry scratch my last post, it's way to late =S
But basically I'm having problems sending out the buffer I created. Just need to know where I'm going wrong =( or if theres a better way.
------ Client Sending Username -------
int bufferSize = 32;
char messageBuffer[bufferSize];
char* message;
if (userName.size() > 8)
{
cout << "Invalid username : Greater than 8 characters" << endl;
}
else
{
switch(regType)
{
case(REGISTER):
{
cout << "Registered name: " << userName << endl;
messageBuffer[0] = 1;
messageBuffer[1] = 0;
for (int i = 2; i < (userName.size() + 2); i++)
{
messageBuffer[i] = userName[(i - 2)];
}
for (int i = 0; i < (userName.size() + 2); i++)
{
cout << messageBuffer[i];
}
cout << "<<<< messageBuffer " << endl;
message = &messageBuffer[0];
cout << messageBuffer << endl;
//message[(userName.size() + 2)] = '\0';
int messageLen = userName.size() + 2;
if (send(sock, messageBuffer, messageLen, 0) != messageLen)
DieWithError("send() send an invalid name");
}break;
case(UNREGISTER):
{
}break;
}
}
----------- Server (Receiver)------------
char msgRcvBuffer[RCVBUFSIZE];
int recvMsgSize;
if ((recvMsgSize = recv(clntSocket, msgRcvBuffer, RCVBUFSIZE, 0)) < 0)
DieWithError("recv() failed");
msgRcvBuffer[recvMsgSize] = '\0';
string msgType( msgRcvBuffer );
cout << "Message Type " << msgType << endl; <<<<<< Nothing appears when printed
void handleReg(string message, int socket, string ipAddr)
{
// Remove the Prefix
int startIndex = 2;
// Get the username from the message
string userName = message.substr(startIndex, message.size() - startIndex);
cout << "Username " << userName << endl;
For some reason my message string is just 1... =S What i'm trying to do is just get the message from what was sent from client. I'm just tryin to remove the '1' and '0' from the beginning of the buffer. 1 and 0 aren't characters.
Thanks so much for everyones help =)
The conversion from char* to string treats the string as null-terminated. This doesn’t seem to be the case here – in particular, your char array appears to contain 0 characters, so the string will be cut off at this position.
To circumvent this, you need to pass the valid range of characters to the string constructor, in place of only the start pointer:
msgType = string(msgRcvBuffer, msgRcvBuffer + recvMsgSize);
If msgRcvBuffer is of size RCVBUFSIZE then msgRcvBuffer[recvMsgSize] = '\0'; is going to be writing beyond the end of the buffer I think.
Use the std::string constructor that takes a buffer and buffer size parameter:
msgType = std::string(msgRcvBuffer, recvMsgSize);
Related
I am trying to parse the data obtained from GET / POST request using C in a MCU based project. I must say upfront that I haven't work with c and c++ for some time, so any suggestion is welcome.
So, the data arriving the MCU has the following markup:
HTTP/1.1
Authorization: Basic blablah
Content-Type: application/json
{
redLedBrightness:50,
redLedIsOn:true,
greenLedBrightness:70,
greenLedIsOn:false,
}
where the end beginnning of the lines are given respectively by \r and \n.
My approach entailed processing line by line, and searching the corresponding key (e.g. Authorization or redLedBrightness) and its value (e.g. blahblah or 50). I wrote the following code, which seemed to be working fine in the compiler I was using, but not in the MCU.
One of problems seems to be in the statement *tempInDataP = *index; since the MCU stops hanging if I comment it out. Of course I need this line, but I cannot figure out where the problem(s) is (are). I suspect the compiler I am using is not showing all the errors.
Here is an adaption of the code:
#include <iostream>
#include <string>
#include <cstring>
#define IN_DATA_SIZE 100
#define TEMP_IN_DATA_SIZE 10
using namespace std;
char mock[] = "Authentication:YERL90,\r\nredLedBri:400,\r\nredLedOn:true\r\n";
char * mockP = mock;
char inData[IN_DATA_SIZE];
char * inDataP = inData;
char tempInData[TEMP_IN_DATA_SIZE];
char * tempInDataP = tempInData;
const char * auth = "YERL90";
bool isAuthenticated = false;
void printBuffer(char * buf) {
for (char *p = buf; *p; p++) {
cout << *p;
}
}
void resetBuffer(char * buf, int _size)
{
memset(buf, 0, _size);
}
/**
* Returns true if keyWord exists and update the variable tempInData
* with the response / value
*/
bool parseResponse(char * res, const char * keyWord, int dataShift ) {
cout << "\nParsing:" << res << endl;
char * index;
// Reset temp in data buffer and its pointer
resetBuffer(tempInData, TEMP_IN_DATA_SIZE);
tempInDataP = &tempInData[0];
// Search for a member /keyword inside the response
index = strstr(res, keyWord);
if (index) {
// Keyword exists in the response
// Move the index to the beginning of the value (key:value)
index = index + strlen(keyWord) + dataShift;
while ((*index != '\r') && (*index != ',')) {
*tempInDataP = *index;
tempInDataP++;
index++;
}
// Terminate the string with a null
*tempInDataP = '\0';
return true;
} else {
cout << "-bul" << endl;
//Object was not found
return false;
}
}
bool checkAuth(const char * _auth) {
if (strcmp (auth, _auth) == 0)
return true;
else
return false;
}
int main()
{
while(*mockP) {
// Simulating, reading data from the channel
*inDataP=*mockP;
//Parsing line by line
if (*inDataP == '\n') {
//Check for authentication if not done yet
if(!isAuthenticated) {
cout << "Authenticating ..." << endl;
if(parseResponse(inData, "Authentication", 1)) {
cout << "Key exists ..." << endl;
if(checkAuth(tempInData)) {
cout << "Correct Password" << endl;
isAuthenticated = true;
} else {
cout << "Password Invalid" << endl;
// Prepare headers
// Send response with unauthorized access
// stop connection
break;
}
} else {
cout << "Data not found" << endl;
}
} else {
// User is logged in
cout << "User is logged in" << endl;
if(parseResponse(inData, "redLedBri", 1)) {
cout << "Data exists:" << tempInData << endl;
// update local variables
} else {
cout << "Data not found" << endl;
}
}
resetBuffer(inData, IN_DATA_SIZE);
inDataP = &inData[0];
}
else {
inDataP++;
}
mockP++;
}
//close connection and log the user out
return 0;
}
I am open for other alternatives, as this implementation seems a bit cumbersome depending on the JSON file sent to the MCU.
I see potential buffer overruns. You trust your input too much. You assume it will end with '\r' or ',' characters, and if it doesn't then you will overrun the bounds of your array(s) and access arbitrary memory.
At the very least, pass the maximum length with each array pointer, and check in each loop iteration that you NEVER access an element beyond the last address of the array.
First of all, I very much appreciate any help you are willing to provide. I am new to C++ and have been scouring this website as well as other resources for the solution to my problem.
Further, this was indeed a portion of a homework assignment. However, the assignment has been turned in (upsettingly, without getting this code to work). It would be great to get an explanation for what the problem in my specific code is and how to fix my current code, rather than the just rewritten code with a different way to approach to problem. I certainly found plenty of ways to solve this problem on this wonderful site!
I am getting no errors with my code, however the reversal output is not showing the reversed character array. This results in my little program here always showing "Your string is not a palindrome! :(" no matter what the input is.
#include <iostream>
#include <string>
using namespace std;
int isPalindrome(char *input, char *input2);
char reverseString(char *input);
int main ()
{
char input[50];
char input2[50];
cout << "Please enter a string of characters no larger than 50." << endl;
cin.getline(input, 50);
reverseString(input);
cout << "The reversed string is " << input2 << endl;
int result;
result = isPalindrome(input, input2);
if(result == 0)
cout << "Your string is a palindrome!" << endl;
else
cout << "Your string is not a palindrome! :( " << endl;
return 0;
}
int isPalindrome(char* first, char* second)
{
if (*first == *second)
return 0;
else
return 1;
}
char reverseString(char* input2)
{
int size = sizeof(input2);
for (int i = 0; i < (size/2); i ++)
swap(input2[i], input2[size-i-1]);
return *input2;
}
Again, I appreciate any help you can provide! I apologize if this is a simple error that I am overlooking and should have been able to find elsewhere.
Checking for a palindrome does not take this much effort.
bool isPalindrome(const char* s) // this function is self-contained.
{ // the caller does not need to provide
size_t n = strlen(s); // any pre-computed value.
if (n == 0)
return false;
const char* e = s + n - 1;
while (s < e)
if (*s++ != *e--)
return false;
return true;
}
int main ()
{
char input[50];
cout << "Please enter a string of characters no larger than 50." << endl;
cin.getline(input, 50);
bool result = isPalindrome(input);
cout << "Your string is"
<< ((result) ? " " : " not ")
<< "a palindrome!\n";
return (result) ? 1 : 0;
}
In your reverseString function:
char reverseString(char* input2)
{
int size = sizeof(input2); // <-- ?? sizeof(char*) != strlen(input2)
size_t size = strlen(input2); // <-- should read.
for (int i = 0; i < (size/2); i ++)
swap(input2[i], input2[size-i-1]);
return *input2; // what's this? returning first char? why?
}
I'm writing a registry generator as a part of a bigger program. I'm very new in C++, but good at other programming languages like PHP.
I'll start by providing the code of the problematic function:
void generacionAleatoria() {
string r_marca, r_nom, r_apellido;
char r_patente[6];
int num_rand;
registroAuto r_auto;
string nombres[8] = {
"Juan", "Pedro", "Roberto", "Miguel", "Guillermo", "Emilio", "Roque", "Gustavo"
} ;
string apellidos[8] = {
"Messi", "Maradona", "Gardel", "Heredia", "Pimpinela", "Nadal", "Mascherano", "Troilo"
};
string marcas[12] = {
"Volvo", "Renault", "Audi", "Ford", "Fiat", "Chevrolet", "Nissan", "Volkswagen", "Mercedes Benz", "Rolls Royce", "Delorean", "Aston Martin"
};
char letras_patentes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char numeros_patentes[] = "0123456789";
for (int i = 0; i < cantidad_autos; i++) {
r_marca = marcas[rand() % (sizeof(marcas)/sizeof(marcas[0]) - 1)];
r_nom = nombres[rand() % (sizeof(nombres)/sizeof(nombres[0]) - 1)];
r_apellido = apellidos[rand() % (sizeof(apellidos)/sizeof(apellidos[0]) - 1)];
for(int m = 0; m < 3; ++m) {
r_patente[m] = letras_patentes[rand() % (sizeof(letras_patentes) - 1)];
}
for(int n = 3; n < 6; n++) {
r_patente[n] = numeros_patentes[rand() % (sizeof(numeros_patentes) - 1)];
}
strcpy(r_auto.patente,r_patente);
strcpy(r_auto.marca,r_marca.c_str());
strcpy(r_auto.apellido,r_apellido.c_str());
strcpy(r_auto.nom,r_nom.c_str());
fwrite(&r_auto,sizeof(registroAuto),1,archivo);
if (ver_variables_testeo) {
//cout << (i+1) << ") " << r_auto.patente<<endl;
cout << (i+1) << ") " << r_auto.marca << " - " << r_auto.patente << " - " << r_auto.nom << " " << r_auto.apellido << endl; //Para testear
}
}
}
This creates 100 structs of the following type:
struct registroAuto {
char marca[15];
char patente[6];
char nom[25];
char apellido[25];
};
In case you're wondering, this is meant to be a registry of Uber drivers and their cars: brand, license plate, name and surname. Well, it's not really a registry, it's college homework.
The problem is that when I print out the contents of my new struct, the license plate and the name will be together, as in:
100) Fiat - KWQ293Maria - Maria Gardel
You can see by the position of the hyphens, that the license plate is now "KWQ293Maria", even though it is an array of 6 chars!
A reminder of the cout command:
cout << (i+1) << ") " << r_auto.marca << " - " << r_auto.patente << " - " << r_auto.nom << " " << r_auto.apellido << endl;
I did some tests, but I don't know what to do with the results.
1: commenting out the strcopy of the name fixes the issue
strcpy(r_auto.patente,r_patente);
strcpy(r_auto.marca,r_marca.c_str());
strcpy(r_auto.apellido,r_apellido.c_str());
//strcpy(r_auto.nom,r_nom.c_str());
As you can see, this is the last of the 4 statements in my original code, so I don't know why it would affect r_auto.patente.
Can you please help me? I'm guessing there's a key concept of char array handling that I missed out on in class :-(
When using character arrays as strings they need to be terminated by a null character '\0'. So when you construct your number-plate you need to make the array 7 characters long.
struct registroAuto {
char marca[15];
char patente[7]; // 6 for numbers, 1 for terminator '\0'
char nom[25];
char apellido[25];
};
Same with your working variable:
char r_patente[7];
And you need to manually add the null-terminator when you create the number:
for(int m = 0; m < 3; ++m) {
r_patente[m] = letras_patentes[rand() % (sizeof(letras_patentes) - 1)];
}
for(int n = 3; n < 6; n++) {
r_patente[n] = numeros_patentes[rand() % (sizeof(numeros_patentes) - 1)];
}
r_patente[6] = '\0'; // add the null terminator
my program compiles without error and appears to run through all of the steps correctly. It is supposed to make a php call and return data. tcpdump does show the request going out so popen is being executed, but the receiving party never updates.
The only discrepancy I can find, is that the command variable appears to be missing data.
# .trol.o
market max price is 0.00638671 at position 0
php coin.php 155 0.006387
0.00638672
the second line in the output is the command I am sending to popen
cout << command << endl; -> php coin.php 155 0.006387
that number is supposed to be the same as the one under it 0.00638672
The number 6 and the number 2 have been chopped off somehow.
How do I get the correct data into my popen command?
code:
void mngr(){
//vector defs
vector<std::string> buydat;
vector<std::string> markdat;
vector<std::string> pricedat;
vector<std::string> purchaseid;
vector<double> doublePdat;
vector<double> doubleMdat;
doublePdat.reserve(pricedat.size());
doubleMdat.reserve(markdat.size());
char buybuff[BUFSIZ];
char command[70];
char sendbuy[12];
buydat = getmyData();
markdat = getmarketbuyData();
//string match "Buy" and send results to new vector with pricedat.push_back()
for(int b = 2; b < buydat.size(); b+=7){
if ( buydat[b] == "Buy" ) {
pricedat.push_back(buydat[b+1]);
}
}
transform(pricedat.begin(), pricedat.end(), back_inserter(doublePdat), [](string const& val) {return stod(val);});
transform(markdat.begin(), markdat.end(), back_inserter(doubleMdat), [](string const& val) {return stod(val);});
auto biggestMy = std::max_element(std::begin(doublePdat), std::end(doublePdat));
std::cout << "my max price is " << *biggestMy << " at position " << std::distance(std::begin(doublePdat), biggestMy) << std::endl;
auto biggestMark = std::max_element(std::begin(doubleMdat), std::end(doubleMdat));
std::cout << "market max price is " << *biggestMark << " at position " << std::distance(std::begin(doubleMdat), biggestMark) << std::endl;
if (biggestMy > biggestMark){
cout << "Biggest is Mine!" << endl;
}
else if (biggestMy < biggestMark){
//cout << "Biggest is market!";
*biggestMark += 0.00000001;
sprintf(sendbuy,"%f",*biggestMark);
sprintf(command, "php coin.php 155 %s",sendbuy);
FILE *markbuy = popen(command, "r");
if (markbuy == NULL) perror ("Error opening file");
while(fgets(buybuff, sizeof(buybuff), markbuy) != NULL){
size_t h = strlen(buybuff);
//clean '\0' from fgets
if (h && buybuff[h - 1] == '\n') buybuff[h - 1] = '\0';
if (buybuff[0] != '\0') purchaseid.push_back(buybuff);
}
cout << command << endl;
cout << *biggestMark << endl;
}
}
I would try to use long float format instead of float as the type of biggestMark should be evaluated as iterator across doubles. I mean try to change sprintf(sendbuy,"%f",*biggestMark); to sprintf(sendbuy,"%lf",*biggestMark);. Hope this would help.
I'm not sure I understand what the bug below is
const char* packs[] = {"zero","one","two","three","four",..."twelve"} //abbreviated for post
struct packinfo {
char* data;
int len;
};
std::vector<packinfo> k;
k.reserve(10000);
for (int i = 0; i < 10; ++i) {
const char* data = packs[i];
packinfo tobuf;
tobuf.data = new char[strlen(data)];
tobuf.len = strlen(data);
memcpy(tobuf.data, data, strlen(data));
k.push_back(tobuf);
}
for (int i = 0; i < k.size(); ++i)
std::cout << "k[" << i << "]: " << k[i].data << ", ";
std::cout << std::endl;
for (int i = 0; i < k.size(); ++i) {
packinfo& pack = k[i];
bool foo = (i < 5);
if (foo) std::cout << "inspecting k[" << i << "]: " << k[i].data << std::endl;
delete pack.data;
if (!foo) {
k.erase(k.begin(), k.begin() + i);
packinfo tobuf;
const char* data = packs[10];
tobuf.data = new char[strlen(data)];
tobuf.len = strlen(data);
memcpy(tobuf.data, data, strlen(data));
break; //intentionally forgot to push_back
}
}
for (int i = 0; i < k.size(); ++i)
std::cout << "k[" << i << "]: " << k[i].data << ", ";
std::cout << std::endl
;
The output of running the above is the following:
k[0]: zero, k[1]: one, ... , k[9]: nine, //all as expected
inspecting k[0]: zero
inspecting k[1]: one
...
inspecting k[4]: four
k[0]: ten^], k[1]: six, k[2] seven, k[3]: eight, k[4]L nine, //gargabe crept in
How did garbage creep into the beginning of the vector?
strlen gives you the length of characters in a nul-terminated string wihtout counting the nul-termination character. So you are dynamically allocating a data buffer that is too short to hold the target string:
tobuf.data = new char[strlen(data)]; // too short by 1
When you fill it using memcpy, there is no space for a null-termination for the string, and you wouldn't copy it if there was anyway, because the array is too short:
memcpy(tobuf.data, data, strlen(data)); // tobuf.data is not nul-terminated
When you attempt to read it as if it were a nul terminated string, you go out of bounds.
The immediate fix would be to use strlen(data) +1, but what you really should do is avoid the whole problem by replacing packinfo by std::string.
std::vector<std::string> k;
k.reserve(10000);
The problem is these lines:
tobuf.data = new char[strlen(data)];
tobuf.len = strlen(data);
memcpy(tobuf.data, data, strlen(data));
Where do you add space for the string terminator?
C++ have the std::string class, you should really use it as it will help you with these kind of problems.