I am trying to switch modem to command mode, write AT command and parse the response, but I am not too good with C and I do not understand what is wrong. The code I am calling is:
void switch_to_command_mode(int uart)
{
current_command_type = BTCommandTypeSwitchToATMode;
char switchCmd[] = "\x2F\x2F\x2F";
char emptySymbol[] = " ";
char checkAT[] = "AT\r";
ssize_t len = 0;
write(uart, emptySymbol, strlen(emptySymbol));
sleep(1);
write(uart, switchCmd, strlen(switchCmd));
sleep(1);
write(uart, checkAT, strlen(checkAT));
char buffer[255]; /* Input buffer */
char *bufptr; /* Current char in buffer */
int nbytes;
bufptr = buffer;
while (ioctl(uart, FIONREAD, (unsigned long)&len) == 0 && len < 2) {
warnx("waiting");
usleep(1000);
}
while ((nbytes = read(uart, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0)
{
bufptr += nbytes;
warnx("buffer %s", buffer);
if (bufptr[-1] == '\n' || bufptr[-1] == '\r')
break;
}
warnx("Final buffer: %s", buffer);
if (strncmp(buffer, "OK", 2) == 0) {
warnx("Great success!");
}
}
What I get as console output is:
waiting
waiting
buffer AT
O p �0
buffer AT
OK
�0
Final buffer: AT
OK
�0
According to documentation for the BT Module, the response should be in form of <CR><LF>OK<CR><LF>.
Any guidance on why this is possibly happening and what can I do with that would be highly appreciated.
P.S. I also already went through Serial programming for POSIX OS.
In C a "string" needs to be 0-terminated.
If they are not before being processed (printed here) the program runs into undefined behaviour. Which could also lead to "garbage" being printed.
To fix this easily initialise the buffer used to all 0s before using it, by doing:
char buffer[255] = "";
Also read() returns ssize_t not int. So you better do:
ssize_t nbytes;
Related
I am writing an application to read data from /dev/ttyUSB0.
I found it necessary to call sleep before calling read in the while loop so that I get the entire line at once. Otherwise, sometimes I get part of the line and the rest in the next iteration.
Do I have to package my data with a header containing the length of the string being sent over? Or is there a better way?
while(1) {
usleep(10000);
unsigned char buf[80];
int rdlen;
ioctl(fd, FIONREAD, &rdlen);
if (rdlen > 0) {
rdlen = read(fd, buf, rdlen);
}
if (rdlen > 0) {
...
}
The better way is to simply deal with receiving partial lines, have your code reading the data figure out when you have a complete line if that is important.
something like (not tested at all):
char buffer[1000];
size_t offset = 0;
while(1 ){
int len = read(fd, buffer+offset,(unsigned)(sizeof(buffer)-offset));
if(!strchr(buffer+offset, '\n')){
/* no end-of-line */
offset +=len;
}
else
{
/* deal with complete line */
offset = 0;
}
}
I am having trouble sending a string, one char at a time through sock_stream connection. The reason for this is that I am attempting to send multiple strings which are nearly 70000 characters at a time. It seems that the write function I was attempting to use requires a string.
for(i=0;i<BUF_SIZE;i++)
{
write(sockfd,plaintext[i],1);
if(plaintext[i]=='0')
break;
}
write(sockfd,'^',sizeof(char));
Also, how would I read this? Here is how I was attempting it.
int read_line(int fd,char message[])
{
size_t message_len=0;
while (message_len<BUF_SIZE)
{
char c;
int ret = read(fd, &c, 1);
if (ret < 0)
{
message[message_len] = 0;
return len; // EOF reached
}
if (c == '^')
{
read(fd,&c,1);
message[message_len] = 0;
return message_len; // EOF reached
}
data[len++] = c;
}
}
How would I implement this? Thank you.
The signature of write api is:
int write(int fd, const void *buf, size_t nbyte);
So what you can do something like:
#define BUF_SIZE 70000
char *buf = (char*)malloc(BUF_SIZE);
int written = 0;
int wrote;
if (buf)
memset(buf, 1, BUF_SIZE);
else
return written;//some error code
while (written < BUF_SIZE)
{
wrote = write(fd, buf, BUF_SIZE);
if (wrote < 0)
return written;
written += wrote;
}
Similarly you should try to do bulk read, as reading one char at a time is too slow unless you have a very valid reason. Each time you do write or read, its system call and they are costly.
So for read you can try something like
int read_bytes = read(fd, buf, BUF_SIZE);
and read_bytes will have the exact value of how much you have read.
Then do parse_buf(buf) in which you can find the tag you are looking for and then save the rest for the future in case you get more data, else if you get less data, then call read again.
You need change line
write(sockfd,plaintext[i],1);
to
write(sockfd,&plaintext[i],1);
Additionally, you can use
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
to enable TCP_NODELAY option.
I'm programming in C an IRC chat client. everything it's working well except I can't read the whole answer sent by the server. here's the code:
char buffer[2048];
write_on_screen(current_page(), "LOG COMMAND", command);
write(sockfd, command, strlen(command)); //write to socket
bzero(buffer, sizeof(buffer));
read(sockfd, buffer, sizeof(buffer));
write_on_screen(current_page(), "RESPONSE", buffer);
return buffer;
most of the time buffer will contain just a piece of the response (which is shorter than 2048 bytes) and other times it contains nothing. in both cases if I do another read() after the first one, it returns me the rest of the answer or another small piece (and then I've to do another read() again). if I put a sleep(1) between write() and read() I get the whole answer, but I'm sure this not a good pratice.
Is there some way I can avoid this?
thank you in advance
You're making the usual mistakes. It is impossible to write correct network code without storing the result of read() or recv() into a variable. You have to:
Check it for -1, and if so look at errno to see whether was fatal, which it almost always is except for EAGAIN/EWOULDBLOCK, and if fatal close the socket and abandon the process.
Check it for zero, which means the peer disconnected. Again you must close the socket and abandon the process.
Use it as the count of bytes actually received. These functions are not obliged nor guaranteed to fill the buffer. Their contract in blocking mode is that they block until an error, end of stream, or at least one byte is transferred. If you're expecting more than one byte, you normally have to loop until you get it.
According to RFC-1459, a single line of text in IRC can contain up to 512 characters and is terminated by a CRLF (\r\n) pair. However:
You're not guaranteed to receive exactly 512 bytes each time. For example, you might receive a comparatively short message from someone else one in the channel: Hi!
Related to the above: A group of 512 bytes might represent more than one message. For example, the buffer might contain a whole line, plus part of the next line: PRIVMSG <msgtarget> <message>\r\nPRIVMS
Given that you could have zero-or-more complete lines plus zero-or-one incomplete lines in your buffer[] at any time, you could try doing something along the lines of:
char buffer[2048];
while(keep_going)
{
char **lines;
int i, num_lines;
// Receive data from the internet.
receiveData(buffer);
// Create an array of all COMPLETE lines in the buffer (split on \r\n).
lines = getCompleteLines(buffer, &num_lines);
removeCompleteLinesFromBuffer(buffer);
// Handle each COMPLETE line in the array.
for (i = 0; i < num_lines; ++i) { handle_line(lines[i]); }
freeLines(lines);
}
This would allow you to handle zero or more complete lines in one go, with any incomplete line (i.e anything after the final \r\n pair) being kept around until the next call to receiveData().
You need to loop around read() until a CRLF had been detected.
A possible way to do this would be:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
ssize_t read_until_crlf(int sd, char * p, size_t s, int break_on_interupt)
{
ssize_t bytes_read = 0;
ssize_t result = 0;
int read_cr = 0;
int read_crlf = 0;
while (bytes_read < s)
{
result = read(sd, p + bytes_read, 1);
if (-1 == result)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
continue;
}
else if (EINTR == errno)
{
if (break_on_interupt)
{
break;
}
continue;
}
else
{
perror("read() failed");
break;
}
}
else if (0 == result)
{
break; /* peer disconnected */
}
if ('\r' == p[bytes_read])
{
read_cr = 1;
}
else if (('\n' == p[bytes_read]) && read_cr)
{
read_crlf = 1;
break; /* CRLF detected */
}
else
{
read_cr = 0;
}
++bytes_read;
}
if (!read_crlf)
{
result = -1; /* Buffer full without having read a CRLF. */
errno = ENOSPC; /* ... or whatever might suite. */
}
return (0 >= result) ?result :bytes_read;
}
Call it like this:
#include <stdio.h>
ssize_t read_until_crlf(int sd, char * p, size_t s, int break_on_interupt);
int main(void)
{
int sd = -1;
/* init sd here */
{
char line[2048] = "";
ssize_t result = read_until_crlf(sd, line, sizeof line, 0);
if (-1 == result)
{
perror("read_until_newline() failed");
}
printf("read '%s'\n", line);
}
return 0;
}
I'm trying to implement a working HTTP Client-Server application just to make practice with network programming.
The 2 programs have to follow this basic algorithm:
CLIENT - send a GET request
SERVER - send "+OK\r\n"
SERVER - send file size in bytes
SERVER - send file
CLIENT - send ACK
I'm having a lot of troubles in the reading part, probably because i perform some dirty read on the stream.
These are the 2 reading function that i'm using:
/* Reads a line from stream socket s to buffer ptr
The line is stored in ptr including the final '\n'
At most maxlen chasracters are read*/
int readline (SOCKET s, char *ptr, size_t maxlen)
{
size_t n;
ssize_t nread;
char c;
for (n=1; n<maxlen; n++)
{
nread=recv(s, &c, 1, 0);
if (nread == 1)
{
*ptr++ = c;
if (c == '\n')
break;
}
else if (nread == 0) /* connection closed by party */
{
*ptr = 0;
return (n-1);
}
else /* error */
return (-1);
}
*ptr = 0;
return (n);
}
and:
int readNumber(SOCKET s, long *num, int maxRead)
{
size_t n;
ssize_t nread;
int totRead;
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
if (nread == sizeof(number))
{
totRead+=nread;
*num = number;
}
else if (nread == 0) /* connection closed by party */
{
*num = 0;
return (n-1);
}
else /* error */
{
printf("nread = %d\n", nread);
return (-1);
}
}
return (totRead);
}
this is the snippet of the main where i receive the +OK message and then the file size:
memset(rbuf,0,sizeof(rbuf)); //rbuf is the buffer where is store the read
printf("waiting for response...\n");
result = readline(s, rbuf, sizeof(rbuf)); //reading function is above
printf("Byte read(okMsg) = %d\n", result);
if (result <= 0)
//ERROR MANAGEMENT
{
printf("Read error/Connection closed\n");
closesocket(s);
SockCleanup();
exit(1);
}
else
{
long fileLength=0;
unsigned char *fBuf;
//RECEIVE OK
if(!strcmp(rbuf,"+OK\r\n"))
{
puts("+OK\n");
//RECEIVE FILE LEN
int nw = readNumber(s, &fileLength, 1); //reading function is above
printf("Byte read(fDim) = %d\n", nw);
printf("File is %ld bytes long\n", fileLength);
if(nw >0)
{
// RECEIVE FILE
}
}
}
When i send the "+OK\r\n" string the server tells me that it sends 8 bytes, but when i read i find the '\0' char only after 6 bytes.
By the way it reads correctly the message, but when i try to read the file size (that is a long) it gives me back a wrong number.
My opinion is that the stream buffer is dirty, and that i'm reading 2 bytes that are not part of the file size, but i'm not understanding why this happens.
Please ask me more info if i'm not clear enough.
SOLVED:
Thank you all for your answers!!!
You put me in the right mindset to understand what was wrong.
Look like the problem was this declaration in the server:
char *okMsg = "+OK\r\n";
instead of
char okMsg[] = "+OK\r\n";
that lead me to an undefined behavior.
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
You forgot to design and implement a protocol to carry the data between your server and your client. Because TCP provides a stream of bytes, your protocol should be defined as a stream of bytes.
How many bytes convey this number? Is "however many bytes a 'long' happens to occupy on my platform" a good answer? What's the semantic meaning of the first byte? Is "whatever the first byte of a 'long' happens to mean on my platform" a good answer?
A good answer would be, "The size shall be conveyed as a 4-byte unsigned integer in little-endian byte order". Then make absolutely sure your code sends and receives in that format.
I have to write a SSL client in C that connects to a server,and gets either a html,either a file. I managed to get the html,but i can't download a binary file. For example,i'm trying to download a 3.8mb file from https://www.openssl.org/source/openssl-1.0.0d.tar.gz and my code only manages to download 1.1mb of them,and i don't even know if i get the right data in it.
Here is the function that i made for it:
char *sslReadfile (connection *c)
{
const int readSize = 1024;
char *rc = NULL;
int received, count = 0;
char buffer[1024];
char filename[40];
printf("Input the file name to be saved:\n");
scanf("%s",filename);
FILE *fp;
fp = fopen(filename, "wb");
if (c)
{
while (1)
{
if (!rc)
rc = malloc (readSize * sizeof (char) + 1);
else
rc = realloc (rc, readSize * sizeof (char) + 1);
received = SSL_read (c->sslHandle, buffer, readSize);
buffer[received] = '\0';
if (received > 0)
fprintf(fp,"%s",buffer);//strcat (rc, buffer);
if (received < readSize)
break;
//count++;
}
}
printf("\nFile saved!! %s !!!\n\n",filename);
fclose(fp);
return rc;
}
oh, and i call it like that:
char command[50];
sprintf(command,"GET /%s\r\n\r\n",relativepath);
sslWrite (c, command);
response = sslReadfile (c);
where c is my connection.
Don't use fprintf to write binary data. Use fwrite. The reason your output is smaller is that fprintf is stopping at the first null character, skipping any characters that remain in the 1024 byte buffer. Also, you don't appear to be using, and don't need the mallocd rc buffer.
So, after the call to SSL_read, you want something like this:
if (received <= 0) break;
fwrite(buffer, 1, received, fp);
You break the loop when received < readSize, instead you should only break the loop when received <= 0 and you have inspected SSL_shutdown() and/or SSL_get_error().
Also, you shouldn't NUL terminate your buffer and use fprintf, but keep the buffer as is while using fwrite. You are now introducing NULs in your data that weren't there.