I have written a client code for mqtt which is supposed to connect (just connect to server for now) to a active mq server. following is the code:
#include "stdafx.h"
#include<iostream>
#include<winsock2.h>
#include "mqtt.h"
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#include <stdlib.h>
#include <winsock2.h>
void mqtt_init(mqtt_broker_handle_t* broker, const char* clientid) {
// Connection options
broker->alive = 300; // 300 seconds = 5 minutes
broker->seq = 1; // Sequence for message identifiers
// Client options
memset(broker->clientid, 0, sizeof(broker->clientid));
memset(broker->username, 0, sizeof(broker->username));
memset(broker->password, 0, sizeof(broker->password));
if(clientid) {
strncpy_s(broker->clientid, clientid, sizeof(broker->clientid));
} else {
strcpy_s(broker->clientid, "emqtt");
}
// Will topic
broker->clean_session = 1;
}
void mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const char* password)
{
if(username && username[0] != '\0')
strncpy_s(broker->username, username, sizeof(broker->username)-1);
if(password && password[0] != '\0')
strncpy_s(broker->password, password, sizeof(broker->password)-1);
}
using namespace std;
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char message[1000] , server_reply[2000];
int recv_size;
int packet_length;
uint16_t msg_id, msg_id_rcv;
mqtt_broker_handle_t broker;
mqtt_init(&broker, "localhost");
mqtt_init_auth(&broker, "cid", "campeador");
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) {
cout<<"Failed. Error Code : "<<WSAGetLastError();
return 1;
}
cout<<"Initialised.\n";
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
cout<<"Could not create socket : " << WSAGetLastError();
}
cout<<"Socket created.\n";
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 1993);
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
mqtt_connect(&broker);
recv_size = recv(s, server_reply, 2000, 0);
server_reply[recv_size] = '\0';
while ( server_reply != "end"){
cout<<server_reply<<endl;
recv_size = recv(s, server_reply, 2000, 0);
server_reply[recv_size] = '\0';
}
closesocket(s);
WSACleanup();
return 0;
}
And also the following is the code for mqtt.h
#ifndef __LIBEMQTT_H__
#define __LIBEMQTT_H__
#endif
#include <stdint.h>
#include <string.h>
#ifndef MQTT_CONF_USERNAME_LENGTH
#define MQTT_CONF_USERNAME_LENGTH 13 // Recommended by MQTT Specification (12 + '\0')
#endif
#ifndef MQTT_CONF_PASSWORD_LENGTH
#define MQTT_CONF_PASSWORD_LENGTH 13 // Recommended by MQTT Specification (12 + '\0')
#endif
#define MQTT_MSG_CONNECT 1<<4
#define MQTT_MSG_CONNACK 2<<4
#define MQTT_MSG_PUBLISH 3<<4
#define MQTT_MSG_PUBACK 4<<4
#define MQTT_MSG_PUBREC 5<<4
#define MQTT_MSG_PUBREL 6<<4
#define MQTT_MSG_PUBCOMP 7<<4
#define MQTT_MSG_SUBSCRIBE 8<<4
#define MQTT_MSG_SUBACK 9<<4
#define MQTT_MSG_UNSUBSCRIBE 10<<4
#define MQTT_MSG_UNSUBACK 11<<4
#define MQTT_MSG_PINGREQ 12<<4
#define MQTT_MSG_PINGRESP 13<<4
#define MQTT_MSG_DISCONNECT 14<<4
#define MQTT_DUP_FLAG 1<<3
#define MQTT_QOS0_FLAG 0<<1
#define MQTT_QOS1_FLAG 1<<1
#define MQTT_QOS2_FLAG 2<<1
#define MQTT_RETAIN_FLAG 1
#define MQTT_CLEAN_SESSION 1<<1
#define MQTT_WILL_FLAG 1<<2
#define MQTT_WILL_RETAIN 1<<5
#define MQTT_USERNAME_FLAG 1<<7
#define MQTT_PASSWORD_FLAG 1<<6
typedef struct {
void* socket_info;
int (*send)(void* socket_info, const void* buf, unsigned int count);
// Connection info
char clientid[50];
// Auth fields
char username[MQTT_CONF_USERNAME_LENGTH];
char password[MQTT_CONF_PASSWORD_LENGTH];
// Will topic
uint8_t will_retain;
uint8_t will_qos;
uint8_t clean_session;
// Management fields
uint16_t seq;
uint16_t alive;
} mqtt_broker_handle_t;
int mqtt_connect(mqtt_broker_handle_t* broker)
{
uint8_t flags = 0x00;
uint16_t clientidlen = strlen(broker->clientid);
uint16_t usernamelen = strlen(broker->username);
uint16_t passwordlen = strlen(broker->password);
uint16_t payload_len = clientidlen + 2;
// Preparing the flags
if(usernamelen) {
payload_len += usernamelen + 2;
flags |= MQTT_USERNAME_FLAG;
}
if(passwordlen) {
payload_len += passwordlen + 2;
flags |= MQTT_PASSWORD_FLAG;
}
if(broker->clean_session) {
flags |= MQTT_CLEAN_SESSION;
}
// Variable header
uint8_t var_header[] = {
0x00,0x06,0x4d,0x51,0x49,0x73,0x64,0x70, // Protocol name: MQTT
0x03, // Protocol version
flags, // Connect flags
broker->alive>>8, broker->alive&0xFF, // Keep alive
};
// Fixed header
uint8_t fixedHeaderSize = 2; // Default size = one byte Message Type + one byte Remaining Length
uint8_t remainLen = sizeof(var_header)+payload_len;
if (remainLen > 127) {
fixedHeaderSize++; // add an additional byte for Remaining Length
}
uint8_t fixed_header[2];
// Message Type
fixed_header[0] = MQTT_MSG_CONNECT;
// Remaining Length
if (remainLen <= 127) {
fixed_header[1] = remainLen;
} else {
// first byte is remainder (mod) of 128, then set the MSB to indicate more bytes
fixed_header[1] = remainLen % 128;
fixed_header[1] = fixed_header[1] | 0x80;
// second byte is number of 128s
fixed_header[2] = remainLen / 128;
}
uint16_t offset = 0;
uint8_t packet[sizeof(fixed_header)+sizeof(var_header)+ sizeof(payload_len)];
memset(packet, 0, sizeof(packet));
memcpy(packet, fixed_header, sizeof(fixed_header));
offset += sizeof(fixed_header);
memcpy(packet+offset, var_header, sizeof(var_header));
offset += sizeof(var_header);
// Client ID - UTF encoded
packet[offset++] = clientidlen>>8;
packet[offset++] = clientidlen&0xFF;
memcpy(packet+offset, broker->clientid, clientidlen);
offset += clientidlen;
if(usernamelen) {
// Username - UTF encoded
packet[offset++] = usernamelen>>8;
packet[offset++] = usernamelen&0xFF;
memcpy(packet+offset, broker->username, usernamelen);
offset += usernamelen;
}
if(passwordlen) {
// Password - UTF encoded
packet[offset++] = passwordlen>>8;
packet[offset++] = passwordlen&0xFF;
memcpy(packet+offset, broker->password, passwordlen);
offset += passwordlen;
}
return 1;
}
When I debug the code there are no errors however when I run the code I get error stating that "the stack around the variable 'packet' is corrupt". I am very new to socket programming and mqtt in general so any help would be great.
What you've shown is derived from libemqtt (which is GPL licensed by the way, don't forget that :), have you tried starting from the examples that they provide?
libemqtt isn't actively developed and has a notice saying "DO NOT USE". Unless you're particularly interested in solving the problem of using MQTT for yourself, I'd suggest you look at something different, like the Paho or mosquitto client libraries.
Related
I've a FastCGI application with C++. I like to send my response with gzip compression to client.
(ZLIB VERSION "1.2.11")
Here is the sample of my source code:
#pragma warning (disable : 4231)
#pragma warning(disable : 4996)
//3:45 PM 11/24/2018
#if !(defined(_WIN32)||defined(_WIN64)) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
#error Have to check !TODO
#else
#if !defined(_IOSTREAM_)
#include <iostream>
#endif//!_IOSTREAM_
#ifndef _WINDOWS_
#include <windows.h>
#endif//!_WINDOWS_
#endif//_WIN32||_WIN64/__unix__
#if !defined(_INC_STDIO)
#include <stdio.h> /* defines FILENAME_MAX, printf, sprintf */
#endif//!_INC_STDIO
#ifndef _XSTRING_
#include <string>// !_XSTRING_// memcpy, memset
#endif //!_XSTRING_
#if !defined(ZLIB_H)
#include <zlib.h>
#endif//!ZLIB_H
#if !defined(_SSTREAM_)
#include <sstream> // std::stringstream
#endif//_SSTREAM_
#if !defined(CHUNK)
#define CHUNK 16384
#endif//!CHUNK
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
#endif//!OS_CODE
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif//!MAX_MEM_LEVEL
#if !defined(assert)
#define assert(expression) ((void)0)
#endif//!assert
static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
void __write_magic_header(std::stringstream&output) {
char*dest = (char*)malloc(10);
sprintf(dest, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], Z_DEFLATED, 0 /*flags*/, 0, 0, 0, 0 /*time*/, 0 /*xflags*/, OS_CODE);
output.write(const_cast<const char*>(dest), 10);
free(dest);
};
int ____def_strm(std::stringstream&source, std::stringstream&dest, int level = Z_BEST_SPEED) {
//6:00 AM 1/18/2019
int ret, flush;
unsigned have;
z_stream strm;
/* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit2_(&strm, level, Z_DEFLATED,
-MAX_WBITS,
DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
ZLIB_VERSION, (int)sizeof(z_stream));
if (ret != Z_OK)
return ret;
/* compress until end of stream */
std::streamsize n;
source.seekg(0, std::ios::end);//Go to end of stream
std::streamoff size = source.tellg();
source.seekg(0, std::ios::beg);//Back to begain of stream
int write_len = 0;
do {
char in[CHUNK];
n = source.rdbuf()->sgetn(in, CHUNK);
strm.avail_in = (uInt)n;
size -= n;
flush = size <= 0 ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = (Bytef*)in;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do {
char out[CHUNK];
strm.avail_out = CHUNK;
strm.next_out = (Bytef*)out;
ret = deflate(&strm, flush); /* no bad return value */
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
have = CHUNK - strm.avail_out;
dest.write(out, have);
write_len += have;
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /* all input will be used */
/* done when last data in file processed */
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END); /* stream will be complete */
/* clean up and return */
(void)deflateEnd(&strm);
return write_len;
};
void compress_gzip (std::stringstream&source, std::stringstream&output) {
__write_magic_header(output);
____def_strm(source, output);
return;
};
void gzip_test(int loop) {
std::stringstream body(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
for (int i = 0; i < loop; i++) {
body << "<b>Hello World</b><br/>";
body << "general-purpose programming language";
body << "\r\n";
}
std::stringstream compressed(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
compress_gzip(body, compressed);
std::stringstream().swap(body);
std::cout << compressed.str();
std::stringstream().swap(compressed);
};
void write_header(const char* ct) {
std::cout << "Content-Type:" << ct << "\n";
std::cout << "Accept-Ranges:bytes\n";
};
int main(int argc, char *argv[], char*envp[]) {
//100 problem ==> ERR_CONTENT_DECODING_FAILED
//1000 problem ==> ERR_CONTENT_DECODING_FAILED
//10000 Ok
write_header("text/plain");
std::cout << "Content-Encoding:gzip\n";
std::cout << "\r\n";
gzip_test(10000);
return EXIT_SUCCESS;
};
Its working but I think this program has bug, but i'm unable to figure it out.
Problems are shown bellow:
if gzip_test(10000); then OK
if gzip_test(100); browser shown ERR_CONTENT_DECODING_FAILED
if gzip_test(1000); browser shown ERR_CONTENT_DECODING_FAILED
Please help me to figure it out this bug.
Success response:
Error response:
You aren't writing the gzip footer containing the CRC and data length:
std::streamoff size = source.tellg();
int totalSize = size;
int tcrc = 0;
...
n = source.rdbuf()->sgetn( in, CHUNK );
strm.avail_in = (uInt)n;
tcrc = crc32( tcrc, (uint8_t*)in, n );
...
(void)deflateEnd( &strm );
dest.write( (char*)&tcrc, sizeof( tcrc ) );
dest.write( (char*)&totalSize, sizeof( totalSize ) );
return write_len;
Your __write_magic_header method is also incorrect as it only allocates 10 bytes but then writes 10 characters with sprintf which will actually write 11 bytes overflowing your buffer.
On windows you can't send binary data through std::cout, you have the same issue as opening a file with ofstream without specifying binary. To fix this call the following before using std::cout:
_setmode( _fileno( stdout ), _O_BINARY );
Some other points unrelated to your issue:
don't wrap your includes with #ifdef, the macros you are using are implementation details and should provide no/negligable performance difference on a modern compiler.
don't use "__" at the beginning of method names or other identifiers, these names (along with "_" followed by a capital letter) are reserved for use by the compiler.
I am actually programming a simple server and it's client in c++ using the tcp protocol. As this is to be integrated in a multiplayer game, every client has to send data extremely fast.
Issue: The server's buffer sometimes gets multiple messages in it.
I tried various things like putting off nagle's algorithm but I didn't manage to fix this problem. Here's the server's code :
#ifdef __linux__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <arpa/inet.h>
#define SOCKET int
#define SOCKADDR_IN struct sockaddr_in
#endif
#ifdef _WIN32
#include <winsock2.h>
#endif
#include <cstdio>
#include <iostream>
#include <thread>
#include <vector>
#include <string>
#include "server.h"
#include "../../Logger/logger.h"
#include "../../AltisCraft.fr/Map/map.h"
#include "../../StringPlus/string_plus.h"
#include "../../AltisCraft.fr/Map/User/User.h"
void connectEvent(), receive(), sendAllUsers(string), closeConnectio(),manageMsg();
vector<SOCKET> clients;
vector<thread> clientsThreads;
vector<string> msg;
SOCKET socketId, newSocketId;
SOCKADDR_IN source;
thread connection;
char buffer[65535] = {0};
int position;
// TODO: crypt every data sendLog/receive
// TODO: whitelist ip serv
// TODO: Auth system
// TODO: timer with packet ? (double receive...)
int sendLog(SOCKET s, const char* c, int i0, int i1)
{
log("Send:");
log(c);
send(s, c, i0, i1);
}
void initializeNetwork()
{
#ifdef _WIN32
WSADATA initWin32;
WSAStartup(MAKEWORD(2, 2),&initWin32);
#endif
socketId = socket(AF_INET, SOCK_STREAM, 0);
source.sin_family = AF_INET;
source.sin_addr.s_addr = INADDR_ANY;
source.sin_port = htons(33333);
bind(socketId, (struct sockaddr*)&source, sizeof(source));
connection = thread(&connectEvent);
connection.join();
closeConnection();
}
void connectEvent()
{
int error;
while(1)
{
error = 99;
while(error != 0)
{
error = listen(socketId, 1);
}
#ifdef _WIN32
int tempo = sizeof(source);
newSocketId = accept(socketId, (struct sockaddr*)&source, &tempo);
clients.push_back(newSocketId);
#endif
#ifdef __linux__
socklen_t tempo;
newSocketId = accept(socketId, (struct sockaddr *)&source, &tempo);
clients.push_back(newSocketId);
#endif
clientsThreads.push_back(thread(&receive));
}
}
void receive()
{
int val = 1;
position = clients.size() - 1;
bool connected = 1;
while(connected)
{
buffer[65535] = {0};
if(recv(clients[position], buffer, 1515, 0) > 0)
{
string msg = buffer;
bool isEmpty = false;
log(string(inet_ntoa(source.sin_addr)) + ": " + msg);
if(startsWith(msg, "Connect "))
addUser(replace(msg, "Connect ", ""));
else if(msg == "MAJ Map")
{
log(elements);
string toSend = "MAJ Map\n" + elements;
sendLog(clients[position], toSend.c_str(), strlen(toSend.c_str()), 0);
}
else if(startsWith(msg, "MAJ User ")) /// optimize: don't sendLog pos to player who sendLog
{
msg = replace(msg, "MAJ User ", "");
if(startsWith(msg, "Pos "))
{
msg = replace(msg, "Pos ", "");
vector<string> elements = split(msg, " ");
User user = *getUserByName(elements[0] + " " + elements[1]);
user.updateView(user.getView().updatePosition(Position(convertStrToDouble(elements[2]), convertStrToDouble(elements[3]), convertStrToDouble(elements[4]))));
}
else if(startsWith(msg, "ViewAngle "))
{
msg = replace(msg, "ViewAngle ", "");
vector<string> elements = split(msg, " ");
User user = *getUserByName(elements[0] + " " + elements[1]);
user.updateView(user.getView().updateViewAngle(ViewAngle(convertStrToDouble(elements[2]), convertStrToDouble(elements[3]))));
}
}
else
sendAllUsers(string(string(inet_ntoa(source.sin_addr)) + ": " + msg).c_str());
}
else
connected = 0;
}
shutdown(clients[position], 2);
for(int i=0;i<msg.size();i++)
cout << msg[i] << endl;
#ifdef _WIN32
closesocket(clients[position]);
#endif
#ifdef __linux__
close(clients[position]);
#endif
clients.erase(clients.begin() + position);
}
void sendAllUsersWithoutOne(string msg, string name)
{
for(int j = 0; j < (int)clients.size(); j++)
{
// only linux here (MSG_DONTWAIT)
#ifdef __linux__
if(recv(clients[j], NULL, 1, MSG_PEEK | MSG_DONTWAIT) == 0)
{
clients.erase(clients.begin() + j);
continue;
}
#endif
sendLog(clients[j], msg.c_str(), strlen(msg.c_str()), 0);
}
}
void sendAllUsers(string msg)
{
for(int j = 0; j < (int)clients.size(); j++)
{
// only linux here (MSG_DONTWAIT)
#ifdef __linux__
if(recv(clients[j], NULL, 1, MSG_PEEK | MSG_DONTWAIT) == 0)
{
clients.erase(clients.begin() + j);
continue;
}
#endif
sendLog(clients[j], msg.c_str(), strlen(msg.c_str()), 0);
}
}
void closeConnection()
{
for(int i = 0; i < (int)clients.size(); i++)
{
shutdown(clients[i], 2);
#ifdef _WIN32
closesocket(clients[i]);
#endif
#ifdef __linux__
close(clients[i]);
#endif
}
#ifdef _WIN32
closesocket(socketId);
WSACleanup();
#endif
#ifdef __linux__
close(socketId);
#endif
}
void freeNetwork()
{
closeConnection();
}`
to expand on Barmar's comment
TCP is a streaming protocol, not a message protocol. THe only guarantee is that you send n bytes, you will receive n bytes in the same order.
You might send 1 chunk of 100 bytes and receive 100 1 byte recvs, or you might receive 20 5 bytes recvs
You could send 100 1 byte chunks and receive 4 25 byte messages
You must deal with message boundaries yourself. Either have a sentinel value to mark start and end or prepend a length that is a fixed size itself (so you know you have read the whole length). Then loop on recv till you have received the whole message
I've been running a script on my Raspi while incrementally improving its performance, it was working fine until I started editing it this morning, and now cout << will not print to the console but interestingly enough - radio.printDetails does print, which uses printf. I think maybe the SD card is starting to die? Could this cause the issue?
Header:
#include <bcm2835.h>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <RF24/RF24.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>
#include <time.h>
#define arrSize 50
//
// Hardware configuration
// Configure the appropriate pins for your connections
/****************** Raspberry Pi ***********************/
RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0);//, BCM2835_SPI_SPEED_4MHZ);
//RF24 radio(22,0); // CE GPIO, CSN SPI-BUS
int interruptPin = 23; // GPIO pin for interrupts
int i=0;
/**************************************************************/
// Radio pipe addresses for the 2 nodes to communicate.
//const uint8_t pipes[][6] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
const uint8_t pipes[][6] = {"1Node","2Node"};
volatile int accelArryNo = 0;
volatile int currentArryNo = 0;
uint8_t ack = 30;
int liveAccelArray[arrSize*3];
float liveCurrentArray[arrSize];
const int max_receivePayload_size = 32;
volatile int recvd = 0;
uint8_t receivePayload[max_receivePayload_size]; // +1 to allow room for a terminating NULL char
uint8_t receivePayloadBuff[max_receivePayload_size];
bool role_ping_out = 1, role_pong_back = 0;
bool role = 0;
//mysql pointers
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
main():
int main(){
char *server = "localhost";
char *user = "monitor";
char *password = "monitor"; /* set me first */
char *database = "data";
conn = mysql_init(NULL);
/* Connect to database */
if (!mysql_real_connect(conn, server,
user, password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
/* send SQL query */
if (mysql_query(conn, "show tables")) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
res = mysql_use_result(conn);
/* output table name */
// printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(res)) != NULL)
//printf("%s \n", row[0]);
mysql_free_result(res);
// Setup and configure rf radio
radio.begin();
radio.setAutoAck(1);
radio.enableDynamicPayloads();
radio.enableAckPayload();
radio.setRetries(0,15);
radio.setDataRate(RF24_1MBPS);
radio.printDetails();
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.writeAckPayload(1, &ack, sizeof(ack));
if(radio.available()){
std::cout << "available";
uint8_t len;
len = radio.getDynamicPayloadSize();
radio.read(&receivePayload, len);
}
std::cout << "listening";
attachInterrupt(interruptPin, INT_EDGE_FALLING, intHandler); //Attach interrupt to bcm pin 23
radio.startListening();
// forever loop
while(1){
if (recvd == 2){
//addLiveData();
recvd = 0;
} else if (recvd == 1) {
insertData();
recvd = 0;
}
}
}
Thanks
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;
}
I have the following code:
#ifndef RAWSOCKET_H
#define RAWSOCKET_H
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include "IPPacket.h"
#define CONF_RING_FRAMES 128
/// Initialize a packet socket ring buffer
// #param ringtype is one of PACKET_RX_RING or PACKET_TX_RING
static inline char *
init_packetsock_ring(int fd, int ringtype)
{
tpacket_req tp;
char *ring;
// tell kernel to export data through mmap()ped ring
tp.tp_block_size = 1024 * 8;
tp.tp_block_nr = 1024;
tp.tp_frame_size = 1024 * 8;
tp.tp_frame_nr = 1024;
setsockopt(fd, SOL_PACKET, ringtype, (void*) &tp, sizeof(tp));
int val = TPACKET_V1;
setsockopt(fd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));
// open ring
ring = (char*)mmap(0, tp.tp_block_size * tp.tp_block_nr,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (!ring)
return NULL;
return ring;
}
/// transmit a packet using packet ring
// NOTE: for high rate processing try to batch system calls,
// by writing multiple packets to the ring before calling send()
//
// #param pkt is a packet from the network layer up (e.g., IP)
// #return 0 on success, -1 on failure
static inline int
process_tx(int fd, char *ring, const char *pkt, int pktlen, sockaddr_ll *txring_daddr)
{
static int ring_offset = 0;
struct tpacket_hdr *header;
struct pollfd pollset;
char *off;
int ret;
// fetch a frame
// like in the PACKET_RX_RING case, we define frames to be a page long,
// including their header. This explains the use of getpagesize().
header = (tpacket_hdr*)(void *) ring + (ring_offset * 1024);
while (header->tp_status != TP_STATUS_AVAILABLE) {
// if none available: wait on more data
pollset.fd = fd;
pollset.events = POLLOUT;
pollset.revents = 0;
ret = poll(&pollset, 1, 1000 /* don't hang */);
if (ret < 0) {
if (errno != EINTR) {
perror("poll");
return -1;
}
return 0;
}
ring_offset++;
if(ring_offset >= 1024 * 8) ring_offset = 0;
header = (tpacket_hdr*)(void *) ring + (ring_offset * 1024);
}
// fill data
off = (char*)(((char*) header) + (TPACKET_HDRLEN - sizeof(struct sockaddr_ll)));
memcpy(off, pkt, pktlen);
// fill header
header->tp_len = pktlen;
header->tp_status = TP_STATUS_SEND_REQUEST;
// increase consumer ring pointer
/*ring_offset++;
if(ring_offset >= 1024 * 8) ring_offset = 0;*/
// notify kernel
if (sendto(fd, NULL, 0, 0, (sockaddr*)txring_daddr, sizeof(sockaddr_ll)) < 0) {
perror("sendto");
return -1;
}
return 0;
}
class RawSocket
{
public:
inline RawSocket() { }
inline void initialize() {
sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
ring = init_packetsock_ring(sockfd, PACKET_TX_RING);
ifreq ifr;
memset (&ifr, 0, sizeof (ifr));
strncpy((char *) ifr.ifr_name, "eth0", IFNAMSIZ);
ioctl(sockfd, SIOCGIFINDEX, &ifr);
int index = ifr.ifr_ifindex;
ioctl(sockfd, SIOCGIFHWADDR, &ifr);
sll = new sockaddr_ll();
sll->sll_family = AF_PACKET;
sll->sll_ifindex = index;
sll->sll_protocol = htons(ETH_P_IP);
sll->sll_halen = htons(6);
memcpy(IPPacket::our_mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
memcpy(sll->sll_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
/*struct packet_mreq mr;
memset (&mr, 0, sizeof (mr));
mr.mr_ifindex = ifr.ifr_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
setsockopt(sockfd, SOL_PACKET,PACKET_ADD_MEMBERSHIP, &mr, sizeof (mr));*/
//setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
}
inline ~RawSocket() {
close(sockfd);
}
inline void send(const IPPacket* ip) const {
process_tx(sockfd, ring, ip->packet_ptr, ip->tot_len, sll);
printf("TX\n");
}
protected:
char *ring;
int sockfd;
sockaddr_ll *sll;
};
#endif // RAWSOCKET_H
ip->packet_ptr being a pointer to a packet containing ethhdr and iphdr and so on.
The packets are being correcly sent via "normal" PF_PACKET sockets.
Now I tried using the TX Ring feature. However, only the first packet ever gets sent (and it gets sent 100% correctly).
Nothing else seems to happen on the network layer (tcpdump -vvv -e shows no network traffic at all occuring!)
However, the sendto() calls get processed correctly.
I didnt test this functionality myself, but I think you have an error in configuring the struct tpacket_req fields. the _nr fields are quite large. See this example code (linked to from the wiki ):
/* Setup the fd for mmap() ring buffer */
req.tp_block_size=4096;
req.tp_frame_size=1024;
req.tp_block_nr=64;
req.tp_frame_nr=4*64;
if ( (setsockopt(fd,
SOL_PACKET,
PACKET_RX_RING,
(char *)&req,
sizeof(req))) != 0 ) {
perror("setsockopt()");
close(fd);
return 1;
};
/* mmap() the sucker */
map=mmap(NULL,
req.tp_block_size * req.tp_block_nr,
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0);
(I know this is a bit late but the documentation for this is still poor and examples are few, so hopefully this will help someone):
As per my comments above, this is the working code for me now (with no error checking, just a crude proof of concept):
struct tpacket2_hdr *hdr;
for (uint16_t i = 0; i < tpacket_req.tp_frame_nr; i += 1) {
hdr = (void*)(mmapped_buffer + (tpacket_req.tp_frame_size * i));
uint8_t *data = (uint8_t*)(hdr + TPACKET_ALIGN(TPACKET2_HDRLEN));
memcpy(data, tx_buffer, frame_size);
hdr->tp_len = frame_size;
hdr->tp_status = TP_STATUS_SEND_REQUEST;
}
int32_t send_ret = sendto(sock_fd, NULL, 0, 0, NULL, 0);