I am trying to implement a UDP communication protocol between a C program and a python program. The C program has a structure that it sends through the UDP port (tx_port) as binary data. This program also listens on another port (rx_port) for any received data, and then prints the received binary output to the screen.
The python program listens on tx_port and unpacks the received data and prints it to the screen. Then it repacks the data and sends it back through UDP port (rx_port).
Here are the C and Python programs that I used.
C program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
#define BUFLEN 4096
#define RX_PORT 8888
#define TX_PORT 8889
// Structure data
struct data {
long frame_number;
double time;
} tx_data, rx_data;
int dlen = sizeof(tx_data);
struct sockaddr_in si_me, si_other;
int tx_soc;
int slen = sizeof(si_other);
int recv_len;
char* buf;
pthread_t rx_thread;
void* receiver_thread(void *arg)
{
int i =0;
while (1) {
recv_len = recvfrom(tx_soc, buf, sizeof(rx_data), 0, (struct sockaddr *) &si_other, &slen);
printf("\nReceived data : %d\n", recv_len);
for (i = 0; i < recv_len; i++) {
printf("%x ", buf[i]);
}
printf("\n");
fflush(stdout);
};
}
void data_init(void) {
tx_data.frame_number = 0;
tx_data.time = 0;
};
int main(void)
{
// Initialize data
data_init();
//create a UDP socket
if ((tx_soc=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Socket error!");
exit(0);
}
// zero out the structure
memset((char *) &si_me, 0, sizeof(si_other));
memset((char *) &si_other, 0, sizeof(si_other));
// Host socket address
si_me.sin_family = AF_INET;
si_me.sin_port = htons(RX_PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
// Remote socket address
si_other.sin_family = AF_INET;
si_other.sin_port = htons(TX_PORT);
si_other.sin_addr.s_addr = htonl(INADDR_ANY);
//bind sockets to the ports
if( bind(tx_soc, (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
{
printf("Binding error!");
}
// Start reader thread.
if (pthread_create(&rx_thread, NULL, &receiver_thread, NULL) != 0) {
printf("\ncan't create thread");
}
//keep listening for data
while(1)
{
// Allocate memory for receive buffer.
buf = (char*) malloc(sizeof(rx_data));
// Update data value.
tx_data.frame_number++;
printf("\nFrame numner: %ld", tx_data.frame_number);
fflush(stdout);
// Send data.
if (sendto(tx_soc, (char*)&tx_data, dlen, 0, (struct sockaddr*) &si_other, slen) == -1)
{
printf("Sending error!");
}
sleep(1);
}
close(tx_soc);
return 0;
}
Python program
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import struct
# Packet format string
packet_fmt = ''.join(['i', # Frame number
'd', # Frame time stamp
])
s = struct.Struct(packet_fmt)
class Echo(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
new_data = s.unpack(data)
print new_data
echo_data = s.pack(*new_data)
self.transport.write(echo_data, (host, port))
reactor.listenUDP(8889, Echo())
reactor.run()
When I execute the two programs, I am able to receive data on both sides. I am able to unpack data in python, print it, repack and send it.
But on the C side, the received data does not match the sent data. I have checked on the python side to make sure the repacked data matches the original data.
Here is a sample output from the C and Python programs. I started the python programs first, and then the C program.
What is the mistake I might be making?
Related
I have this structure
struct Data
{
int id;
int msglen;
char msg[100];
}
and I need to pass this struct between udp server and udp client.udp client is python based.
First, you need to encode the struct data into a single binary buffer
#include <endian.h>
...
struct Data d { ... };
uint32_t be_id = htobe32(d.id);
uint32_t be_len = htobe32(d.msglen);
size_t pos = 0;
uint8_t buf[sizeof(struct Data)];
memcpy(buf, (const void *)&be_id, sizeof(be_id));
pos += sizeof(be_id);
memcpy(buf + pos, (const void *)&be_len, sizeof(be_len));
pos += sizeof(be_len);
memcpy(buf + pos, (const void *)d.msg, sizeof(d.msg));
Then send the buffer, and parse it from the other side.
I am trying to make a messenger program (that currently has a ton of bugs so please dismiss them) and for some reason, the server wont let the clients connect. I have tried changing the port, but nothing works. I get the following error (for my client, which is in python) (this is on a mac, but I have tried the client on a windows computer, still nothing):
Traceback (most recent call last):
File "msgclient.py", line 31, in <module>
Program()
File "msgclient.py", line 8, in __init__
self.s.connect((IP, PORT))
ConnectionRefusedError: [Errno 61] Connection refused
Here is the code for the server (written in c):
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#define MAXCLIENTS 256
#define MAXMSG 269
#define PORT 9989
void forward(int clientslist[MAXCLIENTS], char* msg) {
int x;
for (x=0; x < MAXCLIENTS; x++){
send(clientslist[x], msg, sizeof(msg), 0);
}
return;
}
int main(){
int s = socket(AF_INET, SOCK_STREAM, 0);
int clients[MAXCLIENTS];
int clientcounter = 0;
fd_set socketlist, readlist;
FD_ZERO(&socketlist);
FD_SET(s, &socketlist);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;
bind(s, (struct sockaddr*) &server, sizeof(server));
listen(s, MAXCLIENTS);
int clientsocket;
int i;
int rc;
int max = s;
void* msg = (char *) malloc(MAXMSG+1);
void* usr = (char *) malloc(14);
while (1){
readlist = socketlist;
select(FD_SETSIZE, &readlist, NULL, NULL, NULL);
for (i=0; i<max+1; i++){
if(FD_ISSET(i, &readlist)){
if (i == s){
clientsocket = accept(s, NULL, NULL);
FD_SET(clientsocket, &socketlist);
clients[clientcounter] = clientsocket;
clientcounter++;
rc = recv(clientsocket, usr, 10, 0);
printf("Connection received from %s\n", usr);
usr = "\0";
if (clientsocket > max+1){
max = clientsocket;
}
} else {
rc = recv(i, msg, MAXMSG, 0);
if (rc > 0){
forward(clients, msg);
} else{
close(i);
msg = "\0";
}
}
}
}
}
return 0;
}
and the client (written in python):
import socket
class Program:
def __init__(self):
IP = socket.gethostbyname(socket.gethostname())
PORT = 9989
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.connect((IP, PORT))
self.user = self.username()
self.s.send(bytes(self.user, "utf-8"))
while True:
received = self.s.recv(269)
received = received.decode("utf-8")
print(received)
self.enter()
def username(self):
name = str(input("Enter a username (10 character max): "))
if len(name) > 10:
print("Username is larger than 10; try again")
self.username()
return name;
def enter(self):
msg = str(input("Enter a message>> "))
if msg != "":
self.s.send(bytes(f"{self.user}>> {msg}", "utf-8"))
if __name__ == "__main__":
Program()
regarding the function:
void forward(int clientslist[MAXCLIENTS], char* msg)
and
send(clientslist[x], msg, sizeof(msg), 0);
The expression: sizeof(msg) will return a value (depending on your underlying hardware and certain compiler parameters) of 4 or 8, Not what you want. Suggest passing the actual number of bytes to transmit.
regarding the function:
void forward(int clientslist[MAXCLIENTS], char* msg)
and the statement:
return;
The return; statement is completely unnecessary. Suggest removing that statement.
regarding:
int s = socket(AF_INET, SOCK_STREAM, 0);
This statement can fail. Always check (if socket < 0) then handle the error
regarding:
server.sin_addr.s_addr = INADDR_ANY;
INADDR_ANY has the value: "0.0.0.0" which cannot be directly assigned. Suggest:
server.sin_addr.s_addr = htonl(INADDR_ANY);
OT: regarding:
bind(s, (struct sockaddr*) &server, sizeof(server));
and
listen(s, MAXCLIENTS);
These functions can fail. Always check the returned value to assure the operation was successful.
OT: regarding:
void* msg = (char *) malloc(MAXMSG+1);
and similar statements. In C, the returned type is void* which can be assigned to any pointer. Casting just clutters the code and is error prone. even this statement has an error in the cast. Suggest removing that cast.
regarding:
readlist = socketlist;
select(FD_SETSIZE, &readlist, NULL, NULL, NULL);
for (i=0; i<max+1; i++)
{
if(FD_ISSET(i, &readlist))
{
if (i == s)
{
This code sequence forces serial handling of the incoming sockets. Much better to generate a 'thread pool', then use accept() and pass the resulting client socket to an idle thread. The thread then performs all the communication with the client, then, when finishing with the client, closes the client socket.
regarding:
select(FD_SETSIZE, &readlist, NULL, NULL, NULL);
There must already be an open socket to the client, which there is none, so no communication occurs.
there may be other problems, but this should aim you in the right direction.
I have a multicast packet from a capture using tcpdump. I can replay the packet using tcpreplay -i eth0 on.pcap and I can receive it on another machine using tcpdump.
I have tried c code and python code to try and capture this packet without success. I've tried both on MacOS and Raspian (Rpi 3b).
https://mega.nz/#!ELAgBSDL!XZ3EXCkDBsLLwFn8J1ofWuMm4Z7sssOZPuZVEpmRqvs
here is a c code example:
/*
multicast.c
The following program sends or receives multicast packets. If invoked
with one argument, it sends a packet containing the current time to an
arbitrarily chosen multicast group and UDP port. If invoked with no
arguments, it receives and prints these packets. Start it as a sender on
just one host and as a receiver on all the other hosts
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdio.h>
#define EXAMPLE_PORT 2068
#define EXAMPLE_GROUP "226.2.2.2"
main(int argc)
{
struct sockaddr_in addr;
int addrlen, sock, cnt;
struct ip_mreq mreq;
char message[50];
/* set up socket */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
perror("socket");
exit(1);
}
bzero((char *)&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(EXAMPLE_PORT);
addrlen = sizeof(addr);
if (argc > 1)
{
/* send */
addr.sin_addr.s_addr = inet_addr(EXAMPLE_GROUP);
while (1)
{
time_t t = time(0);
sprintf(message, "time is %-24.24s", ctime(&t));
printf("sending: %s\n", message);
cnt = sendto(sock, message, sizeof(message), 0,
(struct sockaddr *) &addr, addrlen);
if (cnt < 0)
{
perror("sendto");
exit(1);
}
sleep(5);
}
}
else
{
/* receive */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("bind");
exit(1);
}
mreq.imr_multiaddr.s_addr = inet_addr(EXAMPLE_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0)
{
perror("setsockopt mreq");
exit(1);
}
while (1)
{
cnt = recvfrom(sock, message, sizeof(message), 0,
(struct sockaddr *) &addr, &addrlen);
if (cnt < 0)
{
perror("recvfrom");
exit(1);
}
else if (cnt == 0)
{
break;
}
printf("%s: message = \"%s\"\n", inet_ntoa(addr.sin_addr), message);
}
}
}
Here is a python example:
#!/usr/bin/env python
import socket
import binascii
import sys
MCAST_GRP = '226.2.2.2'
MCAST_PORT = 2068
MCAST_IFACE = '192.168.168.200'
def joinMcast(mcast_addr,port,if_ip):
"""
Returns a live multicast socket
mcast_addr is a dotted string format of the multicast group
port is an integer of the UDP port you want to receive
if_ip is a dotted string format of the interface you will use
"""
#create a UDP socket
mcastsock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#allow other sockets to bind this port too
mcastsock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#explicitly join the multicast group on the interface specified
mcastsock.setsockopt(socket.SOL_IP,socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(mcast_addr)+socket.inet_aton(if_ip))
#finally bind the socket to start getting data into your socket
mcastsock.bind((mcast_addr,port))
return mcastsock
def main():
sock = joinMcast(MCAST_GRP, MCAST_PORT, MCAST_IFACE)
while True:
print >>sys.stderr, '\nwaiting to receive message'
print sock.recv(1024)
if __name__ == '__main__':
main()
I would like to sniff packets on a particular Ethernet interface using python.
These packets are received from an FPGA and do not contain any of the usual IP headers. The only header info is the Ethernet header.
I have the following python code which reads raw packets, It's from an example I modified from here.
from socket import *
interface = "em3"
# Create socket connection
sock = socket(AF_PACKET, SOCK_RAW, htons(0x0003))
sock.bind((interface, 0)) #port number
data = sock.recv(1024)
print(data)
sock.close()
I understand that when TCP/UDP sockets are created, port numbers are reserved for use by a specific service. However, I don't know what port number to use for my application. How do I know what port number to use?
Why I'm asking:
I'm asking because the above code doesn't receive any packets from the FPGA, even though when I use tshark (sudo tshark -i em3 -w output.bin) I get two. My interface is in promiscuous mode, and now I'm checking if my port number and protocol types are correct.
austinmarton on GitHub has some code to Receive raw Ethernet frames in Linux. This is not my code, so don't ak me any questions about it, and your mileage may vary. Thanks to #Barmar for the link.
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#define DEST_MAC0 0x00
#define DEST_MAC1 0x00
#define DEST_MAC2 0x00
#define DEST_MAC3 0x00
#define DEST_MAC4 0x00
#define DEST_MAC5 0x00
#define ETHER_TYPE 0x0800
#define DEFAULT_IF "eth0"
#define BUF_SIZ 1024
int main(int argc, char *argv[])
{
char sender[INET6_ADDRSTRLEN];
int sockfd, ret, i;
int sockopt;
ssize_t numbytes;
struct ifreq ifopts; /* set promiscuous mode */
struct ifreq if_ip; /* get ip addr */
struct sockaddr_storage their_addr;
uint8_t buf[BUF_SIZ];
char ifName[IFNAMSIZ];
/* Get interface name */
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Header structures */
struct ether_header *eh = (struct ether_header *) buf;
struct iphdr *iph = (struct iphdr *) (buf + sizeof(struct ether_header));
struct udphdr *udph = (struct udphdr *) (buf + sizeof(struct iphdr) + sizeof(struct ether_header));
memset(&if_ip, 0, sizeof(struct ifreq));
/* Open PF_PACKET socket, listening for EtherType ETHER_TYPE */
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
perror("listener: socket");
return -1;
}
/* Set interface to promiscuous mode - do we need to do this every time? */
strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
ioctl(sockfd, SIOCGIFFLAGS, &ifopts);
ifopts.ifr_flags |= IFF_PROMISC;
ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
/* Allow the socket to be reused - incase connection is closed prematurely */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(sockfd);
exit(EXIT_FAILURE);
}
/* Bind to device */
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(sockfd);
exit(EXIT_FAILURE);
}
repeat: printf("listener: Waiting to recvfrom...\n");
numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
printf("listener: got packet %lu bytes\n", numbytes);
/* Check the packet is for me */
if (eh->ether_dhost[0] == DEST_MAC0 &&
eh->ether_dhost[1] == DEST_MAC1 &&
eh->ether_dhost[2] == DEST_MAC2 &&
eh->ether_dhost[3] == DEST_MAC3 &&
eh->ether_dhost[4] == DEST_MAC4 &&
eh->ether_dhost[5] == DEST_MAC5) {
printf("Correct destination MAC address\n");
} else {
printf("Wrong destination MAC: %x:%x:%x:%x:%x:%x\n",
eh->ether_dhost[0],
eh->ether_dhost[1],
eh->ether_dhost[2],
eh->ether_dhost[3],
eh->ether_dhost[4],
eh->ether_dhost[5]);
ret = -1;
goto done;
}
/* Get source IP */
((struct sockaddr_in *)&their_addr)->sin_addr.s_addr = iph->saddr;
inet_ntop(AF_INET, &((struct sockaddr_in*)&their_addr)->sin_addr, sender, sizeof sender);
/* Look up my device IP addr if possible */
strncpy(if_ip.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFADDR, &if_ip) >= 0) { /* if we can't check then don't */
printf("Source IP: %s\n My IP: %s\n", sender,
inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr));
/* ignore if I sent it */
if (strcmp(sender, inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr)) == 0) {
printf("but I sent it :(\n");
ret = -1;
goto done;
}
}
/* UDP payload length */
ret = ntohs(udph->len) - sizeof(struct udphdr);
/* Print packet */
printf("\tData:");
for (i=0; i<numbytes; i++) printf("%02x:", buf[i]);
printf("\n");
done: goto repeat;
close(sockfd);
return ret;
}
socket probably not going to work here, since it will use TCP/IP
you can try to use the scapy package to sniff packet from that interface.
check this:
http://www.secdev.org/projects/scapy/doc/usage.html#sniffing
I try to send data over an arduino Ethernet shield to client (python on PC)
the problem that i had is when i read like example the pin A0 in arduino i get 1023 but when i send this value to python i get 49152...
arduino code
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Enter a MAC address for your controller below.
IPAddress ip(192,168,0,101);
IPAddress gateway(192,168,0,254);
IPAddress subnet(255,255,255,0);
unsigned int UDPport = 5000;// local port to listen for UDP packets
IPAddress UDPServer(192,168,0,100); // destination device server
const int UDP_PACKET_SIZE= 48;
byte packetBuffer[ UDP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
unsigned int noChange = 0;
int UDPCount = 0;
EthernetUDP Udp;
unsigned long currentTime;
unsigned long secondTime;
unsigned long msPerSecond = 100UL;
float temperature;
float vitesse;
float charge;
float current;
void setup()
{
Serial.begin(9600);
Ethernet.begin(mac,ip,gateway,gateway,subnet);
Udp.begin(UDPport);
delay(1500);
currentTime=millis();
secondTime = currentTime;
}
void loop()
{
currentTime = millis();
getUDPpacket();
if(currentTime - secondTime > msPerSecond) {
temperature = analogRead(0); //read analog input on pin A0
vitesse = analogRead(1); //read analog input on pin A1
charge = analogRead(2); //read analog input on pin A2
current = analogRead(3); //read analog input on pin A3
Serial.println(temperature);
sendUDPpacket(UDPServer); // send an NTP packet to a time server
secondTime += msPerSecond;
}
}
unsigned int udpCount = 0;
unsigned long sendUDPpacket(IPAddress& address)
{
udpCount++;
memset(packetBuffer, 0, UDP_PACKET_SIZE); sprintf((char*)packetBuffer,"%u,%u,%u,%u",temperature,vitesse,charge,current);
Udp.beginPacket(address, UDPport);
Udp.write(packetBuffer,UDP_PACKET_SIZE);
Udp.endPacket();
}
void getUDPpacket() {
if ( Udp.parsePacket() ) {
if(Udp.remoteIP() == UDPServer) {
Serial.print(F("UDP IP OK "));
}
else {
Serial.println(F("UDP IP Bad"));
return;
}
if(Udp.remotePort() == UDPport) {
Serial.println(F("Port OK"));
}
else {
Serial.println(F("Port Bad"));
return;
}
Udp.read(packetBuffer,UDP_PACKET_SIZE); // read the packet into the buffer
Serial.print(F("Received: "));
Serial.println((char*)packetBuffer);
}
}
the python code
import socket
import time
UDP_IP = "192.168.0.100"
UDP_PORT = 5000
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(48)
print data
time.sleep(5)
i think the problem is in this line
sprintf((char*)packetBuffer,"%u,%u,%u,%u",temperature,vitesse,charge,current);
but i dont know what to do
You should enable all warnings (eg in gcc use -Wall) when you compile your C code. That way, it would warn you when you try to print floats with the %u unsigned integer format specifier, as that leads to undefined behaviour.
You should either a) convert temperature, vitesse, charge, and currentto unsigned integer before passing them to sprintf(), or b) change the format specifier to something like %f so that sprintf() knows to expect floating-point data.
Also you should include <stdio.h> so that your program has a prototype for sprintf(); I assume that those headers you have included contain prototypes & constants relevant to the Ethernet & Arduino port IO functions.