Helo, i am trying to pass it like this
typedef struct t_timeSliceRequest{
unsigned int processId;
unsigned int timeRequired;
int priority;
}timeSliceRequest;
struct t_timeSliceRequest request = { 1,2,1 };
sendFlag = send(socketID,(timeSliceRequest *) &request, sin_size ,0);
and on server side
recvFlag = recv(socketID,(timeSliceRequest *) &request,sin_size,0);
but its receiving garbage, even recv returning -1, please help
This is my full Conde
#include<sys/socket.h>
#include<sys/types.h>
#include<string.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<time.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
enum priority_e{ high, normal, low };
typedef struct t_timeSliceRequest{
unsigned int processId;
unsigned int timeRequired;
int priority;
}timeSliceRequest;
typedef struct t_TimeSliceResponse {
timeSliceRequest original_req;
// Unix time stamp of when process was started on server
unsigned int time_started;
// Waiting and running time till end of CPU bust
unsigned int ttl;
} TimeSliceResponse;
int main(int argc, char ** argv){
int socketID = 0, clientID = 0;
char sendBuffer[1024], recvBuffer[1024];
time_t time;
struct sockaddr_in servAddr, clientAddr;
struct t_timeSliceRequest request = {1,1,0};
memset(sendBuffer, '0', sizeof(sendBuffer));
memset(recvBuffer, '0', sizeof(recvBuffer));
fprintf(stdout,"\n\n --- Server starting up --- \n\n");
fflush(stdout);
socketID = socket(AF_INET, SOCK_STREAM, 0);
if(socketID == -1){
fprintf(stderr, " Can't create Socket");
fflush(stdout);
}
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(5000);
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
int bindID, sin_size, recvFlag;
bindID = bind(socketID, (struct sockaddr *)&servAddr, sizeof(servAddr)); // Casting sockaddr_in on sockaddr and binding it with socket id
if(bindID!=-1){
fprintf(stdout," Bind SucessFull");
fflush(stdout);
listen(socketID,5);
fprintf(stdout, " Server Waiting for connections\n");
fflush(stdout);
while(1){
sin_size = sizeof(struct sockaddr_in);
clientID = accept(socketID, (struct sockaddr *) &clientAddr, &sin_size);
fprintf(stdout,"\n I got a connection from (%s , %d)", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
fflush(stdout);
sin_size = sizeof(request);
recvFlag = recv(socketID, &request,sin_size,0);
perror("\n Err: ");
fprintf(stdout, "\n recvFlag: %d", recvFlag);
fprintf(stdout, "\n Time Slice request received:\n\tPid: %d \n\tTime Required: %d ", ntohs(request.processId), ntohs(request.timeRequired));
fflush(stdout);
snprintf(sendBuffer, sizeof(sendBuffer), "%.24s\n", ctime(&time));
write(clientID, sendBuffer, strlen(sendBuffer));
close(clientID);
sleep(1);
}
}else{
fprintf(stdout, " Unable to Bind");
}
close(socketID);
return 0;
}
And Client Code is:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
enum priority_e{ high = +1, normal = 0, low = -1};
typedef struct t_timeSliceRequest{
unsigned int processId;
unsigned int timeRequired;
int priority;
}timeSliceRequest;
int main(int argc, char *argv[])
{
int socketID = 0 /*Socket Descriptor*/, n = 0;
char recvBuffer[1024];
memset(recvBuffer, '0',sizeof(recvBuffer));
struct sockaddr_in servAddr;
struct t_timeSliceRequest request = { 1,2,high };
if(argc!=2){
fprintf(stderr,"\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
socketID = socket(AF_INET, SOCK_STREAM, 0);
if(socketID == -1){
fprintf(stderr, "\n Can't create socket \n");
return 1;
}
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(5000);
if(inet_pton(AF_INET, argv[1], &servAddr.sin_addr)==-1){
fprintf(stderr, "\n Unable to convert given IP to Network Form \n inet_pton Error");
return 1;
}
int connectFlag, sendFlag = 0;
connectFlag = connect(socketID, (struct sockaddr *)&servAddr, sizeof(servAddr));
if(connectFlag == -1){
fprintf(stderr, " Connection Failed\n");
return 1;
}
int sin_size = sizeof(struct t_timeSliceRequest);
fprintf(stdout, " \n %d \n %d \n %d", request.processId, request.timeRequired, request.priority);
sendFlag = send(socketID, &request, sin_size ,0);
fprintf(stdout, "\nSend Flag: %d\n", sendFlag);
n = read(socketID, recvBuffer, sizeof(recvBuffer)-1);
recvBuffer[n] = 0;
fprintf(stdout, "%s",recvBuffer);
if(n < 0){
fprintf(stderr, " Read error\n");
}
return 0;
}
This is the full Code, its giving 'Transport endpoint is not connected'
Keep in mind that sending structs like this over the network may lead to interoperability problems:
if source and destination have different endianess, you're going to receive wrong data (consider using functions like htonl to convert the data to network endianess)
you struct needs to be packed, otherwise different compilers can align differently the variables of the struct (see this to get an idea about aligning the variables)
In any case, ENOTCONN suggests an error establishing the connection between the two hosts.
Transport endpoint is not connected error is returned when your socket isn't bound to any (port,address) pair.
If it's a server side, you should use the socket descriptor that is returned by accept call. In case of a client - you should use a socket that is returned by the successful call to connect.
Btw, sending structure the way you are is quite dangerous. Compilers might insert padding bytes between structure members (invisible to you program, but they take space in the structure) to conform some alignment rules for the target platform. Besides, different platforms might have different endianness, which might screw your structure completely. If your client and server are compiled for different machines, the structure layout and endianness can be incompatible. To solve this problem, you can use packed structures. A way of declaring a structure as packed depends on a compiler. For GCC this can be done by means of adding a special attribute to a structure.
Another way to solve this problem is to put each individual field of a structure to a raw byte-buffer manually. The receiving side should take all this data out in exactly the same way as the data was originally put into that buffer. This approach can be tricky, since you need to take into account a network byte order when saving multi-byte values (like int, long etc). There is a special set of functions like htonl, htons, ntohs etc for that.
Updated
In your server:
recvFlag = recv(socketID, &request,sin_size,0);
Here it should be
recvFlag = recv(clientID, &request,sin_size,0);
socketID is a passive socket and can only accept connections (not send any data).
What is more, the result of accept isn't checked for -1.
Related
Was trying to implement a TCP echo server with C, and came across this code while searching the web and was trying to compile it. It shows some error related to socket.h
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <error.h>
#include <strings.h>
#include <unistd.h>
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
int main(int argc, char **argv)
{
struct sockaddr_in server;
struct sockaddr_in client;
int sock;
int new;
int sockaddr_len = sizeof(struct sockaddr_in);
int data_len;
char data[MAX_DATA];
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)
{
perror("server socket: ");
exit(-1);
}
server.sin_family=AF_INET;
server.sin_port=htons(atoi(argv[1]));
server.sin_addr.s_addr=INADDR_ANY;
bzero(&server.sin_zero, 0);
if((bind(sock, (struct sockaddr *)&server, sockaddr_len)) == ERROR)
{
perror("bind: ");
exit(-1);
}
if((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror("listen");
exit(-1);
}
while(1)
{
if((new = accept(sock, (struct sockaddr *)&client, sockaddr_len)) == ERROR)
{
perror("accept");
exit(-1);
}
printf("New Client connected from port no %d and IP %s\n", ntohs(client.sin_port), inet_ntoa(client.sin_addr));
data_len = 1;
while(data_len)
{
data_len = recv(new, data, MAX_DATA, 0);
if(data_len)
{
send(new, data, data_len, 0);
data[data_len] = '\0';
printf("Sent mesg: %s", data);
}
}
printf("Client disconnected\n");
close(new);
}
close(sock);
}
While compiling in Linux using gcc (Debian 8.3.0-6) 8.3.0 following warnings/errors are thrown,
tcp_srv.c: In function ‘main’:
tcp_srv.c:50:54: warning: passing argument 3 of ‘accept’ makes pointer from integer without a cast [-Wint-conversion]
if((new = accept(sock, (struct sockaddr *)&client, sockaddr_len)) == ERROR)
^~~~~~~~~~~~
In file included from tcp_srv.c:4:
/usr/include/x86_64-linux-gnu/sys/socket.h:233:28: note: expected ‘socklen_t * restrict’ {aka ‘unsigned int * restrict’} but argument is of type ‘int’
socklen_t *__restrict __addr_len);
The binary upon execution is giving a Segmentation fault which I assume due to this error. Tried googling this error but couldn't get any solutions as such.
accept prototype is:
int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
and manual says:
The address_len is a value-result parameter; it should initially
contain the
amount of space pointed to by address; on return it will contain the actual length
(in bytes) of the address returned.
Third argument must be pointer to a socklen_t thus:
if((new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)) == ERROR)
I am writing a program on a Linux system using Lazarus IDE. The program is supposed to connect to the Internet or Intranet. So, I want to display to the user list of all the available network connections that they can use to connect to the Internet or Intranet like wifi, if there are two active network cards on the system, then this program should display their available connections.
At the moment, I don't know where to start or what tool(s) to use.
Any hints, clues or advice will be greatly appreciated.
You can use ifconfig to list all available network interfaces and their status.
Edit: For doing it programmatically you have to use function ioctl with SIOCGIFCONF.
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int sockfd, len, lastlen;
char *ptr, *buf;
struct ifconf ifc;
struct ifreq *ifr;
char ifname[IFNAMSIZ + 1];
char str[INET6_ADDRSTRLEN];
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
lastlen = 0;
len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
for ( ; ; )
{
buf = malloc(len);
ifc.ifc_len = len;
ifc.ifc_buf = buf;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0)
{
if (errno != EINVAL || lastlen != 0)
exit(-1);
}
else
{
if (ifc.ifc_len == lastlen)
break; /* success, len has not changed */
lastlen = ifc.ifc_len;
}
len += 10 * sizeof(struct ifreq); /* increment */
free(buf);
}
printf("LEN: %d\n", ifc.ifc_len);
for (ptr = buf; ptr < buf + ifc.ifc_len; )
{
ifr = (struct ifreq *) ptr;
ptr += sizeof(struct ifreq); /* for next one in buffer */
memcpy(ifname, ifr->ifr_name, IFNAMSIZ);
printf("Interface name: %s\n", ifname);
const char *res;
switch (ifr->ifr_addr.sa_family)
{
case AF_INET6:
res = inet_ntop(ifr->ifr_addr.sa_family, &(((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr), str, INET6_ADDRSTRLEN);
break;
case AF_INET:
res = inet_ntop(ifr->ifr_addr.sa_family, &(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr), str, INET_ADDRSTRLEN);
break;
default:
printf("OTHER\n");
str[0] = 0;
res = 0;
}
if (res != 0)
{
printf("IP Address: %s\n", str);
}
else
{
printf("ERROR\n");
}
}
return 0;
}
ioctl SIOCGIFCONF will return, if success, a struct ifconf which has a pointer to an array of struct ifreq.
These structs are defined in net/if.h
Using this code, from ifc.ifc_req you can get all interfaces, please look at the declaration of struct ifreq in order to determine the length and type of each array element. I think from here you can continue alone, if not please let me know.
The following code does work on my Linux system. It outputs all the available connection point through which you can connect to the Internet or intranet. I modified the code to print out its name and ip address.
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
// you may need to include other headers
int main()
{
struct ifaddrs* interfaces = NULL;
struct ifaddrs* temp_addr = NULL;
int success;
char *name;
char *address;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while (temp_addr != NULL)
{
if (temp_addr->ifa_addr->sa_family == AF_INET) // internetwork only
{
name = temp_addr->ifa_name;
address = inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr);
printf("%s %s\n",name,address);
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
}
I am doing some testing with Unix domain sockets and I can communicate over them without an issue, however, when I call accept() on the server side of my test program, the returned struct sockaddr_un doesn't contain a sun_path.
I am pretty sure that Inet sockets have their address and port properly filled out after an accept() call, so am I doing something wrong in my test program or am I expecting the wrong outcome?
I am running CentOS 6.2 and gcc 4.4.6.
Sample Code:
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NAME "socket"
int main(int argc, char **argv)
{
int sock, msgsock, rval;
struct sockaddr_un server, client;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
for (;;) {
socklen_t len = sizeof(client);
msgsock = accept(sock, (struct sockaddr *)&client, &len);
if (msgsock == -1)
perror("accept");
else do {
printf("strlen(sun_path) = %zu\n", strlen(client.sun_path));
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
return 0;
}
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DATA "Half a league, half a league . . ."
int main(int argc, char **argv)
{
int sock;
struct sockaddr_un server;
if (argc < 2) {
printf("usage:%s <pathname>", argv[0]);
exit(1);
}
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[1]);
if (connect(sock, (struct sockaddr *) &server,
sizeof(struct sockaddr_un)) < 0) {
close(sock);
perror("connecting stream socket");
exit(1);
}
if (write(sock, DATA, sizeof(DATA)) < 0)
perror("writing on stream socket");
close(sock);
return 0;
}
Just to reiterate the question:
Why isn't sun_path filled out after the accept() call on the server?
I am really not sure if this is an answer at all. Probably it's more like musings about some research, though maybe still worth while reading.
The value filled by accept(2) seems to be quite protocol agnostic at least in Linux 3.16.0, NetBSD 6.1.4 and Darwin 13.1.0 kernels. In practice this means that the second parameter to accept(2), struct sockaddr * gets filled only up to what is shared between all protocols. So what you have in your hands after a successful acccept(2) is far from being a complete struct sockaddr_un.
Probably nobody thought it would be of much importance at the time first implementations of accept(2) were done and now we're stuck with this. Fortunately there is a way around that, in case one has lost the pathname used for socket with call to bind(2), and would now like to find it again.
With struct sockaddr_storage and getsockname(2) the member sun_path is accessible. So, to make sure you are getting all juicy details, call getsockname(2) after a successful call to accept(2) (this would be put after line number 40 in your server.c):
struct sockaddr_storage ss;
socklen_t sslen = sizeof(struct sockaddr_storage);
if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
printf("socket name is: %s\n", un->sun_path);
}
Or just use this:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NAME "socket"
int main(int argc, char **argv)
{
int sock, msgsock, rval;
struct sockaddr_un server, client;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
for (;;) {
socklen_t len = sizeof(client);
msgsock = accept(sock, (struct sockaddr *)&client, &len);
if (msgsock == -1)
perror("accept");
else do {
printf("strlen(sun_path) = %zu\n", strlen(client.sun_path));
struct sockaddr_storage ss;
socklen_t sslen = sizeof(struct sockaddr_storage);
if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
printf("socket name is: %s\n", un->sun_path);
}
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
return 0;
}
This has been tested, ie. it compiles and produces expected results, to work on a GNU/Linux system running kernel 3.16.0, a NetBSD system running 6.1.4 kernel, and a system equipped with OS/X Mavericks, running 13.1.0 kernel. In all of these behaviour of accept(2) is consistent: sun_path is nowhere to be found in the structure filled. The behaviour of getsockname(2) is consistent between different operating environments too, making all protocol specific details available.
You haven't bound your client socket to an address.
You don't need to bind your client socket to an address for connect() to work; but, if you expect to access your client address in your server, then you do have to bind().
Make sense?
Just setup a call to bind() before you connect in your client. Make sure you the path you use for you client is valid and check for errors as normal.
The following client program trys to connect to a server and finds the current time and date on that server.
/* Start with the usual includes and declarations. */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *host;
int sockfd;
int len, result;
struct sockaddr_in address;
struct hostent *hostinfo;
struct servent *servinfo;
char buffer[128];
if(argc == 1)
host = "localhost";
else
host = argv[1];
/* Find the host address and report an error if none is found. */
hostinfo = gethostbyname(host);
if(!hostinfo) {
fprintf(stderr, "no host: %s\n", host);
exit(1);
}
/* Check that the daytime service exists on the host. */
servinfo = getservbyname("daytime", "tcp");
if(!servinfo) {
fprintf(stderr,"no daytime service\n");
exit(1);
}
printf("daytime port is %d\n", ntohs(servinfo -> s_port));
/* Create a socket. */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
/* Construct the address for use with connect... */
address.sin_family = AF_INET;
address.sin_port = servinfo -> s_port;
address.sin_addr = *(struct in_addr *)*hostinfo -> h_addr_list;
len = sizeof(address);
/* ...then connect and get the information. */
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1) {
perror("oops: getdate");
exit(1);
}
result = read(sockfd, buffer, sizeof(buffer));
buffer[result] = '\0';
printf("read %d bytes: %s", result, buffer);
close(sockfd);
exit(0);
}
Question:
We run the above program on a client machine, how the function getservbyname can get the
server information without a reference to the server machine in the parameter list?
It examines /etc/services for an entry with the given service name and protocol.
$ grep "^daytime\s.*/tcp" /etc/services
daytime 13/tcp
getservbyname simply looks in /etc/services to find the "daytime" service using the "tcp" protocol.
It's just a convenience, to save you from parsing that file.
Edit (clarification)
Each of these protocols has a friendly name ("daytime", "http", etc) and a useful name (the port number - 13, 80 etc). /etc/services holds this mapping, nothing more.
We are trying to communicate with the server listening on Linux loopback interface via raw socket and it seems like the server does not get a single packet from us. The packets we send are visible in Wireshark.
Is raw socket on loopback possible at all? (Please, don't ask why we need it: it's too complicated to explain here)
EDIT: this is how we open it
_I_RawSocket = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))
memset( &ifr, 0, sizeof( ifr ) );
strcpy( ifr.ifr_ifrn.ifrn_name, _InterfaceName);
ioctl( _I_RawSocket, SIOCGIFINDEX, &ifr )
memset( &sll, 0, sizeof( sll ) );
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons( ETH_P_ALL );
bind( _I_RawSocket, (struct sockaddr *) &sll, sizeof( sll ))
The server is lighttpd and it's reachable via normal socket on localhost.
netstat --raw prints empty table but I'm absolutely sure we have two functional raw sockets on normal eth devices.
Raw sockets behave particularly fizzy with bind() and connect(), but I can't confirm that your issue lies with them. I suggest you follow a more straightforward approach:
Sender
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define DEST "127.0.0.1"
int main(int argc, char **argv)
{
int s;
struct sockaddr_in dst_addr;
char packet[50];
struct iphdr *ip = (struct iphdr *)packet;
if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
dst_addr.sin_family = AF_INET;
dst_addr.sin_port = 0; /* not needed in SOCK_RAW */
inet_pton(AF_INET, DEST, (struct in_addr *)&dst_addr.sin_addr.s_addr);
memset(dst_addr.sin_zero, 0, sizeof(dst_addr.sin_zero));
memset(packet, 'A', sizeof(packet)); /* payload will be all As */
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = htons(40);
ip->frag_off = 0; /* NF */
ip->ttl = 64;
ip->protocol = IPPROTO_RAW; /* this has to be IPPROTO_RAW */
ip->check = 0;
ip->saddr = dst_addr.sin_addr.s_addr;
ip->daddr = dst_addr.sin_addr.s_addr;
while(42) {
sleep(5);
if (sendto(s, packet, sizeof(packet), 0,
(struct sockaddr *)&dst_addr, (socklen_t)sizeof(dst_addr)) < 0)
perror("uh oh:");
}
return(0);
}
Receiver
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int s;
struct sockaddr_in src_addr;
char packet[50];
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(packet));
socklen_t *len = (socklen_t *)sizeof(src_addr);
int fromlen = sizeof(src_addr);
while(42) {
if (recvfrom(s, &packet, sizeof(packet), 0,
(struct sockaddr *)&src_addr, &fromlen) < 0)
perror("uh oh:");
int i = sizeof(struct iphdr); /* print the payload */
for(; i < sizeof(packet); i++) {
printf("%c", packet[i]);
}
printf("\n");
}
return(0);
}
I hope these behave exactly like you want them to. Read man 7 raw for the gory details of why this works and more importantly man 7 packet if you want to extend it. Also, take note that IPPROTO_RAW implies the IP_HDRINCL socket option, which is why we're constructing the ip header ourselves - although the IP checksum and total length are computed and filled in by the kernel, still.
edit: In addition, if you wanted a raw socket with which to send valid data to an application like lighttpd, you'd have to match the protocol argument to socket() as well as provide valid values for the IP header fields. A proper ethernet header is not mandatory - the only important field will be filled for you by the kernel stack.
Please make sure bind to if_index
if (ioctl(sock, SIOCGIFINDEX, &stEthReq ) < 0 )
{
printf( "failed to get IF index!" );
return -1;
}
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sll_family = AF_PACKET;
client_addr.sll_ifindex = stEthReq.ifr_ifru.ifru_ivalue;
client_addr.sll_protocol = VOS_HTONS(usEthType);
ret = bind(sock,(struct sockaddr *)(&client_addr), sizeof(client_addr));