Printing Partition Table - C program - c

I am trying to print a partition table using C programming language, everything seems to work fine: Opening and reading, but I don't understand why it is printing garbage values.
Here is the code:
struct partition
{
unsigned char drive;
unsigned char chs_begin[3];
unsigned char sys_type;
unsigned char chs_end[3];
unsigned char start_sector[4];
unsigned char nr_sector[4];
};
int main()
{
int gc = 0, i = 1, nr = 0, pos = -1, nw = 0;
int fd =0;
char buf[512] ;
struct partition *sp;
printf("Ok ");
if ( (fd = open("/dev/sda", O_RDONLY | O_SYNC )) == -1)
{
perror("Open");
exit(1);
}
printf("fd is %d \n", fd);
pos = lseek (fd, 0, SEEK_CUR);
printf("Position of pointer is :%d\n", pos);
if ((nr = read(fd, buf, sizeof(buf))) == -1)
{
perror("Read");
exit(1);
}
close(fd);
printf("Size of buf = %d\n and number of bytes read are %d ", sizeof(buf), nr);
if ((nw = write(1, buf, 64)) == -1)
{
printf("Write: Error");
exit(1);
}
printf("\n\n %d bytes are just been written on stdout\n", nw,"this can also be printed\n");
printf("\n\t\t*************Partition Table****************\n\n");
for (i=0 ; i<4 ; i++)
{
sp = (struct partition *)(buf + 446 + (16 * i));
putchar(sp -> drive);
}
return 0;
}
It is printing garbage instead of partition table.
I might have some basic understanding issues but I searched with Google for a long time but it did not really help. I also saw the source code of fdisk but it is beyond my understanding at this point. Could anyone please guide me? I am not expecting someone to clear my mistake and give me the working code. Just a sentence or two - or any link.

Try this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct partition
{
unsigned char boot_flag; /* 0 = Not active, 0x80 = Active */
unsigned char chs_begin[3];
unsigned char sys_type; /* For example : 82 --> Linux swap, 83 --> Linux native partition, ... */
unsigned char chs_end[3];
unsigned char start_sector[4];
unsigned char nr_sector[4];
};
void string_in_hex(void *in_string, int in_string_size);
void dump_partition(struct partition *part, int partition_number);
void dump_partition(struct partition *part, int partition_number)
{
printf("Partition /dev/sda%d\n", partition_number + 1);
printf("boot_flag = %02X\n", part->boot_flag);
printf("chs_begin = ");
string_in_hex(part->chs_begin, 3);
printf("sys_type = %02X\n", part->sys_type);
printf("chs_end = ");
string_in_hex(part->chs_end, 3);
printf("start_sector = ");
string_in_hex(part->start_sector, 4);
printf("nr_sector = ");
string_in_hex(part->nr_sector, 4);
}
void string_in_hex(void *in_string, int in_string_size)
{
int i;
int k = 0;
for (i = 0; i < in_string_size; i++)
{
printf("%02x ", ((char *)in_string)[i]& 0xFF);
k = k + 1;
if (k == 16)
{
printf("\n");
k = 0;
}
}
printf("\n");
}
int main(int argc, char **argv)
{
int /*gc = 0,*/ i = 1, nr = 0, pos = -1/*, nw = 0*/;
int fd = 0;
char buf[512] ;
struct partition *sp;
int ret = 0;
printf("Ok ");
if ((fd = open("/dev/sda", O_RDONLY | O_SYNC)) == -1)
{
perror("Open");
exit(1);
}
printf("fd is %d\n", fd);
pos = lseek (fd, 0, SEEK_CUR);
printf("Position of pointer is :%d\n", pos);
if ((nr = read(fd, buf, sizeof(buf))) == -1)
{
perror("Read");
exit(1);
}
ret = close(fd);
if (ret == -1)
{
perror("close");
exit(1);
}
/* Dump the MBR buffer, you can compare it on your system with the output of the command:
* hexdump -n 512 -C /dev/sda
*/
string_in_hex(buf, 512);
printf("Size of buf = %d - and number of bytes read are %d\n", sizeof(buf), nr);
/*if ((nw = write(1, buf, 64)) == -1)
{
printf("Write: Error");
exit(1);
}
printf("\n\n%d bytes are just been written on stdout\nthis can also be printed\n", nw);
*/
//printf("\n\t\t*************Partition Table****************\n\n");
printf("\n\t\t*************THE 4 MAIN PARTITIONS****************\n\n");
/* Dump main partitions (4 partitions) */
/* Note : the 4 partitions you are trying to dump are not necessarily existing! */
for (i = 0 ; i < 4 ; i++)
{
sp = (struct partition *)(buf + 446 + (16 * i));
//putchar(sp->boot_flag);
dump_partition(sp, i);
}
return 0;
}

Related

How to get a line from csv file with a custom fgets

I'm currently writing a program in C that reads in from a CSV file, I have a defined buffer size but am having trouble separating each line from the buffer. I can see where the line ends by checking for a '\n' char. I cannot extract that line from the buffer for parsing however. Anybody have some ideas?
#ifndef BUFFSIZE
#define BUFFSIZE 4096
#endif
int main() {
int fd;
int fdBin;
char * buf = malloc(BUFFSIZE);
int count = 0;
bool EOFFlag = false;
fd = open("SongCSV.csv", O_RDONLY);
fdBin = open("BinarySongData.bin", O_CREAT | O_WRONLY, "0600");
if (fd == -1) {
printf("failed to open a file\n");
exit(1);
}
off_t offset = 0;
off_t offsetOld = 0;
int readBytes;
while (!EOFFlag) {
offsetOld = offset;
offset = lseek(fd, offset - offsetOld, SEEK_CUR);
readBytes = read(fd, buf, BUFFSIZE);
printf("\n\n%lld\n\n", (offset));
int i = 0;
int commaCounter = 0;
while (i < readBytes) {
if (buf[i] != '\n') {
}
if (buf[i] == '\n') {
printf("\t\t THIS IS END OF LINE \t%d", i);
commaCounter = 0;
}
if (buf[i] == ',') {
commaCounter++;
if (commaCounter == 4) {
printf("****Album Name****");
}
}
write(fdBin, buf, BUFFSIZE);
printf("%c", buf[i]);
i++;
}
if (readBytes < BUFFSIZE) {
EOFFlag = true;
printf("\nREACHED END OF FILE");
}
printf("\n");
printf("AA: END OF LINE ****%d*****", count);
count++;
}
close(fd);
close(fdBin);
return 0;
}
I do it this way, easy and simple. I just did it quickly, any doubts just ask me, Cheers.
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int len = sending();
char *firstline;
int i = 0;
char buf[0];
int rd ;
int fd = open("hey.csv", O_RDONLY);
rd = read(fd, buf, 1);
firstline = malloc(sizeof(char) * len);
while (i != len)
{
firstline[i] = buf[0];
i++;
rd = read(fd, buf, 1);
}
firstline[i] = '\0';
printf("%s\n", firstline);
return (0);
}
int sending()
{
int fd = open("hey.csv", O_RDONLY);
char buf[1];
int r = 0;
r = read(fd, buf, 1);
int len = 0;
while (buf[0] != '\n')//getting exact size to malloc
{
len++;
r = read(fd, buf, 1);
}
return len;
}

print garbage values from the shared memory

I am currently working on a producer-consumer implementation using C.
First, I create a buffer on the shared memory of a variable length that is given by the user in the consumer process.
Then, in the producer process, I need to access the shared memory and puts new data to the buffer so the consumer can consume.
Below is the consumer code:
#include "common.h"
#include <unistd.h>
int fd;
int errno;
int MY_LEN = 0;
Shared* shared_mem;
char *job[4];
int setup_shared_memory(){
fd = shm_open(MY_SHM, O_CREAT | O_RDWR, 0666);
if(fd == -1){
printf("shm_open() failed\n");
exit(1);
}
ftruncate(fd, sizeof(Shared) + MY_LEN*sizeof(char *));
}
int attach_shared_memory(){
shared_mem = (Shared*) mmap(NULL, sizeof(Shared) + MY_LEN*sizeof(char *), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shared_mem == MAP_FAILED){
printf("mmap() failed\n");
exit(1);
}
return 0;
}
int init_shared_memory() {
shared_mem->data = 0;
int i;
for(i = 0; i < shared_mem->length; i++)
{
shared_mem->arr[i] = 0;
// shared_mem->arr[i] = (char *)calloc(1, sizeof(char*));
}
sem_init(&(shared_mem->mutex), 1, 1);
}
int init_job(){
int i;
for(i = 0; i < 4; i++)
{
job[i] = (char *)malloc(sizeof(char *));
}
}
int take_a_job(int index){
init_job();
char *ds = strdup(shared_mem->arr[index]);
job[0] = strtok(ds, "-");
int i = 1;
while(i < 4)
{
job[i] = strtok(NULL, "-");
i++;
}
// remove the job from the buffer
shared_mem->arr[index] = NULL;
}
int consume_job(int index){
printf("\nPrinter starts printing the job %s, %s pages from Buffer[%d]. The duration is %s seconds and the source is %s.\n",job[3], job[2], index, job[1], job[0]);
sleep(atoi(job[1])); // sleep for job[1] seconds.
}
int main(int args, char *argv[]) {
setup_shared_memory();
attach_shared_memory();
init_shared_memory();
MY_LEN = atoi(argv[1]); // the first parameter following ./printer = the length of the buffer
shared_mem->length = MY_LEN;
//shared_mem->arr = (int*) &shared_mem->arr;
int index = 1;
*(shared_mem->arr) = "1-10-5-6";
*(shared_mem->arr + 1) = "2-5-2-7";
*(shared_mem->arr + 2) = "3-20-10-8";
*(shared_mem->arr + 3) = "4-7-4-9";
take_a_job(index);
int i;
for(i = 0; i < shared_mem->length; i++){
printf("\n\n%d set %s\n", i, shared_mem->arr[i]);
}
consume_job(index);
printf("\n\nHello second check\n\n");
while (1) {}
return 0;
}
Here is the producer code:
#include "common.h"
int fd;
Shared* shared_mem;
char *job;
int setup_shared_memory(){
fd = shm_open(MY_SHM, O_RDWR, 0666);
if(fd == -1){
printf("shm_open() failed\n");
exit(1);
}
}
int attach_shared_memory(){
shared_mem = (Shared*) mmap(NULL, sizeof(Shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shared_mem == MAP_FAILED){
printf("mmap() failed\n");
exit(1);
}
return 0;
}
int create_a_job(int args, char *argv[]){
int i;
job = (char *)calloc(8, sizeof(char *));
if(args != 5)
return 0; //the parameters are not correctly formatted
else{
for(i = 1; i < args; i++)
{
if(i > 1)
strcat(job, "-");
strcat(job, argv[i]);
}
}
strcat(job, "\0");
printf("\nthe job is %s\n", job);
}
int put_a_job(){
printf("shared_mem->length is %d\n\n", shared_mem->length);
int i;
for(i = 0; i < shared_mem->length; i++)
{
if(*(shared_mem->arr + i) == 0)
{
//shared_mem->arr[i] = (char *)malloc(sizeof(job));
//strcpy(shared_mem->arr[i], job);
*(shared_mem->arr + i) = (char *)job;
printf("\n\nThe index is %d\n", i);
//printf("\n\nthe argument is %s at %d\n", job, i);
return i;
}
}
printf("\n\nThe index is %d\n", i);
}
int main(int args, char *argv[]) {
setup_shared_memory();
attach_shared_memory();
// create a job with the parameters
int result = create_a_job(args, argv);
if(result == 0)
{
printf("Not the right parameters.\n");
printf("Plase enter client ID, job duration, number of pages and job ID.\n");
return 0;
}
int i;
put_a_job();
for (i=0; i < shared_mem->length; i++) {
printf("the argument is %s at %d\n", (char *)(shared_mem->arr + i), i);
}
printf("\n\n");
return 0;
}
The common.h file is
#ifndef _INCLUDE_COMMON_H_
#define _INCLUDE_COMMON_H_
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
// from `man shm_open`
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <string.h>
#include <semaphore.h>
#define MY_SHM "/JIT"
typedef struct {
sem_t mutex;
int data;
int length; // the length of the buffer
char *arr[0];
} Shared;
#endif //_INCLUDE_COMMON_H_
I first run ./consumer 10 & to allocate a buffer of length 10 and after, I run ./producer 1 2 3 4 to put the job to the buffer and print the buffer, I got garbage values
Any help would be really appreciated! Thank you!
Instruction
*(shared_mem->arr + i) = (char *)job;
is storing the pointer job into the shared mem, not the pointed value.
Maybe you want to use a strncpy.
You cannot share memory address between processes, because of Linux uses virtual memory. To make the story short an address in a process is not valid for a different process.
Be aware that you have a memory leakage because you never call free() for the allocated job.

socket programming FD_ISSET() method usage

so I'm new to socket programming, and I was asked to write the server side that sends data to a client according to a certain request. I'm trying to server multiple clients at the same time. When a client first connects, the server accepts with no troubles whatsoever, but when a client sends a certain request, I get stuck in an infinity loop and it's not clear at all to me why the server keeps sending the same info to the client over and over and over again, below is my code for the server side:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#include <windows.h>
#include <winsock.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <fstream>
#include <vector>
#define MAX_CONNECTION 100
#ifndef max
#define max(a,b) ((a) < (b) ? (a) : (b))
#endif
typedef struct connection{
char ipaddr[16];
int port;
int sd;
} connection;
static unsigned short SERVER_PORT = 4118;
int main(int argc, char* argv[])
{
int maxfd =-1;
fd_set rset, allset;
connection client[MAX_CONNECTION];
int passiveSock; /* Main Server Socket */
struct sockaddr_in servSock_in;
#ifdef WIN32
WSADATA wsaData;
WSAStartup(0x0101, &wsaData);
#endif
int port;
if (argc > 1)
port = atoi(argv[1]);
else
port = SERVER_PORT;
for(int i=0; i < MAX_CONNECTION ; i++)
client[i].sd = -1;
memset((char *)&servSock_in, 0, sizeof(servSock_in));
servSock_in.sin_family = PF_INET;
servSock_in.sin_addr.s_addr = htonl(INADDR_ANY);
servSock_in.sin_port = htons((u_short)port);
passiveSock = socket(PF_INET, SOCK_STREAM, 0);
if (passiveSock < 0) {
fprintf(stderr, "I am too tired... I failed to open gate...\n");
return -1;
}
if (bind(passiveSock, (struct sockaddr *)&servSock_in, sizeof(servSock_in)) < 0){
fprintf(stderr, "I couldn't attach gate to port...\n");
return -1;
}
if (listen(passiveSock, 5) < 0) {
fprintf(stderr, "I am not hearing anything...\n");
return -1;
}
FD_SET(passiveSock, &allset);
maxfd = max(maxfd, passiveSock);
struct sockaddr_in cliSock_in;
int cliSockLen;
int connectedSock;
cliSockLen = sizeof(cliSock_in);
printf("\n Waiting for an incoming connection at port number %d", port);
int bytesread = 0;
for (;;)
{
//FD_ZERO(&allset);
rset = allset;
int nready = select(maxfd+1,&rset, NULL, NULL, NULL);
if(FD_ISSET(passiveSock, &rset)){
printf("In the first if");
connectedSock = accept(passiveSock, (struct sockaddr *)&cliSock_in, &cliSockLen);
/* if an error occurs while accepting */
if (connectedSock == -1) {
printf("\n Server: Accept error (errno = %d: %s)\n", errno, strerror(errno));
continue;
}
for (int i=0; i<MAX_CONNECTION; i++)
if (client[i].sd < 0){
client[i].sd=connectedSock;
strcpy(client[i].ipaddr, inet_ntoa(cliSock_in.sin_addr));
client[i].port= ntohs(cliSock_in.sin_port);
printf("\n Server: connection established with %s:%d\n",
client[i].ipaddr, client[i].port);
break;
}
FD_SET(connectedSock, &allset);
maxfd = max(maxfd, connectedSock);
}
else{
for(int j = 0 ; j < MAX_CONNECTION; j++){
connectedSock = client[j].sd;
printf("connectedSock is %d", connectedSock);
if(connectedSock < 0)
continue;
if(FD_ISSET(client[j].sd, &rset)){
unsigned char buffer[66000];
int index = 0;
bytesread = recv(connectedSock, (char *)buffer, 66000, 0);
int type;
type = (buffer[0] & 0xE0) >> 5;
if (type == 0)
{
char fname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
int fs = 0;
fs += (buffer[i++] << 8) & 0xff00;
fs += buffer[i++];
char* filedata = (char*)malloc(fs*sizeof(char));
memcpy(&filedata[0], &buffer[i], fs);
filedata[fs] = '\0';
for (int i = 0; i < fs; i++)
printf("%c", filedata[i]);
printf("type=%d,length=%d,data=%s,fs=%d,filedata=%s", type, length, fname, fs, filedata);
std::ofstream of;
of.open(fname, std::ios::binary);
for (int i = 0; i < fs; i++)
of.write(filedata + i, 1);
of.close();
unsigned char rep;
int reptype = 0;
rep = (unsigned char)(reptype & 0x07);
send(connectedSock, (char*)(&rep), 1, 0);
}
else if (type == 1)
{
char fname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
std::ifstream t;
int fs;
t.open(fname, std::ios::binary);
std::vector<char> vec((
std::istreambuf_iterator<char>(t)),
(std::istreambuf_iterator<char>()));// open input file
t.close();
fs = vec.size();
char* filedata = (char*)malloc(fs*sizeof(char)); // allocate memory for a buffer of appropriate dimension
filedata = &vec[0];
filedata[fs] = '\0';
i = 0;
unsigned char* repbuffer = (unsigned char*)malloc(3 + length + fs);
repbuffer[i] = (unsigned char)(type & 0x07);
repbuffer[i] = repbuffer[i] << 5;
repbuffer[i] = repbuffer[i] | (length & 0x0000003F);
i++;
memcpy(&repbuffer[i], fname, length);
i = i + length;
printf("sizeof fs=%d", sizeof(fs));
repbuffer[i++] = (unsigned char)((fs & 0xff00) >> 8);
repbuffer[i++] = (unsigned char)(fs & 0xff);
memcpy(&repbuffer[i], filedata, fs);
printf("sizeof buffer=%d", sizeof(repbuffer));
i = i + fs;
// printf("the buffer contains %s\n",&repbuffer[11]);
if (send(connectedSock, (char*)repbuffer, i, 0) == -1)
{
printf("A local error was detected while sending data! (errno = %d: %s)\n", errno, strerror(errno));
return -1;
}
}
else if (type == 2)
{
char fname[100],nfname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
int nlength = (buffer[i++] & 0x1F);
memcpy(&nfname[0], &buffer[i], nlength);
nfname[nlength] = '\0';
rename(fname,nfname);
}
else if (type == 3)
{
char rep[32];
strcpy(rep, "bye change get help put");
int length = strlen(rep);
unsigned char* repbuffer = (unsigned char*)malloc(1 + length);
int type = 6;
repbuffer[0] = (unsigned char)(type & 0x07);
repbuffer[0] = repbuffer[0] << 5;
repbuffer[0] = repbuffer[0] | (length & 0x0000003F);
memcpy(&repbuffer[1], rep, length);
if (send(connectedSock, (char*)repbuffer, length+1, 0) == -1)
{
perror("A local error was detected while sending data!!");
return -1;
}
}
else if (type == 4)
{
closesocket(connectedSock);
}
break;
}
}
}
}
closesocket(passiveSock);
WSACleanup();
return 0;
}
I feel there's something wrong with the usage of FD_ISSET() method, I've been trying to figure out the error for 2 hours now, pleeassse help

UART read blocks after reading 33 bytes

I have made a C-program flash image to micro controller through uart.In this code,i am following a protocol,all things are going well.But when i load image into micro controller through uart,write is working fine but read blocked after reading 33 bytes.I am writing and reading byte by byte..declaration & definition of function to load image is written below:
Function declaration :
load_RAM_image(file_size, file_buff);
here file_size is unsigned int and its value is 40,980KB and file_buff is unsigned char pointer which points to image buffer.
Function declaration :
#define BYTE_WRITE 1
#define DELAY 10000
int load_RAM_image(unsigned int buff_size, unsigned char *buff)
{
unsigned int count, num_Wbytes, num_Rbytes, byte;
for (count = 0; count < buff_size;) /* increase count value to every time */
{
num_Wbytes = write( serial_fd, buff + count, BYTE_WRITE );
if (num_Wbytes < 0)
{
fputs("write failed!\n", stderr);
return -1;
}
tcdrain(serial_fd);
usleep(DELAY);
num_Rbytes = read( serial_fd, rbuff + count, BYTE_WRITE );
if (num_Rbytes < 0)
{
if (errno == EAGAIN)
{
printf("SERIAL EAGAIN ERROR\n");
return -EAGAIN;
}
else
{
printf("SERIAL read error %d %s\n", errno, strerror(errno));
}
}
printf("wbuf[ %d ] = %02x rbuff = %02x\n\n",
count /*+ byte*/, *(buff + count/* + byte*/), rbuff[count]);
/* Compare the received byte from BAM */
if (strncmp(buff + count, rbuff + count, BYTE_WRITE ) < 0)
{
printf("Error : RAM loading error(W != R)\n");
return -1;
}
count += BYTE_WRITE ;
printf("count = %d\n", count);
}
return 0;
}

Read line by line from a socket buffer

I want to write a function that read line by line from a socket buffer obtained from third parameter from read() function from unistd.h header.
I have wrote this:
int sgetline(int fd, char ** out)
{
int buf_size = 128;
int bytesloaded = 0;
char buf[2];
char * buffer = malloc(buf_size);
char * newbuf;
int size = 0;
assert(NULL != buffer);
while( read(fd, buf, 1) > 0 )
{
strcat(buffer, buf);
buf[1] = '\0';
bytesloaded += strlen(buf);
size = size + buf_size;
if(buf[0] == '\n')
{
*out = buffer;
return bytesloaded;
}
if(bytesloaded >= size)
{
size = size + buf_size;
newbuf = realloc(buffer, size);
if(NULL != newbuf)
{
buffer = newbuf;
}
else
{
printf("sgetline() allocation failed!\n");
exit(1);
}
}
}
*out = buffer;
return bytesloaded;
}
but I have some problems with this function, for example, if the input is something like:
HTTP/1.1 301 Moved Permanently\r\n
Cache-Control:no-cache\r\n
Content-Length:0\r\n
Location\r\nhttp://bing.com/\r\n
\r\n\r\n
and I do
int sockfd = socket( ... );
//....
char* tbuf;
while(sgetline(sockfd, &tbuf) > 0)
{
if(strcmp(tbuf,"\r\n\r\n") == 0)
{
printf("End of Headers detected.\n");
}
}
the above C application does not output "End of Header detected.". Why is this, and how can I fix this?
It's not OK to read one byte at a time, because you are making too many system calls - better is to use a buffer, read a chunk and check if you got \n. After getting a line, the rest of the bytes read remains in the buffer, so you cannot mix read/recv with read_line. Another version of read n bytes using this kind of buffer can be write...
My version to read a line, and a little example to use it.
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#define CBSIZE 2048
typedef struct cbuf {
char buf[CBSIZE];
int fd;
unsigned int rpos, wpos;
} cbuf_t;
int read_line(cbuf_t *cbuf, char *dst, unsigned int size)
{
unsigned int i = 0;
ssize_t n;
while (i < size) {
if (cbuf->rpos == cbuf->wpos) {
size_t wpos = cbuf->wpos % CBSIZE;
//if ((n = read(cbuf->fd, cbuf->buf + wpos, (CBSIZE - wpos))) < 0) {
if((n = recv(cbuf->fd, cbuf->buf + wpos, (CBSIZE - wpos), 0)) < 0) {
if (errno == EINTR)
continue;
return -1;
} else if (n == 0)
return 0;
cbuf->wpos += n;
}
dst[i++] = cbuf->buf[cbuf->rpos++ % CBSIZE];
if (dst[i - 1] == '\n')
break;
}
if(i == size) {
fprintf(stderr, "line too large: %d %d\n", i, size);
return -1;
}
dst[i] = 0;
return i;
}
int main()
{
cbuf_t *cbuf;
char buf[512];
struct sockaddr_in saddr;
struct hostent *h;
char *ip;
char host[] = "www.google.com";
if(!(h = gethostbyname(host))) {
perror("gethostbyname");
return NULL;
}
ip = inet_ntoa(*(struct in_addr*)h->h_addr);
cbuf = calloc(1, sizeof(*cbuf));
fprintf(stdout, "Connecting to ip: %s\n", ip);
if((cbuf->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(80);
inet_aton(ip, &saddr.sin_addr);
if(connect(cbuf->fd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
perror("connect");
return 1;
}
snprintf(buf, sizeof(buf), "GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", host);
write(cbuf->fd, buf, strlen(buf));
while(read_line(cbuf, buf, sizeof(buf)) > 0) {
// if it's an empty \r\n on a line, header ends //
if(buf[0]=='\r' && buf[1] == '\n') {
printf("------------------------\n");
}
printf("[%s]", buf);
}
close(cbuf->fd);
free(cbuf);
return 0;
}
Try this implementation instead:
int sgetline(int fd, char ** out)
{
int buf_size = 0;
int in_buf = 0;
int ret;
char ch;
char * buffer = NULL;
char * new_buffer;
do
{
// read a single byte
ret = read(fd, &ch, 1);
if (ret < 1)
{
// error or disconnect
free(buffer);
return -1;
}
// has end of line been reached?
if (ch == '\n')
break; // yes
// is more memory needed?
if ((buf_size == 0) || (in_buf == buf_size))
{
buf_size += 128;
new_buffer = realloc(buffer, buf_size);
if (!new_buffer)
{
free(buffer);
return -1;
}
buffer = new_buffer;
}
buffer[in_buf] = ch;
++in_buf;
}
while (true);
// if the line was terminated by "\r\n", ignore the
// "\r". the "\n" is not in the buffer
if ((in_buf > 0) && (buffer[in_buf-1] == '\r'))
--in_buf;
// is more memory needed?
if ((buf_size == 0) || (in_buf == buf_size))
{
++buf_size;
new_buffer = realloc(buffer, buf_size);
if (!new_buffer)
{
free(buffer);
return -1;
}
buffer = new_buffer;
}
// add a null terminator
buffer[in_buf] = '\0';
*out = buffer; // complete line
return in_buf; // number of chars in the line, not counting the line break and null terminator
}
int sockfd = socket( ... );
//....
char* tbuf;
int ret;
// keep reading until end of headers is detected.
// headers are terminated by a 0-length line
do
{
// read a single line
ret = sgetline(sockfd, &tbuf);
if (ret < 0)
break; // error/disconnect
// is it a 0-length line?
if (ret == 0)
{
printf("End of Headers detected.\n");
free(tbuf);
break;
}
// tbuf contains a header line, use as needed...
free(tbuf);
}
while (true);
You are making things more difficult for yourself than they need to be. You really don't need to do strcats to get the single character you read on each read added at the current position.
But your bug is that the routine returns as soon as it sees a \n, so the string it returns can never contain anything following the first \n.

Resources