Sending structure through sockets in Qt - linux

I am writing a client server application to transfer data in linux platform. I am developing a GUI application for client side in QT.I am just a beginner in QT and please help in transferring a structure from server side to client side.
The server side code written for non-GUI environment
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#pragma pack(1)
struct basestruct
{
int element1;
int element2;
};
#pragma pack(0)
struct basestruct newstruct;
int main(int argc, char *argv[])
{
int listenfd = 0, connfd = 0,n=0;
struct sockaddr_in serv_addr;
char sendBuff[1025];
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
newstruct.element1=1;
newstruct.element2=2;
if((n=send(connfd,(void *)&newstruct,sizeof(struct basestruct),0))<0)
perror("Write error");
printf("sent items :%d \n",n);
close(connfd);
sleep(1);
}}`
The client side code written in QT
#include "dialog.h"
#include "ui_dialog.h"
#include <QString>
#include <QDebug>
#include <QTextStream>
#include <QByteRef>
struct basestruct
{
int element1;
int element2;
};
basestruct newstruct;
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
ui->pushButton->setText("Connect");
ui->pushButton_2->setText("Ok");
ui->pushButton_3->setText("Close");
ui->pushButton_4->setText("Disconnect");
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::Read()
{
socket->waitForReadyRead(-1);
QByteArray byteArray;
byteArray=socket->readAll();
deserialize(byteArray);
qDebug()<<socket->readAll();
qDebug()<<"Read contents";
socket->flush();
}
void Dialog::on_pushButton_clicked()
{
socket=new QTcpSocket(this);
socket->connectToHost("127.0.0.1",5000);
qDebug()<<"Connected";
Read();
}
void Dialog::on_pushButton_4_clicked()
{
socket->close();
qDebug()<<"Disconnected";
}
void Dialog::deserialize(const QByteArray& byteArray)
{
QDataStream stream(byteArray);
stream.setVersion(QDataStream::Qt_4_0);
qDebug()<<"size received" <<byteArray.size();
stream >> newstruct.element1
>> newstruct.element2;
qDebug()<<"Element1"<<newstruct.element1<<"Element2"<<newstruct.element2;
}
When I receive the structure and print using qDebug() I am getting some garbage values. Kindly help me and point where I have gone wrong.Is there any easy alternative method to transfer structure in QT without serialising (similar to Non-GUI applications).
Thanks in advance

The Endianness problem can be overcome by specifying the Endianess as:
stream.setByteOrder(QDataStream::LittleEndian);
in the deserialise function after declaring Qdatastream.

Related

setsockopt IPT_SO_SET_REPLACE flag return error (linux)

I try to use setsockopt with the flag IPT_SO_SET_REPLACE but i keep getting the wired error from errno Protocol not available this is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <linux/sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <fcntl.h>
int main(void) {
int sock;
int ret;
void *data;
size_t size;
struct ipt_replace *repl;
sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
if (sock == -1) {
perror("socket");
return -1;
}
size = sizeof(struct ipt_replace);
data = malloc(size); Protocol not available
if (data == NULL) {
perror("malloc");
return -1;
}
memset(data, 0, size);
repl = (struct ipt_replace *) data;
repl->num_counters = 0x1;
repl->size = 0xffffffff;
repl->valid_hooks = 0x1;
repl->num_entries = 0x1;
ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, size);
printf("\ndone %d\n", ret);
perror("error: ");
return 0;
}
this is the output :
sock:3
data:
size:92
done -1
error: : Protocol not available
Looking briefly at the kernel code, this would seem to indicate that the IP tables module isn't available (i.e. the kernel wasn't built with it configured, or it can't be found or loaded).
It appears to me that for a socket of the kind you created, the code flow is:
enter raw_setsockopt: level != SOL_RAW so...
call ip_setsockopt: level == SOL_IP but option isn't any of the IP_xxx options so...
call nf_setsockopt: Search loaded netfilter modules for one that has registered IPT_SO_SET_REPLACE.
I think the last must have failed, so you get ENOPROTOOPT back (== Protocol not available)

Example code on using PACKET_QDISC_BYPASS option on ethernet raw socket on linux

According to http://man7.org/linux/man-pages/man7/packet.7.html, there is a new option
PACKET_QDISC_BYPASS since linux 3.14. This has the potential of sending and receiving packets a lot faster.
Saw a sample code: https://github.com/netoptimizer/network-testing/blob/master/src/raw_packet_send.c, but unfortunately it doesn't have the code on sending packets.
I added some code to send packets but it has a problem with sendto.
# ./raw_packet_send p6p1 64
Lame RAW/PF_PACKET socket TX test program
Enabled kernel qdisc bypass
error sendto : Invalid argument
Not sure why. Here is the code (original raw_packet_send.c with my silly code). Please let me know how could make it work or point me to some good simple sample code. Thanks.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
//#include <stdio.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <sys/socket.h>
//#include <sys/mman.h>
//#include <linux/filter.h>
//#include <ctype.h>
//#include <fcntl.h>
//#include <unistd.h>
//#include <bits/wordsize.h>
//#include <net/ethernet.h>
//#include <netinet/ip.h>
//#include <arpa/inet.h>
//#include <stdint.h>
//#include <string.h>
//#include <assert.h>
//#include <net/if.h>
//#include <inttypes.h>
//#include <poll.h>
//#include <unistd.h>
#ifndef PACKET_QDISC_BYPASS
#define PACKET_QDISC_BYPASS 20
#endif
#include "common_socket.h"
char pkt[2000] = {0x00, 1,2,3,4,0, 0,1,2,3,4,1, 8, 0};;
int len = 96;
char intfName[100] = "em1";
/* Avail in kernel >= 3.14
* in commit d346a3fae3 (packet: introduce PACKET_QDISC_BYPASS socket option)
*/
void set_sock_qdisc_bypass(int fd, int verbose)
{
int ret, val = 1;
ret = setsockopt(fd, SOL_PACKET, PACKET_QDISC_BYPASS, &val, sizeof(val));
if (ret < 0) {
printf("[DEBUG] %s(): err:%d errno:%d\n", __func__, ret, errno);
if (errno == ENOPROTOOPT) {
if (verbose)
printf("No kernel support for PACKET_QDISC_BYPASS"
" (kernel < 3.14?)\n");
} else {
perror("Cannot set PACKET_QDISC_BYPASS");
}
} else
if (verbose) printf("Enabled kernel qdisc bypass\n");
}
int pf_tx_socket(int ver)
{
int ret, val = 1;
/* Don't use proto htons(ETH_P_ALL) as we only want to transmit */
int sock = socket(PF_PACKET, SOCK_RAW, 0);
//int sock = socket(AF_INET,SOCK_PACKET,htons(3));
if (sock == -1) {
perror("Creation of RAW PF_SOCKET failed!\n");
exit(1);
}
ret = Setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver));
return sock;
}
void mybind(int sock, char *intf) {
struct ifreq ifr;
int rc;
memset((char*)&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), intf);
if ((rc = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) < 0)
{
perror("Server-setsockopt() error for SO_BINDTODEVICE");
printf("%s\n", strerror(errno));
close(sock);
exit(-1);
}
}
int flood (int sock) {
struct sockaddr intfAddrs;
char cmd[100];
int tmp;
memset((char*)&intfAddrs, 0, sizeof (struct sockaddr));
intfAddrs.sa_family = PF_PACKET;
strcpy((char*)(intfAddrs.sa_data), intfName);
sprintf(cmd, "ifconfig %s promisc", intfName); system(cmd);
while (1) {
while (1) {
tmp = sendto(sock, pkt, len, 0, &intfAddrs, sizeof(intfAddrs));
if (tmp != len) {perror("error sendto "); exit(0); }
}
}
}
int main(int argc, char **argv)
{
if (argc > 1) { strcpy(intfName, argv[1]); }
if (argc > 2) { len = atoi(argv[2]); }
printf("Lame RAW/PF_PACKET socket TX test program\n");
int sock = pf_tx_socket(0);
set_sock_qdisc_bypass(sock, 1);
mybind(sock, intfName);
flood(sock);
return 0;
}
I think you need to change from PF_PACKET to AF_PACKET (although it looks like PF_PACKET is an alias to AF_PACKET) but I don't have any success when using PF_PACKET.
This code works for me:
// Create a raw socket
sock_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd == -1) {
perror("Can't create AF_PACKET socket");
return EXIT_FAILURE;
}
// Check kernel version
static const int32_t sock_qdisc_bypass = 1;
int32_t sock_qdisc_ret = setsockopt(thd_opt->sock_fd, SOL_PACKET, PACKET_QDISC_BYPASS, &sock_qdisc_bypass, sizeof(sock_qdisc_bypass));
if (sock_qdisc_ret == -1) {
perror("Can't enable QDISC bypass on socket");
return EXIT_FAILURE;
}
This is from setup_socket_mmap() here

Send dns queryis over ssl

I need to dns over ssl. DNS queryis UDP packeted and I need to change it to SSL protocol?
It is working in linux.
How does ubuntu 12.04 resolves dns and how to change to SSL?
I have tried create ssl socket and send dns queryis.
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netdb.h>
#include <openssl/rsa.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
//#include "server.h"
#define FAIL -1
void initChild(int cli, SSL_CTX* ctx);
void error(const char *msg) {
perror(msg);
exit(1);
}
int main(int count, char *strings[]) {
SSL_CTX *ctx;
int server;
char *portnum;
SSL* ssl;
int cli;
struct hostent *hp;
int pid;
if (count != 2)
{
printf("Usage: %s <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX();
LoadCertificates(ctx, "ser-cert.pem", "ser-key.pem");
server = OpenListener(atoi(portnum));
while (1) {
struct sockaddr_in addr;
int len = sizeof(addr);
int cli = accept(server, (struct sockaddr*)&addr, &len);
if (!(pid = fork())) {
//Child process
//close(server);
initChild(cli, ctx);
exit(0);
}
else if (pid > 0) {
//Parent process
}
else {
printf("Fork failed!!");
//close(server);
}
}
close(server);
SSL_CTX_free(ctx);
return 0;
}
void initChild(int cli, SSL_CTX* ctx) {
SSL* ssl;
ssl = SSL_new(ctx);
SSL_set_fd(ssl, cli);
DnsData(ssl);
}
This works in terminal mode. Now I need to change terminal mode to GUI mode. GUI mode is web browser. This code uses ssl certificate generated by me. How to write simple ssl dns queried web browser in c?

linux socket accept can't been blocked

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
int main()
{
int server_sockfd,client_sockfd;
int server_len,client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
create a new socket
unlink("server_socket");
server_sockfd=socket(AF_INET,SOCK_STREAM,0);
name it
server_address.sin_family=AF_INET;
server_address.sin_addr.s_addr=htonl(INADDR_ANY);
server_address.sin_port=htons(9734);
server_len=sizeof(server_address);
bind(server_sockfd,(struct sockaddr *)&server_address,server_len);
set block
int flags=fcntl(server_sockfd,F_GETFL,0);
if(flags&O_NONBLOCK==1){
printf("NONBLOCK");
}else{
printf("BLOCK");
}
flags=flags&~O_NONBLOCK;
fcntl(server_sockfd,F_SETFL,flags);
if(flags&O_NONBLOCK==1){
printf("NONBLOCK");
}else{
printf("BLOCK");
}
listen
listen(server_sockfd,5);
while(1){
char ch;
printf("server waiting\n");
client_len=sizeof(client_address);
client_sockfd=
accept(server_sockfd,(struct sockaddr*)&client_sockfd,&client_len);
it is blocked at first time
read(client_sockfd,&ch,1);
ch++;
write(client_sockfd,&ch,1);
close(client_sockfd);
}
}
when the client connected first,I work,but the next won't work
A mismatch may occurs between client_address and client_sockfd.
The man page of accept() says:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
The addrlen argument is a value-result argument: the caller must initialize it to
contain the size (in bytes) of the structure pointed to by addr; on return it
will contain the actual size of the peer address.
Try:
client_sockfd=
accept( server_sockfd, (struct sockaddr*)&client_address, &client_len );

Linux sockets communicating with QTcpSockets in Qt 4

I am trying to communicate with TCP between a Qt program and a regular linux program. I have an existing linux client server program and I am trying to replace the server program with a Qt application. Here is the linux client code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
portno = 9876;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("ERROR opening socket");
return -1;
}
server = gethostbyname("localhost");
if (server == NULL)
{
printf("ERROR, no such host\n");
return -1;
}
memset((char *) &serv_addr,0,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);
connect(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr));
sprintf(buffer,"This is a test\n");
n = write(sockfd,buffer,256);
return 0;
}
Here is the qt code
#include <Qt>
#include <QApplication>
#include <QTcpServer>
#include <QMessageBox>
#include <QTcpSocket>
#include <QtNetwork>
#include "qtserver.h"
Server::Server()
{
tcp = new QTcpServer(this);
tcp->listen(QHostAddress::Any,9876);
QObject::connect(tcp,SIGNAL(newConnection()),this,SLOT(printline()));
}
void Server::printline()
{
QTcpSocket *client = tcp->nextPendingConnection();
QObject::connect(client,SIGNAL(disconnected()),
client,SLOT(deleteLater()));
QDataStream in(client);
in.setVersion(QDataStream::Qt_4_0);
QString data;
in >> data;
printf("String = %s\n",(char*)data.data());
}
int main(int argc,char** argv)
{
QApplication a(argc,argv);
Server* server = new Server();
return a.exec();
}
When i try to run both of them I just get "String = " instead of the string outputting. Any idea what I'm doing wrong?
QString::data() returns QChar*, you can't just cast it to char* and hope that it would always work. For debugging QString, use qPrintable instead.
Also, QTcpSocket is very easy to use. Still, instead of writing the code from scratch, why not start by checkout out the examples, e.g. Fortune Server example.

Resources