Related
I have a char *data that is a Datagram to represent the packet I want to send in but I need to insert on that an uint8_t array.
// Datagram to represent the packet
char datagram[4096], source_ip[32], *data, *pseudogram;
// zero out the packet buffer
memset(datagram, 0, 4096);
// IP header
struct iphdr *iph = (struct iphdr *)datagram;
// UDP header
struct udphdr *udph = (struct udphdr *)(datagram + sizeof(struct ip));
// Data part
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
uint8_t packet_bytes[] = { 0xff, 0xff, 0x81, 0x01, 0x01 };
memcpy(data, packet_bytes, 5);
Doing this allows me to insert what I need and it works but the problem is that I have and uint8_t array with 0x00 in the middle making this harder than I thought because the 0x00 hex also means a termination of an array, how can I make it to work with this array instead ?
char packet_bytes[] = {
0xff, 0xff, 0x81, 0x00, 0x00, 0x00, 0x00, 0x30,
0x13, 0x43, 0x00, 0x01, 0x01, 0x01, 0x02, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x06, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x63,
0x02, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x09, 0x04, 0x00,
0x0a, 0x00, 0x03, 0x01, 0x00, 0x11, 0x77, 0x25
};
the problem is that I have and uint8_t array with 0x00 in the middle making this harder than I thought because the 0x00 hex also means a termination of an array
There is no such thing as "termination of an array" in C. There is null termination of character arrays used as strings, but that isn't applicable here. So the memcpy part will work just fine.
You have some other problems however:
char datagram[4096], char packet_bytes[] etc
char is unsuitable, dangerous and non-portable for the purpose of holding raw binary data. Use uint8_t instead. See Is char signed or unsigned by default?
struct iphdr *iph = (struct iphdr *)datagram;
This will lead to undefined behavior because of alignment and strict aliasing. What is the strict aliasing rule? You cannot wildly type pun from a character array to another type by pointer casts (though the other way around from "any type" to character type is possible). Furthermore, your struct may contain padding, in which case it is extra non-portable and you don't want to be sending padding bytes around.
(struct udphdr *)(datagram + sizeof(struct ip)); Same problem as above.
The only reliable way to do this is either to disable struct padding and then memcpy in/out of the struct. Or alternatively write serialization/deserialization routines accessing one struct member at a time, moving it to/from the raw data.
I have a structure as follows
typedef struct s_CanMsg
{
uint32_t id;
uint16_t timestamp;
uint8_t data[8];
uint8_t dlc;
bool_t isExtended;
bool_t isRemote;
} s_CanMsg_t;
and I have a structure variable as follows
s_CanMsg_t CANEraseResponse;
Now I am trying to pass an array to the data member of the structure variable as follows:
CANEraseResponse.data[8] = {0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00};
This is showing syntax error and how can I pass the data to the structure variable with array member? Thanks in advance.
You can initialize the whole structure when you define the variable:
s_CanMsg_t CANEraseResponse = {
some_value_for_id,
some_value_for_timestamp,
{0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00},
some_value_for_dlc,
some_value_for_isExtended,
some_value_for_isRemote
};
You can also use a designator to explicitly initialize only the array member;
s_CanMsg_t CANEraseResponse = {
.data = {0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00}
};
Then all other members will be initialized to zero.
And of course you can define a temporary array and copy into the structure array:
static uint8_t data[8] = {0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00},
s_CanMsg_t CANEraseResponse;
memcpy(CANEraseResponse.data, data, sizeof data);
Lastly, if none of the ways above are acceptable, then the only remaining solution is to explicitly assign to each element of the array:
CANEraseResponse.data[0] = 0x00;
CANEraseResponse.data[1] = 0xFF;
CANEraseResponse.data[2] = 0x00;
CANEraseResponse.data[3] = 0x04;
CANEraseResponse.data[4] = 0x02;
CANEraseResponse.data[5] = 0x00;
CANEraseResponse.data[6] = 0x00;
CANEraseResponse.data[7] = 0x00;
The notation you are using can only be used to initialize an array. Once you declare your struct variable, you have moved past initialization. You can, however, do it with something called a "designated initializer" like so:
s_CanMsg_t CANEraseResponse = {.data= {0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00}};
CANEraseResponse.data[8] refers to the 9th element of the data member (as the array is zero based. Try removing the [8].
Edit/Clarification: removing the [8] will not solve your issue, but you should be aware that CANEraseResponse.data[8] points to a position outside of the data array.
You can't assign arrays directly in C. As well as the initialization techniques shown in other answers, you could use a compound literal and memmove() (or memcpy()):
memmove(CANEraseResponse.data, (uint8_t[]){ 0x00, 0xFF, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00 }, sizeof(CANEraseResponse.data));
I am attempting to write an array of char to a BMP file in C. The problem with this is that whilst 0x00 values are required for the file, it seems C interprets this as the end of string when writing to the file i.e. as a NULL char. Is there any way I can override this and have C rely purely on what I say is the number of char I wish to pass?
Code for writing the header to file (this function is executed in main);
void writeFile(void){
unsigned char bmp1[54] = {
0x42, 0x4D, 0x36, 0x00,
0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x00,
0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x01, 0x00,
0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};
FILE *picFile = fopen("pic.bmp","w");
fprintf(picFile, bmp1, 54);
fclose(picFile);
}
Don't use fprintf() to write binary data, of course it's going to interpret its formatting string as a string. That's what it does!
Use fwrite(), and open your file in binary mode with "wb".
You can use sizeof to compute the size of the array, no need to hardcode the value:
FILE *picFile = fopen("pic.bmp", "wb");
if(picFile != NULL)
fwrite(bmp1, sizeof bmp1, 1, picFile);
fclose(picFile);
This works because it's in the same scope as the array declaration of bmp1.
The function fprintf() and its relatives are used to format some information and produce a string then write its characters1 into a file or put it on screen or store it into a given array of characters.
Use function fwrite() to write binary data; this function does not interpret the data you give it in any way and just writes the number of bytes you specify into the file.
Try this:
FILE *picFile = fopen("pic.bmp","w");
fwrite(bmp1, sizeof(bmp1), 1, picFile);
fclose(picFile);
(your call to fprintf() was erroneous, anyway)
1
The functions sprintf() and snprintf() (they put the generated string into a provided buffer of characters) copy the entire generated string onto their destination buffer, including the null terminating character.
The functions fprintf() (writes the string into a file) and printf() (puts the string on screen) do not put the null terminating character of the generated string into the output stream.
(Thanks #chux for pointing out that the C strings include the null terminating character.)
I have a small c program which connect and authenticate with my security DVR which in turn starts sending me data over the socket. I can connect on port 5000 or port 80 sending different authentification methods to start receiving the video/images. My problem is; I am new to c first of all, and I am very lost on how to process the data received over the socket. This is the data I am sending to authenticate.
char authenticate[] = {
0x31, 0x31, 0x31, 0x31, 0x88, 0x00, 0x00, 0x00,
0x01, 0x01, 0x00, 0x00, 0x88, 0x7d, 0xa6, 0x47,
0x0c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x61, 0x64, 0x6d, 0x69, 0x6e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x43, 0x6f, 0x6c, 0x74, 0x6f, 0x6e, 0x73, 0x2d,
0x4d, 0x61, 0x63, 0x42, 0x6f, 0x6f, 0x6b, 0x2d,
0x50, 0x72, 0x6f, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x00, 0x00, 0x00, 0x35, 0x34, 0x32, 0x36,
0x39, 0x36, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00
};
x = sendto(sockfd, authenticate, sizeof(authenticate), 0,
(struct sockaddr*)&servaddr, sizeof(servaddr));
I am then recieving the data with
while(1)
{
n = recvfrom(sockfd, data, 2048, 0, NULL, NULL);
When I connect via http port 80 This is the image data that I receive:
Content-length: 2153
Content-type: image/jpeg
ˇÿˇ‡JFIFHHˇ€Cˇ€Cˇ¿#ˇƒ
ˇƒ8 2A!$X"#3QRTqëîóò“’÷ˇƒˇƒ#
!1A"2QRqrë#SacÅ°¢≥—“ÒBCstÇí¥”ˇ⁄ ?e›n◊}mÀ⁄ÔÅ≥j¿ò[0ÂáֱNU…9'*‚®#ô &yéïùr‰Ù®{ï“däŒÆl$Kkë R,√fƒSl—EX
z \û£≠âflüÈ‚≠ê*àÉ*—1E;q}Ìp6#>øÆÂòŸR≠^Ì˝çò ı;R∆b¡»ü>aÊ∫a˙5KKüz∑¶Î´D“≤κl∂ÎÓ„∆Àn∫¥•sh8vß4≠äöûñy‰H¢çyºí0TQrÏ#π dÅèåfi*XY*F¨Óƒl™¢‰˝S^sgh]î…flzXNü‡†2∑ñæ5t€Tp`qìåos◊iGùjˆ˙+FÈ™‚‘_§≈[”Jˇ *•<*´∆≥ÁpVGfl
ï¶ñ—€{ñgíJmd*ôï„å[YT-J†∞π∂¯ë…{¶dyÓaÓhå©!øg⁄∆™≤È:
≥Ô`Mú)∞ÚÌǯhˇÿ„Tø∑,9˛õ°˛ıØö~ø«ûÔ˝˙aa{ÜÔû÷Èé‡ÂΩk÷ºµ\sÉÒ¬XÓ∞`¯⁄X“">eäÅœ»G¡ìöÜ"˘mütòÅtuÓbÌh;vB1dflL ∂)
´È
Hm∂Í
Ω¡î*Ä≤e‘nÄï‘HΩ…77ÙIè6%â%ãµ"T¿n¢Í3%‹zj#™:”ÂmR˛=L ZsZ[_ïz±»r…™2®ú.«]∑$q¢1)ùftÙ˘îà[q£°Îü&%Ï÷#á∂¿ôEy!ËÇJ0‚‚j»¥|∆fi–ü5"èRj›D˘„õUäú≥û>•«bdôãq]Ö$2ˆ„Gc#,ó±Ò<√-p}ZÍSÛ £ëóŒsäóNçı≠◊òÊö•mÈÇ_W„Y2∆∫9œxπŸ¸*±’dË⁄1(¸05{üfW∆Éû
‘ÿSÑ‘„û.JTÓ9˙Ìø˝∆º=∆ ¬ï∆h≥!`uˆ’Uçõèd„Ï…ı®*GÕıŸ6iíÆiñ¶’ØmBë‰WáÈö˛â‚ı∞>Ó˛◊_Â’ˇπ?º”˘øh~8TÔÕ/ùˆO¬Ewü^◊]…6
ÕïÊ«p2ˆ◊ä”õU÷ËÖˆ◊䲲ãk–«_2ûk4Éÿ‰aÖƒîP∑ùg⁄†·¢µ’ÂS÷}XNï¯5GWæßGk”óS8fòˇ;˝âp;≈“ƒ5ˇ˜„Éû·&Áa¨ö2tÿ±íÉìcÇeÓ"¬Â„(8¯:øØíM £rmfiá~≠æ(:oT/U≤/täó U√ñT0ëªÕ ê’¢víRT#˙‚ìO7ÖÆÒ‘D<dm#;F®—yÑmPǃ5É+FZÀ"8≥-˙7"ç–ãm{Å∑Öunü»à·®icëcoDìf¬·ñ)!å A¡ñÂNrx√aeP\ZM®£ ‘Y\<kJÿ‚’Ó#„Œª+â3
¨π©%Uü±Àñ¨œò§S2àŸßUJjwûYãZ#Ç∆˚¶&hr⁄xj¬ì È™sàK-… 28Fm‡Ôr√û 8Qè
ª∑ØP ptt£‚N—Œ∆Iπ ıo«Y{Èe.U[´‰•ı∫ÎæöÙU’‘…)¶Gy
†“ä]ãä6U≤Å∞b 7X„ ™˙#ÓMÖ∑>_ó
=fiÔ>·π∂ˇ÷ãÎΩfl«Y!µÎô≥—ß;¨J™èΩ|tLoîRˇM›.#nŸÍ±≈±Ê∏Ï~qkãsv≈Xõ‰í∞Lπ/cR,j*6.Sí„ÿ˘fÑ»7f|_™≥RçÿíE°°bã {{Ïõç#·Ãæ:7çú√´u o
⁄N¨Ω\€ù◊K,Z4àÕ8N\˙πÍë’D∫vbfl∏¢>äz.¸¨⁄Ä‘°dx≈ªàˆÕ45‡ßõub-ü%TVTN8⁄∞¨≤µÁñÜD[;o—˘ƒNˇóóØ[ò;´¡O*∫¿ƒ©∏2ߘG#20˘H∆µªú’2€∂O°Â⁄Ùb®äÌ/hÿQÁXÓŸJzB¬Öw]Ù2ÿ—⁄§∆«gÜö·´˚Ëãt‚+˛Iì¯∂⁄nÎ{ºVʬ)aà∆´°ÀÚËÃkr÷â„ç^1©ôæ
óv'ô8∆ãπkB˙цπ¯zÉsÀpv;Ã]ÓI€[Ìj/˙A≤øÒ}O˚ËS|Dûƒˇ¶3=ÓÍæ6?Ú…å!¥›¨Ûˆ¸f…€·I~à≥ g>∆®‰√Û0≥30®Æ) èMÖçGÃ∑dÑÖ∞¥Œéf≥ÔyµE¢Yå.õ·ç+r˙ú ≤ZÄP ‰y¨Km⁄±~ävfl¡'I+b»Ñî[ö<¬ æñ8raEãk
I am unsure if this data is some weird encoding or if it need to be processed somehow to make it valid. I have searched around with no luck or examples of how to properly do this. If i connect via the data port (port 5000 which sends via instead of an image) the data looks pretty much the same although i know it may be processed or unprocessed H.246 video data.
The raw data is an image. It starts after the blank line which terminate the headers.
Code:
n = recvfrom(sockfd, data, 2048, 0, NULL, NULL); // might as well replace with read().
// use a much larger buffer, ideally large enough to fit largest possible whole image
headers_end_str = "\r\n\r\n";
headers_end_position = strstr(data, headers_end_str);
headers_end_position += strlen(headers_end_str );
if (headers_end_position > n) { ... } // handle errors
FILE* fh = fopen("image.jpg", "wb");
int result = fwrite( &( data[ headers_end_position ), n - headers_end_position, 1, fh);
// check result for errors
// continue reading from socket and writing to file, subsequent reads do not have headers
This should get you started, you need to fine tune reading additional data, and also error handling and end of file.
However, even before you have done all that, you should be able to run "file -s image.jpg" (on linux, or cygwin) and it will tell you it's a JPEG image.
I used WireShark to monitor the communication between the DVR and it's web browser plugin client and the authentication message header is similar to your post (0x31 0x31 0x31 0x31...). How did you construct this array? I searched a lot for this protocol documentation but I didn't find.
In my case I do the requests at port 7171 (it's a DVR settings). I also used a while(true) to keep listening this port and the server sends me a h264 stream.
The problem is that the stream is not like rtps protocol describes, see this great post. In our case we have to parse a kind of proprietary header first (that starts with 0x31 0x31 0x31 0x31) to stract the frame, sps and pps.
How would one go about taking hex data into a program and sending it back out?
char peer0_0[] = {
0x00, 0x00, 0x10, 0x01, 0xbf, 0x8b, 0xf9, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x07 };
char peer0_1[] = {
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 };
char peer0_2[] = {
0x02, 0x00, 0x00, 0x00 };
If you already have the code in the format you have posted, then there's not much to do. You haven't actually specified where you want to replay it. Depending on how you want to do this, you simply pass the array to whatever function does the actual sending. For example, if you want to send this data over an existing socket, you can do something like this:
send(my_socket, peer0_0, sizeof(peer0_0), 0);
What you want is bit-twist. It is essentially a replay device for pcap files. You don't have to save the file in any special format, it can be used with the native file format wireshark captures data in.
http://bittwist.sourceforge.net/