Using strtok and get "cannot convert 'char*' to 'char**' in assignment" - c++

I am trying to make a program that reads a string from a file in SPIFFS with 4 tab-separated things and then processes it into four char arrays to be used in another function. However, I get the error cannot convert 'char*' to 'char**' in assignment. Is there any idea why? Here's my code:
#include <string.h>
#include "FS.h"
#include "AdafruitIO_WiFi.h"
char *ssid;
char *pass;
char *aiduser;
char *aidkey;
// comment out the following two lines if you are using fona or ethernet
#include "AdafruitIO_WiFi.h"
//AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);
void setupWifi(char* *aiduser, char* *aidkey, char* *ssid, char* *pass){
#define WIFIFILE "/config.txt"
int addr = 0;
bool spiffsActive = false;
if (SPIFFS.begin()) {
spiffsActive = true;
}
File f = SPIFFS.open(WIFIFILE, "r");
String str;
while (f.position()<f.size())
{
str=f.readStringUntil('\n');
str.trim();
}
// Length (with one extra character for the null terminator)
int str_len = str.length() + 1;
// Prepare the character array (the buffer)
char char_array[str_len];
// Copy it over
str.toCharArray(char_array, str_len);
const char s[2] = {9, 0};
/* get the first token */
aiduser = strtok(char_array, s);
aidpass = strtok(NULL, s);
ssid = strtok(NULL, s);
pass = strtok(NULL, s);
/* walk through other tokens
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, s);
}*/
// RESULT: A thingy
}
void setup(){
setupWifi(&aiduser, &aidkey, &ssid, &pass);
AdafruitIO_WiFi io(aiduser, aidkey, ssid, pass);}
Also, I can't run the setupWifi function unless it is in setup or loop, but I can't make it in another setup because this is #included into another main file.

You get this error because of this:
void setupWifi(char* *aiduser, char* *aidkey, char* *ssid, char* *pass)
{
...
aiduser = strtok(char_array, s);
aidpass = strtok(NULL, s);
ssid = strtok(NULL, s);
pass = strtok(NULL, s);
}
This variables are double pointers, strtok returns a pointer to char, those
are not compatible types.
Because strtok returns char_array + some_offset and char_array is a local
variable in setupWifi, you need to do a copy for each of them and return the
copy instead. You can do it with strdup.
*aiduser = strdup(strtok(char_array, s));
*aidpass = strdup(strtok(NULL, s));
*ssid = strdup(strtok(NULL, s));
*pass = strdup(strtok(NULL, s));
I encourage you to always check the return value of strdup, because it can
return NULL.1
If your system does not have strdup, then you can write your own:
char *strdup(const char *text)
{
if(text == NULL)
return NULL;
char *copy = calloc(strlen(text) + 1, 1);
if(copy == NULL)
return NULL;
return strcpy(copy, text);
}
One last thing:
void setupWifi(char* *aiduser, char* *aidkey, char* *ssid, char* *pass);
It looks really awkward, never seen declaring double pointer this way. Much
easier to read would be
void setupWifi(char **aiduser, char **aidkey, char **ssid, char **pass);
Fotenotes
1While the syntax is correct, I still consider this bad practice,
because you should always check the return values of functions that return
pointers. If they return NULL, you cannot access the memory. This adds a
little bit of more code, but your program will not die of segfaults and it can
recover from the errors.
I'd also change your function to return 1 on success, 0 otherwise:
int parse_and_set(char *txt, const char *delim, char **var)
{
if(delim == NULL || var == NULL)
return 0;
char *token = strtok(txt, delim);
if(token == NULL)
return 0;
token = strdup(token);
if(token == NULL)
return NULL;
*var = token;
return 1;
}
void init_parse(char ***vars, size_t len)
{
for(size_t i = 0; i < len; ++i)
**(vars + i) = NULL;
}
int cleanup_parse(char ***vars, size_t len, int retval)
{
for(size_t i = 0; i < len; ++i)
{
free(**(vars + i));
**(vars + i) = NULL;
}
}
int setupWifi(char **aiduser, char **aidkey, char **ssid, char **pass)
{
if(aiduser == NULL || aidkey == NULL || ssid == NULL || pass == NULL)
return 0;
...
/* get the token token */
char **vars[] = { aiduser, aidkey, ssid, pass };
size_t len = sizeof vars / sizeof *vars;
init_parse(vars, len);
if(parse_and_set(char_array, s, aiduser) == 0)
return cleanup_parse(vars, len, 0);
if(parse_and_set(NULL, s, aidpass) == 0)
return cleanup_parse(vars, len, 0);
if(parse_and_set(NULL, s, ssid) == 0)
return cleanup_parse(vars, len, 0);
if(parse_and_set(NULL, s, pass) == 0)
return cleanup_parse(vars, len, 0);
...
return 1;
}

Related

How does one locate a pointer error?

I am attempting to create a program to create a Markov chain but I am having pointer problems. When I run the Program I get a segmentation fault.
#include <stdio.h>
#include <cstring>
#include <cstdlib>
struct word;
struct nextword
{
word* sourceword;
word* next = 0;
};
int wordcount;
struct word
{
char* wordstr;
struct word* next = 0;
nextword* followingword = 0;
int nextwordcount = 0;
};
int main()
{
word* firstword = 0;
char * buffer = 0;
long length;
FILE * f = fopen ("alice.txt", "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = (char *)malloc (length);
if (buffer)
{
fread (buffer, 1, length, f);
}
fclose (f);
}
if (buffer)
{
char wordbuffer[500];
int fileindex = 0;
while(fileindex < length-1)
{
int wordindex = 0;
while(buffer[fileindex] != ' ')
{
wordbuffer[wordindex] = buffer[fileindex];
wordindex++;
fileindex++;
}
if(wordindex != 0)
{
wordbuffer[wordindex] = '\0';
word* newword = (word*)malloc(sizeof(word));
char* newwordstr = (char*)malloc((strlen(wordbuffer)+1)*sizeof(char));
strcpy(newword->wordstr, newwordstr);
if(!firstword)
{
firstword = newword;
}
else
{
word* testword = firstword;
while(!testword->next)
{
testword = (testword->next);
}
testword->next = newword;
printf(newword->wordstr);
}
}
return 0;
}
}
else
{
return 1;
}
}
I attempted to remove the file reading part and replace it with a hard coded string, but the problem remained.
You might want to read about STL and use a list. Or use a C list, see a couple of examples,
Adding node in front of linklist
How to pop element from tail in linked list?
Trying to make linkedlist in C
Several problems. Fixed some. compiles.
I have annotated the code with places where you need to fix bounds checking, and the big problem was likely the strcpy to the struct word->wordstr uninitialized char*,
#include <stdio.h>
#include <cstring>
#include <cstdlib>
struct word;
struct nextword
{
word* sourceword;
word* next = 0;
};
int wordcount;
struct word
{
char* wordstr; //what do you think this pointer points to?
struct word* next = 0;
nextword* followingword = 0;
int nextwordcount = 0;
};
int main()
{
FILE* fh = NULL;
word* firstword = 0;
char* buffer = 0;
char* fname = "alice.txt";
long length = 0; //you did not initialize length
if ( (fh = fopen ("alice.txt", "rb")) )
{
//why not use fstat to get file size?
//why not use mmap to read file?
fseek (fh, 0, SEEK_END);
length = ftell (fh); //ok, length set here
fseek (fh, 0, SEEK_SET);
if( (buffer = (char *)malloc (length)) )
{
fread (buffer, 1, length, fh);
}
fclose (fh);
}
else
{
printf("error: cannot open %s",fname);
exit(1);
}
printf("read %s, %ld\n",fname,length);
if (!buffer)
{
printf("error: cannot open %s",fname);
exit(1);
//use exit, to return from main() //return 1;
}
//already checked buffer
{
int fileindex = 0;
//put wordbuffer after fileindex, avoids stackoverflow overwrite
char wordbuffer[500]; //500 bytes on stack, initialize?
memset(wordbuffer,0,sizeof(wordbuffer));
while(fileindex < length-1)
{
int wordindex = 0;
//several errors in this line, check for null terminator,
//check for newline, tab, basically any whitespace
//while(buffer[fileindex] != ' ')
while( buffer[fileindex] && buffer[fileindex] != ' ' )
{
wordbuffer[wordindex] = buffer[fileindex];
wordindex++;
fileindex++;
//here is another error, do not overflow your stack based buffer
if( wordindex>sizeof(buffer)-1 ) break; //do not overflow buffer
}
wordbuffer[wordindex] = '\0'; //terminate wordbuffer
//since you chose wordindex signed, you want it > 0
if(wordindex > 0)
{
//use a constructor
word* newword = (word*)malloc(sizeof(word));
//use a constructor
//or just use strdup, since it is just a cstring
char* newwordstr = strdup(wordbuffer);
//no, just set pointer to the above allocated string
//strcpy(newword->wordstr, newwordstr);
newword->wordstr = newwordstr;
if(!firstword)
{
firstword = newword;
}
else
{
word* testword = firstword;
while(!testword->next)
{
testword = (testword->next);
}
testword->next = newword;
printf(newword->wordstr);
}
}
return 0;
}
}
exit(0); //done
}
This compiles and runs without error, you need to look up linked list handling. You should implement a linked list, and then add word elements to list.

How do I modify strcat so that it wouldn't edit str1

Why does strcat gives me its version of str1? As far as I know there has to be & thing before paramatater in function prototype and implementation if you want to get it editted, but I don't see it here.
char *strcat( char *str1, const char *str2 );
How do I edit this function so that it would only return new string but leave out the ones I give it?
My try
char *strApp(char *dest, const char *src)
{
size_t i,j;
size_t k = 0;
for (i = 0; dest[i] != '\0'; i++);
char rdest[100];
do {
rdest[k] = dest[k];
} while(++k<=i);
for (j = 0; src[j] != '\0'; j++)
rdest[i+j] = src[j];
rdest[i+j] = '\0';
return rdest;
}
It damages second string. Could anyone give me safe and correct version? Thanks in advance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *strApp(const char *s1, const char *s2)
{
char *pointer = malloc(strlen(s1) + strlen(s2) + 1);
if (pointer == NULL)
{
perror("failed to allocate memory");
exit(EXIT_FAILURE);
}
return strcat(strcpy(pointer, s1), s2);
}
int main()
{
char *s1 = "original";
char *s2 = " modified";
char *s3 = strApp(s1, s2);
printf("%s\n", s1);
printf("%s\n", s2);
printf("%s\n", s3);
free(s3);
return 0;
}
Just trying to point out you don't need to completely rewrite strcat() to get what you want.
strcat is, by definition, altering the target. If you don't want to, you should make a copy yourself in a target memory location you allocate yourself.
You've tagged your question with both C and C++. I'm providing a C solution. Adjustments may be needed for C++.
#include <stdlib.h>
#include <string.h>
char* strdupcat(const char* s1, const char* s2) {
size_t s1_len = strlen(s1);
size_t s2_len = strlen(s2);
char* s = malloc(s1_len + s2_len + 1);
if (s == NULL)
return NULL;
{
char* s_end = s;
s_end = mempcpy(s_end, s1, s1_len);
s_end = mempcpy(s_end, s2, s2_len);
*s_end = '\0';
}
return s;
}
Example usage:
#include <stdio.h>
int main() {
char* s = strdupcat("abc", "def");
if (s == NULL) {
perror("Can't concatenate");
return EXIT_FAILURE;
}
puts(s);
free(s);
return EXIT_SUCCESS;
}
This function is used similarly to strdup.
DESCRIPTION
The strdupcat() function returns a pointer to a new string which is a duplicate of the string s1 with a duplicate of string s2 appended. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
RETURN VALUE
The strdupcat() function returns a pointer to the duplicated string, or NULL if insufficient memory was available.
ERRORS
ENOMEM Insufficient memory available to allocate the new string.
You can use strerror or perror to obtain an error message when strdupcat() returns NULL.
Here's a version that accepts an arbitrary number of arguments:
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
char* strdupcatmany(int dummy, ...) {
#define strdupcatmany(...) strdupcatmany(0, __VA_ARGS__, NULL)
size_t len = 0;
char* s;
char* s_dst;
const char* s_src;
va_list ap;
va_start(ap, dummy);
while (1) {
s_src = va_arg(ap, const char*);
if (s_src == NULL)
break;
len += strlen(s_src);
}
va_end(ap);
s = malloc(len + 1);
if (s == NULL)
return NULL;
s_dst = s;
va_start(ap, dummy);
while (1) {
s_src = va_arg(ap, const char*);
if (s_src == NULL)
break;
s_dst = stpcpy(s_dst, s_src);
}
va_end(ap);
*s_dst = '\0';
return s;
}
For example,
#include <stdio.h>
int main() {
char* s = strdupcatmany("abc", "def", "ghi");
if (s == NULL) {
perror("Can't concatenate");
return EXIT_FAILURE;
}
puts(s);
free(s);
return EXIT_SUCCESS;
}
Note: I don't know how portable __VA_ARGS__ args is.

Readline: How to list all autocomplete matches on double tab?

I'm using "readline" library to create a console interface for my program. I'm able to autocomplete words using tab, but when I have words that share the same prefix like (car, card, carbon) it always chooses the shortest one. Here's my program (mostly taken from link):
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <iostream>
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wifes"};
void *xmalloc (int size)
{
void *buf;
buf = malloc (size);
if (!buf)
{
fprintf (stderr, "Error: Out of memory. Exiting.\n");
exit (1);
}
return buf;
}
char *dupstr (const char *str)
{
char *temp;
temp = (char *) xmalloc (strlen (str) + 1);
strcpy (temp, str);
return (temp);
}
char *my_generator (const char *text, int state)
{
static int list_index, len;
const char *name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while (name = words[list_index])
{
list_index++;
if (strncmp (name, text, len) == 0) return dupstr (name);
}
// If no names matched, then return NULL.
return ((char *) NULL);
}
static char **my_completion (const char *text, int start, int end)
{
char **matches = (char **) NULL;
if (start == 0)
{
matches = rl_completion_matches ((char *) text, &my_generator);
}
else rl_bind_key ('\t', rl_abort);
return matches;
}
int main (int argc, char *argv[])
{
char *buf;
rl_attempted_completion_function = my_completion;
while ((buf = readline(">> ")) != NULL)
{
rl_bind_key ('\t', rl_complete);
if (strcmp (buf, "exit") == 0) break;
else if (buf[0] == '\0') continue;
else
{
std::cout << buf << std::endl;
add_history (buf);
}
}
free (buf);
return 0;
}
Is it possible to list all matches on double tab just like in ubuntu terminal?
I managed to get it to work by commenting out these two lines:
rl_bind_key ('\t', rl_complete);
and:
else rl_bind_key ('\t', rl_abort);
The default completion behaviour of readline works exactly like in ubuntu terminal, one tab to complete and two tabs to list possible completions. Not sure though what's the default completion function that's binded with the tab key, from the documentation i thought it was rl_possible_completions but it didn't give the same results.
Also i added the following line to my_completion function to prevent adding space at the end of the matched word:
rl_completion_append_character = '\0';
I removed dupstrfunction it and replaced it with the native strdup function instead (this has nothing to do with the auto complete problem, it's just to remove unnecessary code).
This is the final code:
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <iostream>
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wives"};
// Generator function for word completion.
char *my_generator (const char *text, int state)
{
static int list_index, len;
const char *name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while (name = words[list_index])
{
list_index++;
if (strncmp (name, text, len) == 0) return strdup (name);
}
// If no names matched, then return NULL.
return ((char *) NULL);
}
// Custom completion function
static char **my_completion (const char *text, int start, int end)
{
// This prevents appending space to the end of the matching word
rl_completion_append_character = '\0';
char **matches = (char **) NULL;
if (start == 0)
{
matches = rl_completion_matches ((char *) text, &my_generator);
}
// else rl_bind_key ('\t', rl_abort);
return matches;
}
int main (int argc, char *argv[])
{
char *buf;
rl_attempted_completion_function = my_completion;
while ((buf = readline(">> ")) != NULL)
{
// rl_bind_key ('\t', rl_complete);
if (strcmp (buf, "exit") == 0) break;
else if (buf[0] == '\0')
{
free (buf);
continue;
}
else
{
std::cout << buf << std::endl;
add_history (buf);
}
free (buf);
buf = NULL;
}
if (buf != NULL) free (buf);
return 0;
}
The answer by razzak is almost correct, but this NULL must be added at the end of array of strings:
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wives", NULL};
Some changes for nonwarning compilation in my_generator() function:
while ((name = words[list_index++]))
{
if (strncmp (name, text, len) == 0) return strdup (name);
}

application crashes at first strcat_s

I have tried both strcat and strcat_s, but they both crash. Does anyone know why this happens? I can't find the problem.
Crash: "Unhandled exception at 0x58636D2A (msvcr110d.dll)"
_Dst 0x00ea6b30 "C:\\Users\\Ruben\\Documents\\School\\" char *
_SizeInBytes 260 unsigned int
_Src 0x0032ef64 "CKV" const char *
available 228 unsigned int
p 0x00ea6b50 "" char *
Code:
#include <Windows.h>
#include <strsafe.h>
extern "C"
{
char* GetFilesInFolders(LPCWSTR filedir, char* path)
{
char* files = "";
char DefChar = ' ';
char* Streepje = "-";
bool LastPoint = false;
WIN32_FIND_DATA ffd;
TCHAR szDir[MAX_PATH];
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError = 0;
StringCchCopy(szDir, MAX_PATH, filedir);
hFind = FindFirstFile(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
return "";
do
{
DWORD attributes = ffd.dwFileAttributes;
LPCWSTR nm = ffd.cFileName;
char name[260];
WideCharToMultiByte(CP_ACP,0,ffd.cFileName,-1, name,260,&DefChar, NULL);
for (int i = 0; i <= 260; i++)
{
if (name[i] == '.')
LastPoint = true;
else if (name[i] == ' ')
break;
}
if (LastPoint == true)
{
LastPoint = false;
continue;
}
if (attributes & FILE_ATTRIBUTE_HIDDEN)
{
continue;
}
else if (attributes & FILE_ATTRIBUTE_DIRECTORY)
{
char* newfiledir = "";
char* newpath = path;
char* add = "\\";
char* extra = "*";
strcat_s(newpath, sizeof(name), name);
strcat_s(newpath, sizeof(add), add);
puts(newpath);
strcpy_s(newfiledir, sizeof(newpath) + 1, newpath);
strcat_s(newfiledir, sizeof(extra) + 1, extra);
puts(newfiledir);
size_t origsize = strlen(newfiledir) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, newfiledir, _TRUNCATE);
LPCWSTR dir = wcstring;
GetFilesInFolders(dir, newpath);
}
else
{
char* file = path;
strcat_s(file, sizeof(name), name);
puts(file);
strcat_s(files, sizeof(file), file);
strcat_s(files, sizeof(Streepje), Streepje);
puts(files);
}
}
while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
return files;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char* path = "C:\\Users\\Ruben\\Documents\\School\\";
char* filedir = "C:\\Users\\Ruben\\Documents\\School\\*";
size_t origsize = strlen(filedir) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, filedir, _TRUNCATE);
LPCWSTR dir = wcstring;
char* files = GetFilesInFolders(dir, path);
return 0;
}
Extra info: I don't want to use boost or strings and I want to keep this in unicode (default).
You assign a const char* to files, then attempt to append to it.
char* files = "";
// ...
strcat_s(files, sizeof(file), file);
You cannot modify a constant string literal.
I would recommend that you turn on compiler warnings and make sure to look at them. This would warn you about assigning a const char* to a char*. To fix it, you might have changed files to be const, which would then cause your strcpy_s to no longer compile.
It looks like you don't understand how variables are stored in memory or how pointers work. In your _tmain() you have char * path pointing to a constant string literal, which you pass into GetFilesInFolders(), where it gets modified. Compilers tend to allow char *s to point at constant strings for backward compatibility with old C programs. You cannot modify these. You cannot append to them. The compiler (generally) puts these in a read-only segment. That's one reason why you're getting an exception.
Your whole GetFilesInFolders() is wrong. And as DarkFalcon pointed out, you haven't allocated any space anywhere for files, you have it pointing to a constant string literal.
Get "The C++ Programming Language" and read chapter 5.

making the Websocket using the c++ server

I was making the server in c++ to connect to WebSocket but somehow, it was not connecting with the websocket. The WebSocket is showing the connection is closed and there is also some problem in the c++ server, as on second call to the server from WebSocket, it is showing the following error - double free or corruption (out). I have spend a lot of time on it. Here is the code:
c++
#include<iostream>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
using namespace std;
string getConnectionKey(char*);
void acceptConnection(int, const char*);
void readConnection(int);
void bail(char*);
string executeShellCommand(const string&);
string getBase64Encoded(string);
char *getClientKey(char*);
string getSHA1Hash(string);
int main()
{
char srvr_adr[] = "127.0.0.1";
char srvr_port[] = "9099";
struct sockaddr_in adr_srvr;
struct sockaddr_in adr_clnt;
socklen_t len_inet;
int s; // Server Socket
int c; // Client Socket
int z;
char *data;
char readdata[256];
int count = 2;
data = (char*)malloc(sizeof(char)*128);
s = socket(PF_INET, SOCK_STREAM, 0);
if(s == -1)
bail("socket()");
memset(&adr_srvr,0,sizeof(adr_srvr));
adr_srvr.sin_family = AF_INET;
adr_srvr.sin_port = htons(atoi(srvr_port));
if( strcmp(srvr_adr,"*")!=0)
{
adr_srvr.sin_addr.s_addr = inet_addr(srvr_adr);
if(adr_srvr.sin_addr.s_addr == INADDR_NONE)
bail(" INVALID ADRESS \n");
}
else /* WILD ADDRESS*/
adr_srvr.sin_addr.s_addr = INADDR_ANY;
len_inet = sizeof adr_srvr;
z = bind(s,(struct sockaddr*)&adr_srvr, len_inet);
if(z==-1)
bail("bind(2)");
z = listen(s,10);
if(z==-1)
bail("listen(2)");
for(;;)
{
len_inet = sizeof(adr_clnt);
c = accept(s, (struct sockaddr*)&adr_clnt,&len_inet);
if(c==-1)
bail("accept(2)");
readConnection(c);
close(c);
}
return 0;
}
void readConnection(int c)
{
int z;
char readdata[256];
// READING
z = read(c,readdata, sizeof(readdata)-1);
if(z==-1)
bail("read(2)");
else if(strlen(readdata)>0)
printf(" READ \n%s\n", readdata);
string key = getConnectionKey(readdata);
cout<<" KEY "<<key<<endl;
acceptConnection(c, key.c_str());
}
void acceptConnection(int c, const char *key)
{
int z;
char response[] = "HTTP/1.1 101 Switching Protocols\nUpgrade: websocket\nConnection: Upgrade\nSec-WebSocket-Accept: ";
char *output;
output = (char*)malloc( sizeof(char) * ( strlen(key) + strlen(response) + 1) );
strcat(output, response);
strcat(output, key);
cout<<" output "<<output<<endl;
// WRITING
z = write(c, output, strlen(output));
if(z == -1)
bail("write(2)");
printf(" Connection Done \n");
}
string getConnectionKey(char *str)
{
char *start,*end,*key;
int len;
string s("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
// GET CLIENT KEY
key = getClientKey(str);
// Appending the key
s = key + s;
// SHA1 HASH
string out = getSHA1Hash(s);
//hashwrapper *h = new sha1wrapper();
//string out = h->getHashFromString(s);
// BASE 64 ENCODING
string encoded = getBase64Encoded(out);
//encoded = (char*)malloc(sizeof(char)*256);
//strcpy(encoded, getBase64Encoded(out) );
free(key);
//delete h;
return encoded;
}
char *getClientKey(char *str)
{
int len;
char *start,*end,*key;
start = strstr(str, "Sec-WebSocket-Key:");
if(start == NULL)
return false;
start += 17;
end = strstr(start, "==");
if(end == NULL)
return false;
end++;
while( !(*start>=65 && *start<=90 || *start >= 97 && *start<=122 || *start>=48 && *start<=57 || *start == '+' || *start=='/') )
start++;
len = end - start + 1;
key = (char*) malloc( sizeof(char) * (len+1) );
strncpy(key,start,len);
return key;
}
string getBase64Encoded(string s)
{
int len;
string str="";
len = s.length();
char *command;
for(int i=len-1 ; i>=1; i=i-2)
{
str = s.substr(i-1,2) + str;
str = "\\x" + str;
}
if(len%2==1)
{
str = s[0] + str;
str = "\\x" + str;
}
// making the command to be send to shell
str = "printf \"" + str ;
str = str + "\" | base64";
cout<<endl<<" STRING "<<str<<endl;
return executeShellCommand(str);
}
string getSHA1Hash(string str)
{
int len ;
string output;
str = "printf \""+str;
str = str +"\" | sha1sum";
cout<<str<<endl;
output = executeShellCommand(str);
return output.substr(0,output.length()-4);;
}
string executeShellCommand(const string& cmd)
{
FILE *fpipe;
if ( !(fpipe = (FILE*)popen(cmd.c_str(),"r")) )
{ // If fpipe is NULL
perror("Problems with pipe");
exit(1);
}
char buf[256] = "";
string line="";
while ( fgets( buf, sizeof buf, fpipe) )
{
if(strlen(buf)>0)
line.append(buf);
memset(buf, 0, sizeof(buf));
}
// CLOSE THE PIPE
pclose(fpipe);
return line;
}
void bail(char *on_what)
{
if(errno!=0)
{
fputs( strerror(errno), stderr);
fputs( ":", stderr);
}
fputs( on_what, stderr);
fputs("\n",stderr);
}
Here is the Websocket Code:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<section id="content"></section>
<input id="message" type="text" tabindex="1"/>
<textarea id="show">
</textarea>
<script src="http://www.google.com/jsapi"></script>
<script>google.load("jquery", "1.3")</script>
<script src="http://jquery-json.googlecode.com/files/jquery.json-2.2.min.js"></script>
<!--script src="http://jquery-websocket.googlecode.com/files/jquery.websocket-0.0.1.js"></script-->
<script src="/js/jquery.websocket-0.0.1.js"></script>
<script type="text/javascript">
/*var ws = $.websocket("ws://127.0.0.1:9099/",
{
events: {
message: function(e)
{
alert("e.data");
$('#content').append(e.data + '<br>')
}
}
});*/
var websocketConnection = new WebSocket("ws://127.0.0.1:9099/");
websocketConnection.onopen = function(ev)
{
showmsg('Connected to the echo service');
};
websocketConnection.onerror = function(ev)
{
showmsg(" ERROR : ".ev.data);
}
websocketConnection.onclose = function(ev)
{
showmsg(" Connection Closed");
};
websocketConnection.onmessage = function(event)
{
showmsg(event.data);
$('#content').append(event.data+"<br>");
};
showmsg(" CURRENT STATE "+websocketConnection.readyState);
if(!websocketConnection)
showmsg(" object null ");
websocketConnection.send("Hello Echo Server");
$('#message').change(function(){
flag = ws.send('message', this.value);
if(!flag)
alert("not send");
this.value = '';
});
function showmsg(content)
{
$('#show').val(content+"<br>");
}
</script>
</body>
</html>
Please Help me out , what is the problem in the C++ and what is the response to be sent to the WebScoket.
This is one problem (in executeShellCommand() function):
command = (char*) malloc( sizeof(char) * cmd.length() );
line = (char*)malloc(sizeof(char)*256);
line[0] = '\0';
//cout<<" COMMAND "<<cmd<<endl;
strcpy(command, cmd.c_str() ); // Writes one beyond the end of the
// 'command' buffer as no space allocated
// for null terminator
You could just pass the cmd.c_str() directly to popen() instead of allocating and populating the command buffer for that purpose:
if ( !(fpipe = (FILE*)popen(cmd.c_str(),"r")) )
I would recommend replacing char* with std::string where possible and allow it to manage memory for you and use stack allocated buffers instead of dynamically allocating buffers if a std::string is not appropriate. For example:
std::string executeShellCommand(const std::string& cmd)
{
FILE *fpipe;
if ( !(fpipe = (FILE*)popen(cmd.c_str(),"r")) )
{ // If fpipe is NULL
perror("Problems with pipe");
exit(1);
}
char buf[256] = "";
std::string line;
while ( fgets( buf, sizeof buf, fpipe) )
{
line += buf;
memset(buf, 0, sizeof(buf));
}
// CLOSE THE PIPE
pclose(fpipe);
return line;
}