linux serial port : read be blocked mode - linux

My goal is to set 2 threads for serial ports: one for read, one for write.
My example is refer to the [one](//refer to how to open, read, and write from serial port in C) heavily, but I added pthread to my code:
//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h> /* POSIX Threads */
#define MAX_STR_LEN 256
/*
* The values for speed are
* B115200, B230400, B9600, B19200, B38400, B57600, B1200, B2400, B4800, etc
*
* The values for parity are 0 (meaning no parity),
* PARENB|PARODD (enable parity and use odd),
* PARENB (enable parity and use even),
* PARENB|PARODD|CMSPAR (mark parity),
* and PARENB|CMSPAR (space parity).
* */
int SetInterfaceAttribs(int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) /* save current serial port settings */
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return -1;
}
return 0;
}/*set_interface_attribs*/
void SetBlocking(int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0)
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
}/*SetBlocking*/
void *sendThread(void *parameters)
{
char sendBuff[MAX_STR_LEN];
memset(&sendBuff[0], 0, MAX_STR_LEN);
snprintf(&sendBuff[0], MAX_STR_LEN, "hello!");
int fd;
fd = *((int*)parameters);
while(1)
{
write(fd, &sendBuff[0], strlen(&sendBuff[0]) );
// sleep enough to transmit the length plus receive 25:
// approx 100 uS per char transmit
usleep((strlen(&sendBuff[0]) + 25) * 100);
}/*while*/
pthread_exit(0);
}/*sendThread */
void *readThread(void *parameters)
{
char readBuff[MAX_STR_LEN];
int fd;
fd = *((int*)parameters);
while(1)
{
ssize_t len;
memset(&readBuff[0], 0, MAX_STR_LEN);
len = read(fd, &readBuff[0], MAX_STR_LEN);
if (len == -1)
{
switch(errno)
{
case EAGAIN:
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
usleep(5*1000);
continue;
break;
default:
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
pthread_exit(0);
break;
}
}
// sleep enough to transmit the length plus receive 25:
// approx 100 uS per char transmit
usleep((len + 25) * 100);
printf("len = %d\n", (int)len);
int i;
for(i = 0; i< len; i++)
printf("%c(%d %#x)\t", readBuff[i], readBuff[i], readBuff[i]);
printf("\n");
}/*while*/
pthread_exit(0);
}/*readThread */
int main(int argc, char *argv[])
{
int fd, c, res;
struct termios oldtio,newtio;
char buf[MAX_STR_LEN];
int k;
char deviceName[MAX_STR_LEN];
memset(&deviceName[0], 0, MAX_STR_LEN);
snprintf(&deviceName[0], MAX_STR_LEN, "/dev/ttyUSB0");
k = 1;
while(argc > k)
{
if(0 == strncmp(argv[k], "-d", MAX_STR_LEN))
{
if(k + 1 < argc)
{
snprintf(&deviceName[0], MAX_STR_LEN, "%s", argv[k + 1]);
}
else
{
printf("error : -d should be follow a device!\n");
return 0;
}/*if */
}
k++;
}/*while k*/
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
if(0 > fd)
{
perror(&deviceName[0]);
exit(-1);
}/*if */
SetInterfaceAttribs(fd, B115200, 0); /* set speed to 115,200 bps, 8n1 (no parity)*/
SetBlocking(fd, 1);
pthread_t readThread_t, sendThread_t; /* thread variables */
pthread_create(&sendThread_t, NULL, (void *)sendThread, (void *)&fd);
pthread_create(&readThread_t, NULL, (void *)readThread, (void *)&fd);
pthread_join(sendThread_t, NULL);
pthread_join(readThread_t, NULL);
close(fd);
return 0;
}/*main*/
The send data thread works well.
But the read data thread : I could not set it as blocking, the read function returns immediately, even the read data length is zero.
How should I modify the code to make the read function be blocked?

fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
Try removing O_NONBLOCK and O_NDELAY from your open call. Or is there a particular reason you have that even though you specifically want it to block?

Related

How to get unbuffered output from popen & fgets

I'm using popen to execute a command and read the output. I'm setting the file descriptor to non-blocking mode so that I can put in my own timeout, as follows:
auto stream = popen(cmd.c_str(), "r");
int fd = fileno(stream);
int flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
while(!feof(stream)) {
if(fgets(buffer, MAX_BUF, stream) != NULL) {
// do something with buffer...
}
sleep(10);
}
pclose(stream);
This works just fine, except that fgets keeps returning NULL, until the program has finished executing, at which time it returns all the output as expected.
In other words, even if the program immediately outputs some text and a newline to the stdout, my loop doesn't read it immediately; it only sees it later.
In the documentation for popen I see:
Note that output popen() streams are block buffered by default.
I've tried a few things to turn off buffering (ex. setvbuf(stream, NULL, _IONBF, 0)) , but so far no luck.
How do I turn off buffering so that I can read the output in real-time?
Thank you!
A solution based on something like select() would be more accurate and flexible. Try this :
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/select.h>
void read_cmd(const char *cmd)
{
FILE *stream;
int fd;
int flags;
char buffer[1024];
fd_set fdset;
struct timeval timeout;
int rc;
int eof;
stream = popen(cmd, "r");
fd = fileno(stream);
eof = 0;
while(!eof) {
timeout.tv_sec = 10; // 10 seconds
timeout.tv_usec = 0;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
rc = select(fd + 1, &fdset, 0, 0, &timeout);
switch(rc) {
case -1: {
// Error
if (errno != EINTR) {
fprintf(stderr, "select(): error '%m' (%d)\n", errno);
}
return;
}
break;
case 0: {
// Timeout
printf("Timeout\n");
}
break;
case 1: {
// Something to read
rc = read(fd, buffer, sizeof(buffer) - 1);
if (rc > 0) {
buffer[rc] = '\0';
printf("%s", buffer);
fflush(stdout);
}
if (rc < 0) {
fprintf(stderr, "read(): error '%m' (%d)\n", errno);
eof = 1;
}
if (0 == rc) {
// End of file
eof = 1;
}
}
break;
} // End switch
} // End while
pclose(stream);
}
int main(int ac, char *av[])
{
read_cmd(av[1]);
return 0;
} // main

Time consumption of Linux RS485 serial communication

I'm trying to communicate with several Modbus RTU devices through one usb to RS232 to RS485 port at baudrate 38400, 1 start bit, 8databits, no parity and 1 stop bit.
Communication processes with one Modbus RTU device is as follows:
Send 8 bytes to the device;
wait for replies from the device;
Receive 23 bytes of replies.
According to my calculation and the digital oscilloscope, send 8 bytes costs 2.083ms, receive 23 bytes costs 5.99ms, response time of the Modbus RTU device is about 1.3ms. So time of the communication process costs 9.373ms in total.
But in my test program I found the average communication time is about 15ms (10000 times average). I wonder where does the additional 5 more milliseconds come from and how could I optimize my program to reduce this time.
Thanks in advance!
The test program is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
void print_hex_buf(unsigned char *buffer, int size)
{
for (int i=0; i<size; i++)
{
printf("%02x ", buffer[i]);
}
printf("\n");
}
void diff_time(struct timeval t1, struct timeval t2, struct timeval *diff)
{
time_t sec;
suseconds_t usec;
//time in two different days
if (t1.tv_sec > t2.tv_sec)
sec = t2.tv_sec + 24*60*60 - t1.tv_sec;
else
sec = t2.tv_sec - t1.tv_sec;
usec = t2.tv_usec - t1.tv_usec;
if (usec < 0)
{
sec -= 1;
usec += 1000000;
}
diff->tv_sec = sec;
diff->tv_usec = usec;
}
int serial_write(int uart_fd, char *buffer, int size)
{
int count = 0;
count = write(uart_fd, buffer, size);
return count;
}
int serial_read(int uart_fd, char *buffer, int size)
{
int count = 0;
int bytes_read = 0;
int read_retry = 0;
fd_set fds_read;
struct timeval timeout;
FD_ZERO(&fds_read);
FD_SET(uart_fd, &fds_read);
timeout.tv_sec = 0;
timeout.tv_usec = 500000; //500ms
int ret = select(uart_fd + 1, &fds_read, NULL, NULL, &timeout);
if (ret > 0 && FD_ISSET(uart_fd, &fds_read))
{
count = read(uart_fd, buffer, size);
bytes_read = (count > 0)?count:0;
while (bytes_read < size && read_retry++ < 500)
{
count = read(uart_fd, buffer+bytes_read, size-bytes_read);
bytes_read += (count > 0)?count:0;
if (bytes_read >= size)
break;
}
}
else
{
printf("Failed to from uart!\n");
return -1;
}
return bytes_read;
}
int main(int argc, char** argv)
{
int fd;
struct termios opt;
int count;
unsigned char send_buf[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x09, 0x30, 0x0c};
unsigned char buffer[256];
int iteration = 0;
int delay_ms = 0;
int err_count = 0;
int cycle = 0;
suseconds_t average_time = 0;
setbuf(stdout, NULL);
if (argc != 3)
{
printf("Usage: testuart [uart device] [iteration]\n");
return 0;
}
iteration = atoi(argv[2]);
fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
printf("Failed to open port: %s\n", argv[1]);
return -1;
}
if (tcgetattr(fd, &opt) != 0)
{
printf("Failed to get uart attribute!\n");
return -1;
}
opt.c_cflag = B38400|CS8|CREAD|CLOCAL;
opt.c_iflag = IGNPAR;
opt.c_cflag &= ~PARENB;
opt.c_cflag &= ~PARODD;
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
opt.c_oflag &= ~OPOST;
opt.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &opt) != 0)
{
printf("Failed to setup serial port!\n");
close(fd);
return -1;
}
while (cycle++ < iteration)
{
printf("Send hex command:\n");
print_hex_buf(send_buf, 8);
struct timeval tm_start;
struct timeval tm_end;
struct timeval tm_diff;
gettimeofday(&tm_start, NULL);
count = serial_write(fd, send_buf, 8);
if (count != 8)
{
printf("Failed to write 8 bytes!\n");
close(fd);
return -1;
}
count = serial_read(fd, buffer, 23);
if (count <= 0)
{
printf("serial read returns %d\n", count);
close(fd);
return -1;
}
gettimeofday(&tm_end, NULL);
diff_time(tm_start, tm_end, &tm_diff);
print_hex_buf(buffer, count);
printf("serial communication costs %ld.%06ld seconds.\n",
tm_diff.tv_sec, tm_diff.tv_usec);
average_time = ((average_time*(cycle-1))+tm_diff.tv_usec)/cycle;
}
printf("%d times, average time in usec is %ld\n", cycle-1, average_time);
close(fd);
return 0;
}
Thanks to sawdust!
The following link helps! The average time has reduced from 15ms to 10ms.
High delay in RS232 communication on a PXA270

Segmentation Fault Error When Reading Two Serial Port with BeagleBone Black

I am getting Segmentation fault error while reading two diffentent serial communication line with using Debian GNU/Linux 7.4 on Beaglebone Black. One of them is CAN-BUS data. I am using Waveshares RS485/CAN CAPE module for this with using can-utils package. "https://github.com/linux-can/can-utils/blob/master/candump.c"
CAN log file
And the other one is UART data by a GPS module called uBlox GY-NEO6MV2 module. For the GPS I have this code which works perfectly;
#include <stdio.h>
#include <fcntl.h> /* File Control Definitions */
#include <termios.h> /* POSIX Terminal Control Definitions */
#include <unistd.h> /* UNIX Standard Definitions */
#include <errno.h> /* ERROR Number Definitions */
#include <string.h> /* Array to String */
void main(void){
int fd;/*File Descriptor*/
/*------------------------------- Opening the Serial Port -------------------------------*/
/* Change /dev/ttyUSB0 to the one corresponding to your system */
while(1){
fd = open("/dev/ttyO2",O_RDWR | O_NOCTTY); /* ttyUSB0 is the FT232 based USB2SERIAL Converter */
/* O_RDWR - Read/Write access to serial port */
/* O_NOCTTY - No terminal will control the process */
/* Open in blocking mode,read will wait */
if(fd == -1) /* Error Checking */
printf("\n Error! in Opening ttyO2 ");
else
printf("\n ttyO2 Opened Successfully ");
/*---------- Setting the Attributes of the serial port using termios structure --------- */
struct termios SerialPortSettings; /* Create the structure */
tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */
/* Setting the Baud rate */
cfsetispeed(&SerialPortSettings,B9600); /* Set Read Speed as 9600 */
cfsetospeed(&SerialPortSettings,B9600); /* Set Write Speed as 9600 */
/* 8N1 Mode */
SerialPortSettings.c_cflag &= ~PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
SerialPortSettings.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 42; /* Read at least 51 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 9600 \n StopBits = 1 \n Parity = none \n\n");
/*------------------------------- Read data from serial port -----------------------------*/
tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
char read_buffer[42]; /* Buffer to store the data received */
int bytes_read = 0; /* Number of bytes read by the read() system call */
int ia = 0; int a;
int test = 0;
char new_read[38];
char curr_read[33];
a = 0;
do{
bytes_read = read(fd,&read_buffer,42); /* Read the data */
if(read_buffer[0] == '$')
if(read_buffer[1] == 'G')
if(read_buffer[2] == 'P')
if(read_buffer[3] == 'G')
if(read_buffer[4] == 'G'){
for(ia=7;ia<bytes_read;ia++){ /*printing only the received characters*/
new_read[a] = read_buffer[ia];
printf("%c",read_buffer[ia]);
a = a+1;
test = 1;
}
strcpy(curr_read, new_read);
printf("\n%s \n", curr_read);
}
else
test = 0;
else
test = 0;
else
test = 0;
else
test = 0;
else
test = 0;
}while(test == 0);
close(fd); /* Close the serial port */
}
}
And for the CAN logging I am using the code in the link above. What I try to achive is logging two data in to same log file. I modified the code above a little to get the datas only that I need; which is timestamp and location coordinates.
GPS edited data
GPS module gives data every second so I am triyng to get one data from GPS and attach it to the next 1000 CAN data then write in to a .log file then read a new value from GPS. GPS modules communication bitrate is 9600kbps and CAN bitrate is 125000 kbps. GPS is connected to UART2 pin, CAN to UART1. When I try to combine two code into one I get the Segmentation fault error. I made a little research its UNIX error code while violeting the restiricted memory space. But these two codes works perfectly when working seperatly. This is where I got stucked.
The code I tried to merge is like;
/* for hardware timestamps - since Linux 2.6.30 */
#ifndef SO_TIMESTAMPING
#define SO_TIMESTAMPING 37
#endif
/* from #include <linux/net_tstamp.h> - since Linux 2.6.30 */
#define SOF_TIMESTAMPING_SOFTWARE (1<<4)
#define SOF_TIMESTAMPING_RX_SOFTWARE (1<<3)
#define SOF_TIMESTAMPING_RAW_HARDWARE (1<<6)
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
#define MAXIFNAMES 30 /* size of receive name index to omit ioctls */
#define MAXCOL 6 /* number of different colors for colorized output */
#define ANYDEV "any" /* name of interface to receive from any CAN interface */
#define ANL "\r\n" /* newline in ASC mode */
#define SILENT_INI 42 /* detect user setting on commandline */
#define SILENT_OFF 0 /* no silent mode */
#define SILENT_ANI 1 /* silent mode with animation */
#define SILENT_ON 2 /* silent mode (completely silent) */
static char *cmdlinename[MAXSOCK];
static __u32 dropcnt[MAXSOCK];
static __u32 last_dropcnt[MAXSOCK];
static char devname[MAXIFNAMES][IFNAMSIZ+1];
static int dindex[MAXIFNAMES];
static int max_devname_len; /* to prevent frazzled device name output */
const int canfd_on = 1;
#define MAXANI 4
const char anichar[MAXANI] = {'|', '/', '-', '\\'};
const char extra_m_info[4][4] = {"- -", "B -", "- E", "B E"};
extern int optind, opterr, optopt;
static volatile int running = 1;
void sigterm(int signo)
{
running = 0;
}
int idx2dindex(int ifidx, int socket) {
int i;
struct ifreq ifr;
for (i=0; i < MAXIFNAMES; i++) {
if (dindex[i] == ifidx)
return i;
}
/* create new interface index cache entry */
/* remove index cache zombies first */
for (i=0; i < MAXIFNAMES; i++) {
if (dindex[i]) {
ifr.ifr_ifindex = dindex[i];
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
dindex[i] = 0;
}
}
for (i=0; i < MAXIFNAMES; i++)
if (!dindex[i]) /* free entry */
break;
if (i == MAXIFNAMES) {
fprintf(stderr, "Interface index cache only supports %d interfaces.\n",
MAXIFNAMES);
exit(1);
}
dindex[i] = ifidx;
ifr.ifr_ifindex = ifidx;
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
perror("SIOCGIFNAME");
if (max_devname_len < strlen(ifr.ifr_name))
max_devname_len = strlen(ifr.ifr_name);
strcpy(devname[i], ifr.ifr_name);
#ifdef DEBUG
printf("new index %d (%s)\n", i, devname[i]);
#endif
return i;
}
int main(int argc, char **argv)
{
fd_set rdfs;
int s[MAXSOCK];
int bridge = 0;
useconds_t bridge_delay = 0;
unsigned char timestamp = 0;
unsigned char hwtimestamp = 0;
unsigned char down_causes_exit = 1;
unsigned char dropmonitor = 0;
unsigned char extra_msg_info = 0;
unsigned char silent = SILENT_INI;
unsigned char silentani = 0;
unsigned char color = 0;
unsigned char view = 0;
unsigned char log = 0;
unsigned char logfrmt = 0;
int count = 0;
int rcvbuf_size = 0;
int opt, ret;
int currmax, numfilter;
int join_filter;
char *ptr, *nptr;
struct sockaddr_can addr;
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3*sizeof(struct timespec) + sizeof(__u32))];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
struct can_filter *rfilter;
can_err_mask_t err_mask;
struct canfd_frame frame;
int nbytes, i, maxdlen;
struct ifreq ifr;
struct timeval tv, last_tv;
struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
FILE *logfile = NULL;
int fd;/*File Descriptor*/
struct termios SerialPortSettings; /* Create the structure */
signal(SIGTERM, sigterm);
signal(SIGHUP, sigterm);
signal(SIGINT, sigterm);
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
if (optind == argc) {
print_usage(basename(argv[0]));
exit(0);
}
if (logfrmt && view) {
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP options!\n");
exit(0);
}
if (silent == SILENT_INI) {
if (log) {
fprintf(stderr, "Disabled standard output while logging.\n");
silent = SILENT_ON; /* disable output on stdout */
} else
silent = SILENT_OFF; /* default output */
}
currmax = argc - optind; /* find real number of CAN devices */
if (currmax > MAXSOCK) {
fprintf(stderr, "More than %d CAN devices given on commandline!\n", MAXSOCK);
return 1;
}
for (i=0; i < currmax; i++) {
ptr = argv[optind+i];
nptr = strchr(ptr, ',');
#ifdef DEBUG
printf("open %d '%s'.\n", i, ptr);
#endif
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s[i] < 0) {
perror("socket");
return 1;
}
cmdlinename[i] = ptr; /* save pointer to cmdline name of this socket */
if (nptr)
nbytes = nptr - ptr; /* interface name is up the first ',' */
else
nbytes = strlen(ptr); /* no ',' found => no filter definitions */
if (nbytes >= IFNAMSIZ) {
fprintf(stderr, "name of CAN device '%s' is too long!\n", ptr);
return 1;
}
if (nbytes > max_devname_len)
max_devname_len = nbytes; /* for nice printing */
addr.can_family = AF_CAN;
memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, ptr, nbytes);
#ifdef DEBUG
printf("using interface name '%s'.\n", ifr.ifr_name);
#endif
if (strcmp(ANYDEV, ifr.ifr_name)) {
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
exit(1);
}
addr.can_ifindex = ifr.ifr_ifindex;
} else
addr.can_ifindex = 0; /* any can interface */
if (nptr) {
/* found a ',' after the interface name => check for filters */
/* determine number of filters to alloc the filter space */
numfilter = 0;
ptr = nptr;
while (ptr) {
numfilter++;
ptr++; /* hop behind the ',' */
ptr = strchr(ptr, ','); /* exit condition */
}
rfilter = malloc(sizeof(struct can_filter) * numfilter);
if (!rfilter) {
fprintf(stderr, "Failed to create filter space!\n");
return 1;
}
numfilter = 0;
err_mask = 0;
join_filter = 0;
while (nptr) {
ptr = nptr+1; /* hop behind the ',' */
nptr = strchr(ptr, ','); /* update exit condition */
if (sscanf(ptr, "%x:%x",
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
numfilter++;
} else if (sscanf(ptr, "%x~%x",
&rfilter[numfilter].can_id,
&rfilter[numfilter].can_mask) == 2) {
rfilter[numfilter].can_id |= CAN_INV_FILTER;
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
numfilter++;
} else if (*ptr == 'j' || *ptr == 'J') {
join_filter = 1;
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr);
return 1;
}
}
if (err_mask)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
&err_mask, sizeof(err_mask));
if (join_filter && setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
&join_filter, sizeof(join_filter)) < 0) {
perror("setsockopt CAN_RAW_JOIN_FILTERS not supported by your Linux Kernel");
return 1;
}
if (numfilter)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
rfilter, numfilter * sizeof(struct can_filter));
free(rfilter);
} /* if (nptr) */
/* try to switch the socket into CAN FD mode */
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
if (rcvbuf_size) {
int curr_rcvbuf_size;
socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size);
/* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUFFORCE,
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
#ifdef DEBUG
printf("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n");
#endif
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
perror("setsockopt SO_RCVBUF");
return 1;
}
if (getsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
&curr_rcvbuf_size, &curr_rcvbuf_size_len) < 0) {
perror("getsockopt SO_RCVBUF");
return 1;
}
/* Only print a warning the first time we detect the adjustment */
/* n.b.: The wanted size is doubled in Linux in net/sore/sock.c */
if (!i && curr_rcvbuf_size < rcvbuf_size*2)
fprintf(stderr, "The socket receive buffer size was "
"adjusted due to /proc/sys/net/core/rmem_max.\n");
}
}
if (timestamp || log || logfrmt) {
if (hwtimestamp) {
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \
SOF_TIMESTAMPING_RX_SOFTWARE | \
SOF_TIMESTAMPING_RAW_HARDWARE);
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING,
&timestamping_flags, sizeof(timestamping_flags)) < 0) {
perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel");
return 1;
}
} else {
const int timestamp_on = 1;
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
&timestamp_on, sizeof(timestamp_on)) < 0) {
perror("setsockopt SO_TIMESTAMP");
return 1;
}
}
}
if (dropmonitor) {
const int dropmonitor_on = 1;
if (setsockopt(s[i], SOL_SOCKET, SO_RXQ_OVFL,
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
return 1;
}
}
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return 1;
}
}
if (log) {
time_t currtime;
struct tm now;
char fname[sizeof("candump-2006-11-20_202026.log")+1];
if (time(&currtime) == (time_t)-1) {
perror("time");
return 1;
}
localtime_r(&currtime, &now);
sprintf(fname, "candump-%04d-%02d-%02d_%02d%02d%02d.log",
now.tm_year + 1900,
now.tm_mon + 1,
now.tm_mday,
now.tm_hour,
now.tm_min,
now.tm_sec);
if (silent != SILENT_ON)
printf("\nWarning: console output active while logging!");
fprintf(stderr, "\nEnabling Logfile '%s'\n\n", fname);
logfile = fopen(fname, "w");
if (!logfile) {
perror("logfile");
return 1;
}
}
/* these settings are static and can be held out of the hot path */
iov.iov_base = &frame;
msg.msg_name = &addr;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &ctrlmsg;
while (running) {
/*------------------------------- Opening the Serial Port -------------------------------*/
/* Change /dev/ttyUSB0 to the one corresponding to your system */
fd = open("/dev/ttyO2",O_RDWR | O_NOCTTY); /* ttyUSB0 is the FT232 based USB2SERIAL Converter */
/* O_RDWR - Read/Write access to serial port */
/* O_NOCTTY - No terminal will control the process */
/* Open in blocking mode,read will wait */
/* Error Checking */
if(fd == -1)
printf("\n Error! in Opening ttyO2 ");
else
printf("\n ttyO2 Opened Successfully ");
/*---------- Setting the Attributes of the serial port using termios structure --------- */
//struct termios SerialPortSettings; /* Create the structure */
tcgetattr(fd, &SerialPortSettings); /* Get the current attributes of the Serial port */
/* Setting the Baud rate */
cfsetispeed(&SerialPortSettings,B9600); /* Set Read Speed as 9600 */
cfsetospeed(&SerialPortSettings,B9600); /* Set Write Speed as 9600 */
/* 8N1 Mode */
SerialPortSettings.c_cflag &= ~PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
SerialPortSettings.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing*/
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 42; /* Read at least 42 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0) /* Set the attributes to the termios structure*/
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 9600 \n StopBits = 1 \n Parity = none \n\n");
/*------------------------------- Read data from serial port -----------------------------*/
tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
char read_buffer[42]; /* Buffer to store the data received */
int bytes_read = 0; /* Number of bytes read by the read() system call */
int ia = 0; int a;
int test = 0;
char new_read[38];
char curr_read[33];
int countc = 0;
a = 0;
do{
bytes_read = read(fd,&read_buffer,42); /* Read the data */
if(read_buffer[0] == '$')
if(read_buffer[1] == 'G')
if(read_buffer[2] == 'P')
if(read_buffer[3] == 'G')
if(read_buffer[4] == 'G'){
for(ia=7;ia<bytes_read;ia++){ /*printing only the received characters*/
new_read[a] = read_buffer[ia];
//printf("%c",read_buffer[ia]);
a = a+1;
test = 1;
}
strcpy(curr_read, new_read);
//printf("\n%s \n", curr_read);
}
else
test = 0;
else
test = 0;
else
test = 0;
else
test = 0;
else
test = 0;
}while(test == 0);
//tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
close(fd); /* Close the serial port */
while(countc < 1000){
FD_ZERO(&rdfs);
for (i=0; i<currmax; i++)
FD_SET(s[i], &rdfs);
if (timeout_current)
*timeout_current = timeout_config;
if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, timeout_current)) <= 0) {
//perror("select");
running = 0;
continue;
}
for (i=0; i<currmax; i++) { /* check all CAN RAW sockets */
if (FD_ISSET(s[i], &rdfs)) {
int idx;
/* these settings may be modified by recvmsg() */
iov.iov_len = sizeof(frame);
msg.msg_namelen = sizeof(addr);
msg.msg_controllen = sizeof(ctrlmsg);
msg.msg_flags = 0;
nbytes = recvmsg(s[i], &msg, 0);
idx = idx2dindex(addr.can_ifindex, s[i]);
if (nbytes < 0) {
if ((errno == ENETDOWN) && !down_causes_exit) {
fprintf(stderr, "%s: interface down\n", devname[idx]);
continue;
}
perror("read");
return 1;
}
if ((size_t)nbytes == CAN_MTU)
maxdlen = CAN_MAX_DLEN;
else if ((size_t)nbytes == CANFD_MTU)
maxdlen = CANFD_MAX_DLEN;
else {
fprintf(stderr, "read: incomplete CAN frame\n");
return 1;
}
if (count && (--count == 0))
running = 0;
if (bridge) {
if (bridge_delay)
usleep(bridge_delay);
nbytes = write(bridge, &frame, nbytes);
if (nbytes < 0) {
perror("bridge write");
return 1;
} else if ((size_t)nbytes != CAN_MTU && (size_t)nbytes != CANFD_MTU) {
fprintf(stderr,"bridge write: incomplete CAN frame\n");
return 1;
}
}
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
if (cmsg->cmsg_type == SO_TIMESTAMP) {
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
/*
* stamp[0] is the software timestamp
* stamp[1] is deprecated
* stamp[2] is the raw hardware timestamp
* See chapter 2.1.2 Receive timestamps in
* linux/Documentation/networking/timestamping.txt
*/
tv.tv_sec = stamp[2].tv_sec;
tv.tv_usec = stamp[2].tv_nsec/1000;
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
memcpy(&dropcnt[i], CMSG_DATA(cmsg), sizeof(__u32));
}
/* check for (unlikely) dropped frames on this specific socket */
if (dropcnt[i] != last_dropcnt[i]) {
__u32 frames = dropcnt[i] - last_dropcnt[i];
if (silent != SILENT_ON)
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
if (log)
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
last_dropcnt[i] = dropcnt[i];
}
/* once we detected a EFF frame indent SFF frames accordingly */
if (frame.can_id & CAN_EFF_FLAG)
view |= CANLIB_VIEW_INDENT_SFF;
if (log) { /* CODE GETS IN TO THIS PART */
char buf[CL_CFSZ]; /* max length */ /* WHEN PRINTING INTO FILE */
/* */
/* log CAN frame with absolute timestamp & device */ /* */
sprint_canframe(buf, &frame, 0, maxdlen); /* */
fprintf(logfile, "%s %*s %s\n", /* */
curr_read, /* */
max_devname_len, devname[idx], buf); /* */
} /* */
if (logfrmt) {
char buf[CL_CFSZ]; /* max length */
/* print CAN frame in log file style to stdout */
sprint_canframe(buf, &frame, 0, maxdlen);
printf("(%010ld.%06ld) %*s %s\n",
tv.tv_sec, tv.tv_usec,
max_devname_len, devname[idx], buf);
goto out_fflush; /* no other output to stdout */
}
if (silent != SILENT_OFF){
if (silent == SILENT_ANI) {
printf("%c\b", anichar[silentani%=MAXANI]);
silentani++;
}
goto out_fflush; /* no other output to stdout */
}
printf(" %s", (color>2)?col_on[idx%MAXCOL]:"");
switch (timestamp) {
case 'a': /* absolute with timestamp */
printf("(%010ld.%06ld) ", tv.tv_sec, tv.tv_usec);
break;
case 'A': /* absolute with date */
{
struct tm tm;
char timestring[25];
tm = *localtime(&tv.tv_sec);
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
printf("(%s.%06ld) ", timestring, tv.tv_usec);
}
break;
case 'd': /* delta */
case 'z': /* starting with zero */
{
struct timeval diff;
if (last_tv.tv_sec == 0) /* first init */
last_tv = tv;
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
if (diff.tv_usec < 0)
diff.tv_sec--, diff.tv_usec += 1000000;
if (diff.tv_sec < 0)
diff.tv_sec = diff.tv_usec = 0;
printf("(%03ld.%06ld) ", diff.tv_sec, diff.tv_usec);
if (timestamp == 'd')
last_tv = tv; /* update for delta calculation */
}
break;
default: /* no timestamp output */
break;
}
printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:"");
printf("%*s", max_devname_len, devname[idx]);
if (extra_msg_info) {
if (msg.msg_flags & MSG_DONTROUTE)
printf (" TX %s", extra_m_info[frame.flags & 3]);
else
printf (" RX %s", extra_m_info[frame.flags & 3]);
}
printf("%s ", (color==1)?col_off:"");
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
printf("%s", (color>1)?col_off:"");
printf("\n");
}
out_fflush:
fflush(stdout);
}
countc = countc +1;
}
}
for (i=0; i<currmax; i++)
close(s[i]);
if (bridge)
close(bridge);
if (log)
fclose(logfile);
return 0;
}
Actually everything matters works in while(running) block. Inside this block when I make the bytes_read = read(fd,&read_buffer,42); as comment, it didn't write anything but also doesn't give the Segmentation fault error. Same also happens when I connect the GPS' TX pin in to BBB. So the problem starts to occur when the data is coming from the GPS and read by the BBB.
Segmentation Fault Err
What should I do about it?
Thanks.
Your GPS reading code
char new_read[38];
char curr_read[33];
strcpy(curr_read, new_read);
is copying a 38 char buffer into a 33 char buffer, which can result in bad things.
Strcpy will copy the contents of the source buffer into the destination buffer until it reads NULL from the source buffer. If the NULL char is at the 36th position in new_read, strcpy will be writing in random memory which can cause the segmentation fault.
I am guessing that when you run your GPS reading code as stand-alone, the writing into random memory goes un-noticed, but when you combine it with the CAN bus reading, it writes into allocated space and the error happens.

Thread issue in socket Programming

I have the following codes..
server.c
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
static int clients = 0;
static int* memptr = NULL;
void serve(void*);
int* push(int* memptr, int nsfd) {
clients++;
if (clients == 1)
memptr = (int*)malloc(sizeof(int) * clients);
else
memptr = (int*)realloc(memptr, sizeof(int) * clients);
memptr[clients - 1] = nsfd;
return memptr;
}
int main(int argc, char** argv) {
pthread_t thread[2];
int threadCount = 0;
if (argc != 3){
printf("\nUsage: ./server port_number maximum_clients\n");
return 1;
}
static struct sockaddr_in sock, sock_client;
int len, new_sock_fd;
int sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr("0.0.0.0");
len = sizeof(sock);
if ( bind(sock_fd, (struct sockaddr *)&sock, len) == -1){
perror("bind");
exit(1);
}
if ( listen(sock_fd, atoi(argv[2])) == -1){
perror("listen");
exit(1);
}
while(1) {
new_sock_fd = accept(sock_fd, (struct sockaddr *)&sock_client, (socklen_t *)&len);
memptr = push(memptr, new_sock_fd);
if (new_sock_fd == -1){
perror("accept");
exit(1);
}
pthread_create(&(thread[threadCount]), NULL, (void*)&serve, (void *)&new_sock_fd);
pthread_join(thread[threadCount++], NULL);
printf("threadCount = %d\n", threadCount);
sleep(1);
}
return 0;
}
void serve(void* fd){
int* new_sock_fd = (int*)fd;
Packet packet;
while(1){
bzero(&packet, sizeof(packet));
read(*new_sock_fd , &packet, sizeof(packet));
printf("%d\n", *new_sock_fd);
//printf("recipientId = %d\n", packet.recipientId);
// printf("message = %s\n", packet.data);
write(memptr[packet.recipientId - 1], packet.data, 1024);
}
pthread_exit(0);
}
and the tcp.h looks like
#ifndef __TCP_H__
# define __TCP_H__
typedef struct {
int recipientId; // this is the reciever ID
char data[1024]; // this is the main data part
}Packet;
#endif /* __TCP_H__ */
and each client.h looks like this
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
void print(void);
void scan(void);
int sock_fd;
int main(int argc, char** argv) {
if (argc != 3){
printf("\nUsage: ./client port_number server_ip\n");
return 1;
}
static struct sockaddr_in sock;
int len;
pthread_t thread1, thread2;
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr(argv[2]);
len = sizeof(sock);
if ( connect(sock_fd, (struct sockaddr *)&sock , len) == -1 ){
perror("connect");
exit(1);
}
pthread_create(&thread1, NULL, (void*)&print, NULL);
pthread_create(&thread2, NULL, (void*)&scan, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void print(){
char messege[1024];
while(1){
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
}
pthread_exit(0);
}
void scan(void){
Packet packet;
while(1){
printf("Enter the reciver ID: ");
scanf("%d", &packet.recipientId);
printf("Enter the data: ");
scanf("%s", packet.data);
if ( write(sock_fd, &packet, sizeof(packet)) == -1) {
perror("read");
return;
}
}
pthread_exit(0);
}
Now the problems are
when I am running the server & the in 2 terminals, 2 clients after each client is accepted threadCount should be printed at the server end but it is not printing. It means the execution stops/skips after the first pthread_join but WHY ??
After connecting two threads, when I sent the data from 1st client to the 1st client itself, it works but not from the 1st client to the 2nd client..rather it is sending to the server terminal window. WHY ??
When sent from the second client nothing works ( sending itself or client 1)..WHY??
Please help..And thanks for patiently reading all the codes above.
TCP is a byte stream protocol, not a message protocol. You are calling TCP functions and expecting them to send or receive messages. They don't. If you want to send or receive messages, you have to implement a message protocol, write functions that send and receive messages, and then call those functions.
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
This call to printf is a disaster. The %s format specifier is for C-style strings, not arbitrary chunks of bytes received from a byte stream. For the most obvious way to see how bad this is, consider this --- how should printf decide how many bytes to print? You threw away the value read returned after you compared it to -1, so you have no idea how many bytes you received.
I'm sure there are other issues with your code, but the fact that the fundamental design is broken makes it not worth fixing those issues. Instead, design a message protocol and implement that.

create SOCK_RAW socket just for sending data without any recvform()

If I create a socket whose type is SOCK_RAW only to send some data without receiving any data, is there any problem when kernel continue to receive network packets and copy its datagram to somebuffer (of application?). In other words, after the somebuffer is filled what will happened? error or ignore?
I don't know how to prevent kernel from delivering the copy of datagram to my application.
Reference http://sock-raw.org/papers/sock_raw 0x4 raw_input
After the IP layer processes
a new incoming IP datagram, it calls ip_local_deliver_finish() kernel function
which is responsibe for calling a registered transport protocol handler by
inspecting the protocol field of the IP header (remember from above). However
before it delivers the datagram to the handler, it checks every time if an
application has created a raw socket with the same protocol number. If there
is one or more such applications, it makes a copy of the datagram and delivers
it to them as well.
You can use shutdown(2) in order to shutdown reception part of the socket.
See shutdown man page
EDIT : I found that shutdown only works on connected (ie TCP) sockets.
With Raw socket, there are 2 possibilities :
Receive data into a temporary buffer (with recv) and discard them (perhaps in an other thread)
If I remember well, when the socket buffer is full, incoming data are automatically discarded (and data in the buffer aren't modified), so you can set the socket reception buffer size to 0 (and increase it later if needed).
Here's how to set reception buffer size to 0 :
int opt = 0;
setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
TEST
/**
* #file raw_print_pkt.c
* #brief
* #author Airead Fan <fgh1987168#gmail.com>
* #date 2012/08/22 12:35:22
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
int main(int argc, char *argv[])
{
int s;
ssize_t rn; /* receive number */
struct sockaddr_in saddr;
char packet[4096];
int count;
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(packet));
socklen_t *len = (socklen_t *)sizeof(saddr);
int fromlen = sizeof(saddr);
int opt = 0;
count = 0;
while(1) {
if ((rn = recvfrom(s, (char *)&packet, sizeof(packet), 0,
(struct sockaddr *)&saddr, &fromlen)) < 0)
perror("packet receive error:");
if (rn == 0) {
printf("the peer has performed an orderly shutdown\n");
break;
}
printf("[%d] rn = %lu \n", count++, rn);
if (count == 16) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
perror("setsocketopt failed");
} else {
fprintf(stdout, "setsocketopt successful\n");
}
// int shutdown(int sockfd, int how);
/* if (shutdown(s, SHUT_RD) < 0) {
* perror("shutdown failed");
* } */
}
}
return 0;
}
TEST 2 (same includes):
int main(int argc, char *argv[])
{
int s;
ssize_t rn; /* receive number */
char packet[4096];
int count;
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(packet));
int opt = 0;
count = 0;
//Set recv buffer size
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
perror("setsocketopt failed");
} else {
fprintf(stdout, "setsocketopt successful\n");
}
//10 seconds countdown
int i = 10;
while(i > 0)
{
printf("\r%d ", i);
fflush(stdout);
i--;
sleep(1);
}
printf("\n");
while(1) {
if ((rn = recv(s, (char *)&packet, sizeof(packet), 0)) <= 0)
perror("packet receive error:");
printf("[%d] rn = %lu \n", count++, rn);
}
return 0;
}
Here's how to proceed with test 2 :
First of all, set the buffer size to 4096 (or bigger if you have a lot of traffic on your network). Compile and launch. During the 10 seconds before starting receiving data, send a lot of data to the socket. After the 10 seconds, the program will receive everything you sent during the countdown.
After that, set the buffer size to 0. Proceed as previously. After the 10 seconds, the program won't receive the data you sent during the countdown. But if you send data while it's in recvfrom, it will read them normally.
I don't really understand what you want! if you want just to inject some packets, it's simple:
#include<netinet/tcp.h> /* TCP header */
#include<netinet/ip.h> /* IP header */
/* Checksum compute function */
/* source : http://www.winpcap.org/pipermail/winpcap-users/2007-July/001984.html */
unsigned short checksum(unsigned short *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(unsigned short);
}
if(size)
cksum += *(UCHAR*)buffer;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (unsigned short)(~cksum);
}
int main (int argc, char **argv)
{
char packet_buffer[BUFFER_SIZE];
struct sockaddr_in sin;
struct iphdr *ip_header; /* IP header */
struct tcphdr *tcp_header; /* TCP header */
int flag = 1;
/* Creating RAW socket */
int raw_socket = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
ip_header = (struct iphdr *) packet_buffer;
tcp_header = (struct tcphdr *) (packet_buffer + sizeof (struct ip));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT_NUMBER);
sin.sin_addr.s_addr = inet_addr (IP_ADDRESS);
/* Zeroing the bbuffer */
memset (packet_buffer, 0, BUFFER_SIZE);
/* Construct your IP Header */
ip_header->ihl = 5;
ip_header->version = 4;
ip_header->tos = 0;
ip_header->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
ip_header->id = htonl(CHOOSE_PACKET_ID);
ip_header->frag_off = 0;
ip_header->ttl = 255;
ip_header->protocol = 6; /* TCP. Change to 17 if you want UDP */
ip_header->check = 0;
ip_header->saddr = inet_addr (SOURCE_IP_ADDRESS_TO_SPOOF);
ip_header->daddr = sin.sin_addr.s_addr;
/* Construct your TCP Header */
tcp_header->source = htons (SOURCE);
tcp_header->dest = htons(DEST);
tcp_header->seq = random();
tcp_header->ack_seq = 0;
tcp_header->doff = 0;
tcp_header->syn = 1;
tcp_header->window = htonl(65535);
tcp_header->check = 0;
tcp_header->urg_ptr = 0;
/* IP Checksum */
ip_header->check = checksum((unsigned short *) packet_buffer, ip_header->tot_len >> 1);
if (setsockopt(raw_socket, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(flag)) < 0)
{
/* ERROR handling */
}
while (1)
{
/* Send the packet */
if (sendto(raw_socket, packet_buffer, ip_header->tot_len, 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
/* ERROR handling */
}
/* The rest of your need */
}
return 0;
}

Resources