C - Extern struct - c++

I'm using structure to process NMEA messages, but I don't know what, something goes wrong when processing it. So, I have NMEA_parse.h:
/* GPRMC */
#define TIME 2U
#define LAT 4U
#define LON 6U
#define SPD 8U
#define ANG 9U
#define DATE 10U
extern struct gprmc{
char time[10];
char latitude[10];
char longitude[10];
char speed[10];
char angle[10];
char date[10];
}gprmc_datas;
NMEA_parse.c:
#include "NMEA_parse.h"
struct gprmc gprmc_datas;
static void fill_data (char* param_in)
{
uint8_t i = 0U;
char* trunk;
char trunk_datas[20U][10U];
trunk = strtok(param_in, ",");
while(trunk != NULL)
{
i++;
if(i > 20) { i = 0; }
strcpy(trunk_datas[i],trunk);
trunk = strtok (NULL, ",");
}
if(memcmp(trunk_datas[1U],"GPRMC",6U) == 0U)
{
strcpy(gprmc_datas.time,trunk_datas[TIME]);
strcpy(gprmc_datas.latitude,trunk_datas[LAT]);
strcpy(gprmc_datas.longitude,trunk_datas[LON]);
strcpy(gprmc_datas.date,trunk_datas[DATE]);
strcpy(gprmc_datas.time,trunk_datas[TIME]);
}
}
main.c:
#include <stdio.h>
#include "NMEA_parse.h"
int main(void)
{
char *message = "$GPRMC,182127.00,A,4753.47678,N,02022.20259,E,0.837,,161019,,,A*7C\r\n";
char *mes = "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A";
proc_sentence(message);
printf("\ntime: %s\n", gprmc_datas.time);
printf("latitude: %s\n", gprmc_datas.latitude);
printf("longitude: %s\n", gprmc_datas.longitude);
}
proc_sentence function pass the data to fill_data(), if the message valid (checksum, etc)
When I'm using the mes as input, everything is correct, but when I switch to message, some abnormality is shown, because the result is the following:
time: 182127.00
latitude: 4753.4767802022.2025E
longitude: 02022.2025E
Do you have any idea what goes wrong?

If you change latitude[10] in the struct into latitude [12], the string "message" can also be used.

Unlike almost every other SO question about the use of scanf, yours is actually a problem that cries out for it. After all, if a machine wrote it, a machine can read it, right?
Using C's concatenation of string literals, I got pretty close to filling the struct with a single function:
int n = sscanf( message,
"%[^,],"
"%[^,],"
"%*[^,],%[^,],"
"%*[^,],%[^,],"
"%*[^,],%[^,],"
"%[^,],"
"%[^,],",
label,
gprmc.time,
gprmc.latitude,
gprmc.longitude,
gprmc.speed,
gprmc.angle,
gprmc.date );
This makes use of the little-used regex specifier, where we look for non-commas %[^] separated by commas. The %*[^] specifies to skip the field.

Related

FIFO: One process never reads from pipe

I'm following THIS TutorialsPoint guide to Linux Piping, and I specifically need to use FIFOs.
However, the code doesn't work at all for the server side.
The server file either hangs indefinitely or it reads nothing, while the client instead writes on the FIFO and immediately reads it has just written.
Here's the full code for both files in case you don't want to go through TutorialsPoint:
fifoserver_twoway.cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
void reverse_string(char *);
int main() {
int fd;
char readbuf[80];
char end[10];
int to_end;
int read_bytes;
/* Create the FIFO if it does not exist */
mkfifo(FIFO_FILE, S_IFIFO|0640);
strcpy(end, "end");
fd = open(FIFO_FILE, O_RDWR);
while(1) {
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOSERVER: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
to_end = strcmp(readbuf, end);
if (to_end == 0) {
close(fd);
break;
}
reverse_string(readbuf);
printf("FIFOSERVER: Sending Reversed String: \"%s\" and length is %d\n", readbuf, (int) strlen(readbuf));
write(fd, readbuf, strlen(readbuf));
/*
sleep - This is to make sure other process reads this, otherwise this
process would retrieve the message
*/
sleep(2);
}
return 0;
}
void reverse_string(char *str) {
int last, limit, first;
char temp;
last = strlen(str) - 1;
limit = last/2;
first = 0;
while (first < last) {
temp = str[first];
str[first] = str[last];
str[last] = temp;
first++;
last--;
}
return;
}
fifoclient_twoway.cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
int main() {
int fd;
int end_process;
int stringlen;
int read_bytes;
char readbuf[80];
char end_str[5];
printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
fd = open(FIFO_FILE, O_CREAT|O_RDWR);
strcpy(end_str, "end");
while (1) {
printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
end_process = strcmp(readbuf, end_str);
//printf("end_process is %d\n", end_process);
if (end_process != 0) {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOCLIENT: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
} else {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
close(fd);
break;
}
}
return 0;
}
When I run both processes, this is what I get:
./fifoserver_twoway
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
./fifoclient_twoway
FIFOCLIENT: Sent string: "ciao" and string length is 4
FIFOCLIENT: Received string: "ciao" and length is 4
Enter string: why won't you reverse?
FIFOCLIENT: Sent string: "why won't you reverse?" and string length is 29
FIFOCLIENT: Received string: "why won't you reverse?" and length is 29
It's also worth noting that before starting to write this question, the server behaviour was completely different: instead of receiving nothing and printing like you see here, it would hang indefinitely after the "read" (and I haven't changed the code one bit, except for changing the FIFO_FILE path)
You let the server sleep after writing – but not the client. That way, the client still might read its own output back before the server can fetch it. So at very least you should add a sleep after both writes, letting the server sleep a bit longer to make sure the client wakes up first to read the servers output.
Accessing the same end of unnamed pipes (created via pipe functions) concurrently is undefined behaviour. While not sure for named pipes, I'd assume pretty much the same there as well. Synchronising concurrent access to such ends via simple delays (sleep, usleep) might perhaps do the trick, but it is a pretty unsafe method.
I'd rather recommend two separate pipes instead (as Tony Tannous proposed already), one for each direction (open the respective ends RDONLY or WRONLY as needed), then you get full duplex communication instead of half duplex and you don't need further synchronisation either (delays in most simple variant):
// server
int fd_cs = open(FIFO_FILE_CS, O_RDONLY);
int fd_sc = open(FIFO_FILE_SC, O_WRONLY);
read(fd_cs, ...);
write(fd_sc, ...);
// client
int fd_cs = open(FIFO_FILE_CS, O_WRONLY);
int fd_sc = open(FIFO_FILE_SC, O_RDONLY);
write(fd_cs, ...);
read(fd_sc, ...);

Adafruit Fona 3g Library; How exactly does this work?

I am trying to send a packet to a server over 3g and TCP connection. Below is a link to the .cpp and .h file I have found:
https://os.mbed.com/users/Nels885/code/Adafruit_FONA_3G/
More specifically, I am really confused on how TCPSend works under the Adafruit_FONA_3G class. I am trying to implement it but my code seems to get stuck at packet[0] = 0; under function bool Adafruit_FONA_3G::TCPsend(char *packet).
I have tried commenting out packet[0] = 0; and the code runs all the way through. I have also tried initializing char* packet[32]; before packet[0] = 0; and the code runs all the way through. I am assuming the function is not detecting the packet input.
Here is the specific function from the .cpp file:
bool Adafruit_FONA_3G::TCPsend(char *packet)
{
if (strlen(packet) > 0)
{
mySerial.printf("%s", packet);
//mySerial.printf("%s\r\n", packet);
readline();
packet[0] = 0;
return true;
}
else
return false;
}
Here is my main code:
#include "mbed.h"
#include "Adafruit_FONA.h"
#define FONA_RST D4
#define FONA_TX D1
#define FONA_RX D0
#define FONA_RI D7 //not used
char replybuffer[255];
Adafruit_FONA_3G fona(FONA_TX, FONA_RX, FONA_RST, FONA_RI);
Serial pc(USBTX, USBRX);
int main()
{
fona.TCPinitialize();
char Timeout[21];
fona.getTCPtimeout(Timeout);
char * Server = "52.14.99.26";
uint16_t Port = 10001;
fona.TCPconnect(Server,Port);
char *Packet = "Pick Up %";
fona.TCPsend(Packet);
fona.TCPclose();
}
Adafruit_FONA_3G::TCPsend() assumes that you pass it a writable buffer. You're passing a read-only buffer. So, replace
char *Packet = "Pick Up %";
with
char Packet[] = "Pick Up %";
The problem is really that your compiler allows you to initialize writable pointers with read-only values. This is a shortcoming of your compiler.

Lcd displaying old data with new data

I have interfaced a programmable xbee with a 16x2 character LCD. I transmit wireless frames with the the help of another xbee and display it on the recieving xbee.
The problem arises when I send two wireless frames one after another.
Consider that I send 24 characters in the first frame, that will be displayed normally as it should be(with a random extra character at the end of the display which I dont know why)
The problem arises when I send a second frame which is smaller than the first frame for eg. of 6 characters. The LCD displays the the 6 characters but adds further 18 characters that were there in the first frame after the 6 characters.
The display looks likes this:
Frame1 display : This is a check message.
Frame2 display : Hello!s a check message. (original message : Hello!)
I tried clearall() lcd function between frames at different positions but it does not work. I also different things you see in the code but they dont work.
The code currently looks like this;
enter code here
#include <xbee_config.h>
#include <types.h>
#include <string.h>
#include <ctype.h>
#define char_lcd_writ_str(a) char_lcd_writ(a, strlen(a))
static uint8_t test_stage = 0;
static uint8_t test_stage_done = 0;
static const char str[] = "abcdefghijklmnopqrstuvwxyz012345";
#if defined(RTC_ENABLE_PERIODIC_TASK)
void rtc_periodic_task(void)
{
test_stage++;
if (test_stage == 8)
test_stage = 0;
test_stage_done = 0;
}
#endif
#ifdef ENABLE_XBEE_HANDLE_RX
int xbee_transparent_rx(const wpan_envelope_t FAR *envelope, void FAR *context)
{
int c=0;
char addrbuf[ADDR64_STRING_LENGTH];
char_lcd_init(CHAR_LCD_CFG);
char_lcd_clear();
addr64_format(addrbuf, &envelope->ieee_address);
sys_watchdog_reset();
while (c<4)
{
char_lcd_writ_str(envelope->payload);
delay_ticks(2*HZ);
char_lcd_clear();
char_lcd_goto_xy(0, 0);
c++;
}
}
#endif
void main(void)
{
uint8_t i, j;
sys_hw_init();
sys_xbee_init();
sys_app_banner();
char_lcd_init(CHAR_LCD_CFG);
for (;;) {
if (!test_stage_done) {
switch (test_stage) {
case 0:
char_lcd_goto_xy(0, 0);
char_lcd_writ_str("All working fine");
break;
}
test_stage_done = 1;
}
sys_watchdog_reset();
sys_xbee_tick();
}
}
ssize_t char_lcd_writ(const uint8_t *data, size_t len)
{
size_t written = 0;
while (written < len) {
char_lcd_putchar(*data++);
written++;
if ( written == 32 || written == 64 || written == 96 || written == 128 || written == 160 || written == 192 )
{
delay_ticks(2*HZ);
char_lcd_clear();
char_lcd_goto_xy(0, 0);
}
}
while (written < len) {
written = 0;
memset(*data++, '\0', len);
written++;
}
return (ssize_t)written;
}
Could be as simple as envelope->payload not being null-terminated and actually containing those extra characters if you go beyond the payload length specified in the envelope. Try using your char_lcd_writ() function with the payload's length instead of char_lcd_writ_str() which will use strlen() to find the length.

Convert byte string to normal string in C++

I have the following situation:
I'm actually trying to read streamdata from a server into a label in Visual Studio:
//Receive a reply from the server
if((recv_size = recv(ConnectSocket , server_reply , 2000 , 0)) == SOCKET_ERROR){
MessageBox::Show("recv failed","");
//exit(1);
}
this->label1->Text = Convert::ToString(server_reply[0]);
example result:
ANAG;FCA;11:20:27;NL0010877643;FIAT CHRYSLER AUTO;16.85;0.0;0
when I get it into my program, I have it like:
657865...
which I think is the byte representation of the corresponding characters (eg.: 65 = A, 78 = N, etc.).
Question is: How do I convert these bytecodes into a normal string of characters?
The server seems to be sending byte data
Thanks in advance
You just need to create a string from it.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char byteArray[] = { 65, 78, 65, 71 }; // .... your input
std::string s(byteArray, sizeof(byteArray));
cout << s;
return 0;
}

Running an executable from a C++ program in the same process

Is that possible? I'd like an easy access to the executable's memory to edit it. Alternately, when I'm not the administrator, is it possible to edit the executable's memory from another process? I've tried the ptrace library and it fails if I'm not the administrator. I'm on Linux
I'm not entirely sure what you are asking, but this is possible with shared memory.
See here: http://www.kernel.org/doc/man-pages/online/pages/man7/shm_overview.7.html
This is what a debugger does. You could look at the code of an open source debugger, e.g. gdb, to see how it works.
The answer:
Yes - it works: you don't have to be administrator / root, but of course you need the rights to access the process' memory, i.e. same user.
No - it is not easy
The possibility to write to /proc/pid/mem was added some time ago to the Linux kernel. Therefore it depends on the kernel you are using. The small programs were checked with kernel 3.2 where this works and 2.6.32 where it fails.
The solution consists of two programs:
A 'server' which is started, allocates some memory, writes some pattern into this memory and outputs every three seconds the memory contents which is placed after the pattern is printed.
A 'client' which connects via the /proc/pid/maps and /proc/pid/mem to the server, searches for the pattern and writes some other string into the server's memory.
The implementation uses heap - but as long as the permissions allow - it is also possible to change other portions of the other process' memory.
This is implemented in C, because it is very 'low level' - but it should work in C++. It is a proof of concept - no production code - e.g. there are some error checks missing and it has some fixed size buffers.
memholder.c
/*
* Alloc memory - write in some pattern and print out the some bytes
* after the pattern.
*
* Compile: gcc -Wall -Werror memholder.c -o memholder.o
*/
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main() {
char * m = (char*) malloc(2048);
memset(m, '\xAA', 1024);
strcpy(m + 1024, "Some local data.");
printf("PID: %d\n", getpid());
while(1) {
printf("%s\n", m + 1024);
sleep(3);
}
return 0;
}
memwriter.c
/*
* Searches for a pattern in the given PIDs memory
* and changes some bytes after them.
*
* Compile: gcc -Wall -std=c99 -Werror memwriter.c -o memwriter
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
int open_proc_file(pid_t other_pid, char const * const sn,
int flags) {
char fname[1024];
snprintf(fname, 1023, "/proc/%d/%s", other_pid, sn);
// Open file for reading and writing
int const fd = open(fname, flags );
if(fd==-1) {
perror("Open file");
exit(1);
}
return fd;
}
void get_heap(int fd_maps, size_t * heap_start, size_t * heap_end) {
char buf[65536];
ssize_t const r = read(fd_maps, buf, 65535);
if(r==-1) {
perror("Reading maps file");
exit(1);
}
buf[r] = '\0';
char * const heap = strstr(buf, "[heap]");
if(heap==NULL) {
printf("[heap] not found in maps file");
exit(1);
}
// Look backward to the latest newline
char const * hl_start;
for(hl_start = heap; hl_start > buf && *hl_start != '\n';
--hl_start) {}
// skip \n
++hl_start;
// Convert to beginnig and end address
char * lhe;
*heap_start = strtol(hl_start, &lhe, 16);
++lhe;
*heap_end = strtol(lhe, &lhe, 16);
}
int main(int argc, char *argv[]) {
if(argc!=2) {
printf("Usage: memwriter <pid>\n");
return 1;
}
pid_t const other_pid = atoi(argv[1]);
int fd_mem = open_proc_file(other_pid, "mem", O_RDWR);
int fd_maps = open_proc_file(other_pid, "maps", O_RDONLY);
size_t other_mem_start;
size_t other_mem_end;
get_heap(fd_maps, &other_mem_start, &other_mem_end);
ptrace(PTRACE_ATTACH, other_pid, NULL, NULL);
waitpid(other_pid, NULL, 0);
if( lseek(fd_mem, other_mem_start, SEEK_SET) == -1 ) {
perror("lseek");
return 1;
}
char buf[512];
do {
ssize_t const r = read(fd_mem, buf, 512);
if(r!=512) {
perror("read?");
break;
}
// Check for pattern
int pat_found = 1;
for(int i = 0; i < 512; ++i) {
if( buf[i] != '\xAA' )
pat_found = 0;
break;
}
if( ! pat_found ) continue;
// Write about one k of strings
char const * const wbuf = "REMOTE DATA - ";
for(int i = 0; i < 70; ++i) {
ssize_t const w = write(fd_mem, wbuf, strlen(wbuf));
if( w == -1) {
perror("Write");
return 1;
}
}
// Append a \0
write(fd_mem, "\0", 1);
break;
} while(1);
ptrace(PTRACE_DETACH, other_pid, NULL, NULL);
close(fd_mem);
close(fd_maps);
return 0;
}
Example output
$ ./memholder
PID: 2621
Some local data.
Some local data.
MOTE DATA - REMOTE DA...
Other interpretation
There is also another interpretation of your question (when reading the headline and not the question), that you want to replace the 'executable' from one process with another one. That can be easily handled by exec() (and friends):
From man exec:
The exec() family of functions replaces the current process image with a new process image.
In Windows, the methods used for this are named ReadProcessMemory / WriteProcessMemory, you will, however, need administrative rights for this. The same is for linux, as I've said in my comment, no sane system would allow user process to modify non-owned memory.
For linux, the only function is ptrace. You will need to be administrator.
http://cboard.cprogramming.com/cplusplus-programming/92093-readprocessmemory-writeprocessmemory-linux-equivalent.html contains more detailed discussion.
Can you imagine the consequences of allowing process to modify other process memory, without being administrator?