I want to receive bytes into conbuf.buffer. either of test 1 or test2 is ok. I am not seeing any value in printf statement. Am I passing in the pointer correctly? How do I allocate memory to a char pointer inside a struct.
typedef struct cBuf
{
int size;
char *buffer;
} cbuf;
class A
{
cbuf conbuf;
void test();
}
void A::test()
{
int buffersize = 20;
char buf[buffersize];
conbuf.buffer = (char *)malloc(buffersize * sizeof(char *));
// test 1
int n = socket.receivebytes(conbuf.buffer, buffersize);
// test 2
//int n = socket.receivebytes(buf, buffersize);
//strcpy(conbuf.buffer, buf);
printf("conbuf.buffer %s \n", conbuf.buffer);
}
this
conbuf.buffer = (char *)malloc(buffersize * sizeof(char *));
should be
conbuf.buf = (char *)malloc(buffersize * sizeof(char)); //allocate space for char not pointer to char. Your struct only has buf member not "buffer"
Use this:
conbuf.buffer = (char *)calloc( (buffersize * sizeof(char))+1,1);
since printf requires last char of string to be null terminated, this ensures it. But data received from network may already contain NUL in the middle. So instead of using printf you should use fwrite:
fwrite(conbuf.buffer,buffersize , STDOUT);
I'd suggest you to redirect it in a file and do a hex dump to see the output.
Related
I'm trying to build a raw socket and I've built a structure to have every header : ETH, IP, etc.
I just started by assigning ETH field but when I run just this part of code, I get segmentation fault:
typedef struct Network_frame_test{
unsigned char dst_mac_addr[CONF_MAC_ADDRESS_SIZE];
unsigned char src_mac_addr[CONF_MAC_ADDRESS_SIZE];
struct ethhdr *ethh;
struct iphdr *iph;
struct udphdr *udph;
unsigned char buffer[ SIZE_BUFFER ];
} Network_frame_test;
int main(void)
{
Network_frame_test frame_test;
const unsigned char message[] = {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'};
int message_size = sizeof(message)/sizeof(message[0]);
printf("messge size : %d", message_size);
unsigned char* sendbuff;
printf(" message %.2x", message[0]);
memset(&sendbuff,0,43);
printf(" %d", 0);
for(int i=0;i<6;i++)
{
frame_test.dst_mac_addr[i] = message[i+6];
}
frame_test.ethh = (struct ethhdr *)(sendbuff);
for(int i=0; i<CONF_MAC_ADDRESS_SIZE; i++)
{
frame_test.ethh->h_dest[i] = frame_test.dst_mac_addr[i];
}
}
sendbuff is a pointer to a char, not allocated or anything. By using memset on its address, you set its value to 0, which means a null pointer. Later on you assign it to frame_test.ethh, and try to access it. I believe that is where you see the issue.
Why is sendbuff an unsigned char pointer and not simply of type
struct ethhdr?
Also, why is the memset used for 43 bytes? I'd change it to be the size of struct ethhdr.
After that, simeply use
frame_test.ethh = &sendbuff;
...
struct ethhdr srndbuff:
memset(&sendbuff, 0, sizeof(sendbuff));
...
frame_test.ethh = &sendbuff
...
If you have to use it with unsigned char, then:
#DEFINE SIZE 43 /* or sizeof(struct ethhdr) */
...
unsigned char sendbuff[SIZE];
memset(sendbuff, 0, SIZE);
...
frame_test.ethh = (struct ethhdr *)(sendbuff);
...
Hope that helps.
#include <fstream>
#include<iostream>
#include<cstring>
using namespace std;
class Address {
public:
char addr[6];
Address() {}
Address(string address) {
size_t pos = address.find(":");
int id = stoi(address.substr(0, pos));
short port = (short)stoi(address.substr(pos + 1, address.size()-pos-1));
memcpy(addr, &id, sizeof(int));
memcpy(&addr[4], &port, sizeof(short));
}
};
enum MsgTypes{
JOINREQ,
JOINREPLY,
DUMMYLASTMSGTYPE,
HEARTBEAT
};
/**
* STRUCT NAME: MessageHdr
*
* DESCRIPTION: Header and content of a message
*/
typedef struct MessageHdr {
enum MsgTypes msgType;
}MessageHdr;
typedef struct en_msg {
// Number of bytes after the class
int size;
// Source node
Address from;
// Destination node
Address to;
}en_msg;
//class Testing{
void send(Address *myaddr, Address *toaddr, char *data, int size);
int main()
{
MessageHdr *msg=new MessageHdr();
size_t msgsize = sizeof(MessageHdr) + sizeof(Address) + sizeof(long) + 1;
msg=(MessageHdr *)malloc(msgsize*sizeof(char));
int id=233;
short port =22;
long heartbeat=1;
msg=(MessageHdr *)malloc(msgsize*sizeof(char));
string s=to_string(id)+":"+to_string(port);
string s1=to_string(id+1)+":"+to_string(port+1);
cout<<s<<'\n';
cout<<s1<<'\n';
Address *addr= new Address(s);
for (int i = 0; i < 6; i++)
cout << addr->addr[i];
Address *toaddr= new Address(s1);
msg->msgType = JOINREQ;
//cout<<(char *)msg->msgType;
memcpy((char *)(msg+1), addr, sizeof(addr));
memcpy((char *)(msg+1) + 1 + sizeof(addr), &heartbeat, sizeof(long));
send(addr, toaddr, (char *)msg, msgsize);
return 0;
}
void send(Address *myaddr, Address *toaddr, char *data, int size) {
cout<<"inside send"<<'\n';
en_msg *em;
//static char temp[2048];
em = (en_msg *)malloc(sizeof(en_msg) + size);
em->size = size;
memcpy(&(em->from), &(myaddr), sizeof(em->from));
memcpy(&(em->to), &(toaddr), sizeof(em->from));
memcpy(em + 1, data, size);
cout<<(char *)(em+1);
}
This is my program,in between I am trying to check the address what is being stored in my char array. but upon printing the array, it gives some strange output. two strange symbols after printing the value of s and s1.
I am trying to store the id:port in the char array of the address class, but looks without success. Please help
The code I am referring to for printing is in the main function. Approx ten lines down the main function.
For say, my id is 233 and port is 22, The address is 233:22 I want to retrieve back 233:22 and print it. How do I do that here?
Thanks in advance :)
The problem is in this line:
cout << addr->addr[i];
Since addr->addr is an array of char, each element will be printed as the character it represents. If you'd rather print the integer value of each, simply cast it to int first.
cout << static_cast<int>(addr->addr[i]); // or old-fashioned: (int)addr->addr[i];
Given the following code:
for (int i = 0; i <= 6; i++)
cout << addr->addr[i];
And given Address's constructor:
size_t pos = address.find(":");
int id = stoi(address.substr(0, pos));
short port = (short)stoi(address.substr(pos + 1, address.size()-pos-1));
memcpy(addr, &id, sizeof(int));
memcpy(&addr[4], &port, sizeof(short));
It's clear that you are printing the bytes that conform a number
addr->addr is a char array which contains two integer variables, one having two bytes (int) and the other having 2 bytes (short).
So, if the number is , lets say, 436, you are printing:
0xB4 0x01 0x00 0x00
<crazy char> SOH NULL NULL
You must understand what are you printing, or what you want to print in order to print it properly.
Note: The most popular setup is assumed here, which means:
Little Endian arquitecture
4-byte int
2-byte short
Update
How to get address and port back:
int address;
unsigned short port;
memset(&address, addr->addr, 4);
memset(&port, addr->addr+4, 2);
I need to convert an unsigned 64-bit integer into a string. That is in Base 36, or characters 0-Z. ulltoa does not exist in the Linux manpages. But sprintf DOES. How do I use sprintf to achieve the desired result? i.e. what formatting % stuff?
Or if snprintf does not work, then how do I do this?
You can always just write your own conversion function. The following idea is stolen from heavily inspired by this fine answer:
char * int2base36(unsigned int n, char * buf, size_t buflen)
{
static const char digits[] = "0123456789ABCDEFGHI...";
if (buflen < 1) return NULL; // buffer too small!
char * b = buf + buflen;
*--b = 0;
do {
if (b == buf) return NULL; // buffer too small!
*--b = digits[n % 36];
n /= 36;
} while(n);
return b;
}
This will return a pointer to a null-terminated string containing the base36-representation of n, placed in a buffer that you provide. Usage:
char buf[100];
std::cout << int2base36(37, buf, 100);
If you want and you're single-threaded, you can also make the char buffer static -- I guess you can figure out a suitable maximal length:
char * int2base36_not_threadsafe(unsigned int n)
{
static char buf[128];
static const size_t buflen = 128;
// rest as above
The send function in winsock2 accepts only char pointers.
How do I send integers or objects through it too?
const char *buf which you need to pass to send() function as an argument is just a pointer to array of bytes. You need to convert integers to bytes:
const int MAX_BUF_SIZE = 1024;
int int_data = 4;
const char *str_data = "test";
char *buf = (char*) malloc(MAX_BUF_SIZE);
char *p = buf;
memcpy(&int_data, p, sizeof(int_data));
p += sizeof(int_data);
strcpy(p, str_data);
p += strlen(str_data) + 1;
send(sock, buf, p - buf, 0);
free(buf);
and reading code:
const int MAX_BUF_SIZE = 1024;
int int_data = 0;
const char *str_data = NULL;
char *buf = (char*) malloc(MAX_BUF_SIZE);
char *p = buf;
recv(sock, buf, MAX_BUF_SIZE, 0);
memcpy(p, &int_data, sizeof(int_data));
p += sizeof(int_data);
str_data = malloc(strlen(p) + 1);
strcpy(str_data, p);
p += strlen(p) + 1;
free(buf);
and complex objects needs to be serialized to stream of bytes.
Note 1: The code sample is valid iff both server and client use the same platforms (x32 / x64 / ...) that means int has the same amount of bytes and byte order is the same.
Note 2: Writing code should check that there is no buffer (MAX_BUF_SIZE) overflow on each step.
Just store the value into a variable and then type-cast the variable to char*. The send() and recv() functions operate on binary data, despite taking char* parameters.
Sending:
int int_data = 4;
send(sock, (char*) &int_data, sizeof(int), 0);
Reading:
int int_data;
recv(sock, (char*) &int_data, sizeof(int), 0);
Generally, the easiest way is to print the integer or object to a string, and send that string. Textual representations are more portable, and also easier to debug.
std::stringstream may be a useful class both to create the string and parse it on the other end.
I am having trouble converting strings from utf8 to gb2312. My convert function is below
void convert(const char *from_charset,const char *to_charset, char *inptr, char *outptr)
{
size_t inleft = strlen(inptr);
size_t outleft = inleft;
iconv_t cd; /* conversion descriptor */
if ((cd = iconv_open(to_charset, from_charset)) == (iconv_t)(-1))
{
fprintf(stderr, "Cannot open converter from %s to %s\n", from_charset, to_charset);
exit(8);
}
/* return code of iconv() */
int rc = iconv(cd, &inptr, &inleft, &outptr, &outleft);
if (rc == -1)
{
fprintf(stderr, "Error in converting characters\n");
if(errno == E2BIG)
printf("errno == E2BIG\n");
if(errno == EILSEQ)
printf("errno == EILSEQ\n");
if(errno == EINVAL)
printf("errno == EINVAL\n");
iconv_close(cd);
exit(8);
}
iconv_close(cd);
}
This is an example of how I used it:
int len = 1000;
char *result = new char[len];
convert("UTF-8", "GB2312", some_string, result);
edit: I most of the time get a E2BIG error.
outleft should be the size of the output buffer (e.g. 1000 bytes), not the size of the incoming string.
When converting, the string length usually changes in the process and you cannot know how long it is going to be until afterwards. E2BIG means that the output buffer wasn't large enough, in which case you need to give it more output buffer space (notice that it has already converted some of the data and adjusted the four variables passed to it accordingly).
As others have noted, E2BIG means that the output buffer wasn't large enough for the conversion and you were using the wrong value for outleft.
But I've also noticed some other possible problems with your function. Namely, with the way your function works, your caller has no way of knowing how many bytes are in the output string. Your convert() function neither nul-terminates the output buffer nor does it have a means of telling its caller the number of bytes it wrote to outptr.
If you want to deal with nul-terminates strings (and it appears that's what you want to do since your input string is nul-terminated), you might find the following approach to be much better:
char *
convert (const char *from_charset, const char *to_charset, const char *input)
{
size_t inleft, outleft, converted = 0;
char *output, *outbuf, *tmp;
const char *inbuf;
size_t outlen;
iconv_t cd;
if ((cd = iconv_open (to_charset, from_charset)) == (iconv_t) -1)
return NULL;
inleft = strlen (input);
inbuf = input;
/* we'll start off allocating an output buffer which is the same size
* as our input buffer. */
outlen = inleft;
/* we allocate 4 bytes more than what we need for nul-termination... */
if (!(output = malloc (outlen + 4))) {
iconv_close (cd);
return NULL;
}
do {
errno = 0;
outbuf = output + converted;
outleft = outlen - converted;
converted = iconv (cd, (char **) &inbuf, &inleft, &outbuf, &outleft);
if (converted != (size_t) -1 || errno == EINVAL) {
/*
* EINVAL An incomplete multibyte sequence has been encounĀ-
* tered in the input.
*
* We'll just truncate it and ignore it.
*/
break;
}
if (errno != E2BIG) {
/*
* EILSEQ An invalid multibyte sequence has been encountered
* in the input.
*
* Bad input, we can't really recover from this.
*/
iconv_close (cd);
free (output);
return NULL;
}
/*
* E2BIG There is not sufficient room at *outbuf.
*
* We just need to grow our outbuffer and try again.
*/
converted = outbuf - out;
outlen += inleft * 2 + 8;
if (!(tmp = realloc (output, outlen + 4))) {
iconv_close (cd);
free (output);
return NULL;
}
output = tmp;
outbuf = output + converted;
} while (1);
/* flush the iconv conversion */
iconv (cd, NULL, NULL, &outbuf, &outleft);
iconv_close (cd);
/* Note: not all charsets can be nul-terminated with a single
* nul byte. UCS2, for example, needs 2 nul bytes and UCS4
* needs 4. I hope that 4 nul bytes is enough to terminate all
* multibyte charsets? */
/* nul-terminate the string */
memset (outbuf, 0, 4);
return output;
}