Recently I have been struggling with servers for the first time:
The case is: I have a software (Motive from Optitrack) that provides a streaming of data via multicasting.
I have tried to modify a previous program, it can be build but I have some issues to solve:
1º- I want a .bat file to automatically open the server with the argc parameters, I have made one, but it doesn't work. The code is at the end.
2º When executing the .exe file, the console bips for a moment and closes. I suppose that it is because it returns -1, but maybe there is some error in the code.
I'm on Windows 10, using Code::Blocks and Gcc compiler.
The server code is:
#include <sys/types.h> /* for type definitions */
#include <winsock2.h> /* for win socket API calls */
#include <ws2tcpip.h> /* for win socket structs */
#include <stdio.h> /* for printf() and fprintf() */
#include <stdlib.h> /* for atoi() */
#include <string.h> /* for strlen() */
#define MAX_LEN 1024 /* maximum receive string size */
#define MIN_PORT 1051 /* minimum port allowed */
#define MAX_PORT 1051 /* maximum port allowed */
#define NUM_RIG_OBJ 2
int main(int argc, char *argv[]) {
int sock; /* socket descriptor */
int flag_on = 1; /* socket option flag */
struct sockaddr_in mc_addr; /* socket address structure */
char recv_str[MAX_LEN+1]; /* buffer to receive string */
int recv_len, ID ; /* length of string received */
struct ip_mreq mc_req; /* multicast request structure */
char* mc_addr_str ; /* multicast IP address */
unsigned short mc_port; /* multicast port */
struct sockaddr_in from_addr; /* packet source */
unsigned int from_len; /* source addr length */
WSADATA wsaData; /* Windows socket DLL structure */
float xa,ya,za,qx,qy,qz,qw;
/* validate number of arguments */
if (argc != 3) {
fprintf(stderr,
"Usage: %s <Multicast IP> <Multicast Port>\n",
argv[0]);
exit(1);
}
mc_addr_str = argv[1]; /* arg 1: multicast ip address */
mc_port = atoi(argv[2]); /* arg 2: multicast port number */
/* validate the port range */
if ((mc_port < MIN_PORT) || (mc_port > MAX_PORT)) {
fprintf(stderr, "Invalid port number argument %d.\n",
mc_port);
fprintf(stderr, "Valid range is between %d and %d.\n",
MIN_PORT, MAX_PORT);
exit(1);
}
/* Load Winsock 2.0 DLL */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
fprintf(stderr, "WSAStartup() failed");
exit(1);
}
/* create socket to join multicast group on */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket() failed");
exit(1);
}
/* set reuse port to on to allow multiple binds per host */
if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&flag_on,
sizeof(flag_on))) < 0) {
perror("setsockopt() failed");
exit(1);
}
/* construct a multicast address structure */
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = htonl(INADDR_ANY);
mc_addr.sin_port = htons(mc_port);
/* bind to multicast address to socket */
if ((bind(sock, (struct sockaddr *) &mc_addr,
sizeof(mc_addr))) < 0) {
perror("bind() failed");
exit(1);
}
/* construct an IGMP join request structure */
mc_req.imr_multiaddr.s_addr = inet_addr(mc_addr_str);
mc_req.imr_interface.s_addr = htonl(INADDR_ANY);
/* send an ADD MEMBERSHIP message via setsockopt */
if ((setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char*) &mc_req, sizeof(mc_req))) < 0) {
perror("setsockopt() failed");
exit(1);
}
int md=recv_str[0];
char *ptr = recv_str;
float x[NUM_RIG_OBJ]= {0};
float y[NUM_RIG_OBJ]= {0};
float z[NUM_RIG_OBJ]= {0};
float q1[NUM_RIG_OBJ]= {0};
float q2[NUM_RIG_OBJ]= {0};
float q3[NUM_RIG_OBJ]= {0};
float q4[NUM_RIG_OBJ]= {0};
for (;;) { /* loop forever */
/* clear the receive buffers & structs */
memset(recv_str, 0, sizeof(recv_str));
from_len = sizeof(from_addr);
memset(&from_addr, 0, from_len);
/* block waiting to receive a packet */
if ((recv_len = recvfrom(sock, recv_str, MAX_LEN, 0,
(struct sockaddr*)&from_addr, &from_len)) < 0) {
perror("recvfrom() failed");
exit(1);
}
/* output received string */
printf("Received %d bytes from %s: ", recv_len,
inet_ntoa(from_addr.sin_addr));
printf("%s", recv_str);
// rigid body pos/ori
if (md==7){
for (int i=0;i<NUM_RIG_OBJ;i++){
memcpy(&ID, ptr, 4); ptr += 4;
memcpy(&xa, ptr, 4); ptr += 4;
memcpy(&ya, ptr, 4); ptr += 4;
memcpy(&za, ptr, 4); ptr += 4;
memcpy(&qx, ptr, 4); ptr += 4;
memcpy(&qy, ptr, 4); ptr += 4;
memcpy(&qz, ptr, 4); ptr += 4;
memcpy(&qw, ptr, 4); ptr += 4;
printf("ID : %d\n", ID);
printf("pos: [%3.4f,%3.4f,%3.4f]\n", xa,ya,za);
printf("ori: [%3.4f,%3.4f,%3.4f,%3.4f]\n", qx,qy,qz,qw);
x[i]=xa;
y[i]=ya;
z[i]=za;
q1[i]=qx;
q2[i]=qy;
q3[i]=qz;
q4[i]=qw;
ptr = recv_str;
memcpy(ptr, &i, 4); ptr += 4;
memcpy(ptr, &x[i], 4); ptr += 4;
memcpy(ptr, &y[i], 4); ptr += 4;
memcpy(ptr, &z[i], 4); ptr += 4;
memcpy(ptr, &q1[i], 4); ptr += 4;
memcpy(ptr, &q2[i], 4); ptr += 4;
memcpy(ptr, &q3[i], 4); ptr += 4;
memcpy(ptr, &q4[i], 4); ptr += 4;
}
}
/* send a DROP MEMBERSHIP message via setsockopt */
if ((setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
(void*) &mc_req, sizeof(mc_req))) < 0) {
perror("setsockopt() failed");
exit(1);
}
closesocket(sock);
WSACleanup(); /* Cleanup Winsock */
}
return 0;
}
and the .bat file is
#echo off
echo Opening server...
cd C:\Users\Optitrack\Desktop\Conrado\mcreceive
start mcreceive.exe 259.44.99.107 1051
Any piece of advice would be much appreciated.
thank you
Related
I am writing a TCP client and server protocol for a school project. The client sends a "GET \r\n" message and the server has to transfer "+OK\r\n", size of the file and the file, in case it exists in the server directory. I'm blocked in the file transfer
I tried to solve it at small steps at a time. I set up the connection, sent the request from the client and received the "OK" message from the server.
Now I opened the file in the server and tried to send it 128 bytes at a time to the client. The reading of the file works and apparently also the sending of the buffers but the client is not receiving anything...
Here's my server.c
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "../errlib.h"
#include "../sockwrap.h"
#define BUFLEN 128 /* Buffer length */
#define TIMEOUT 15 /* TIMEOUT */
/* FUNCTION PROTOTYPES */
void service(int s);
/* GLOBAL VARIABLES */
char *prog_name;
int main(int argc, char *argv[])
{
int conn_request_skt; /* passive socket */
uint16_t lport_n, lport_h; /* port used by server (net/host ord.) */
int bklog = 2; /* listen backlog */
int s; /* connected socket */
fd_set cset; // waiting for connection
struct timeval tval; // timeout
size_t n;
socklen_t addrlen;
struct sockaddr_in saddr, caddr; /* server and client addresses */
prog_name = argv[0];
if (argc != 2) {
printf("Usage: %s <port number>\n", prog_name);
exit(1);
}
/* get server port number */
if (sscanf(argv[1], "%" SCNu16, &lport_h)!=1)
err_sys("Invalid port number");
lport_n = htons(lport_h);
/* create the socket */
printf("creating socket...\n");
s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("done, socket number %u\n",s);
/* bind the socket to any local IP address */
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = lport_n;
saddr.sin_addr.s_addr = INADDR_ANY;
showAddr("Binding to address", &saddr);
Bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
printf("done.\n");
/* listen */
printf ("Listening at socket %d with backlog = %d \n",s,bklog);
Listen(s, bklog);
printf("done.\n");
conn_request_skt = s;
/* main server loop */
for ( ; ; )
{
printf("waiting for connection...\n");
/* accept next connection */
FD_ZERO(&cset);
FD_SET(conn_request_skt, &cset);
tval.tv_sec = TIMEOUT;
tval.tv_usec = 0;
n = Select(FD_SETSIZE, &cset, NULL, NULL, &tval);
if ( n > 0 ){
addrlen = sizeof(struct sockaddr_in);
s = Accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
showAddr("Accepted connection from", &caddr);
printf("new socket: %u\n",s);
/* serve the client on socket s */
service(s);
} else {
printf("No connection request after %d seconds\n",TIMEOUT);
}
}
}
void service(int s) {
char buf[BUFLEN]; /* reception buffer */
char filename[BUFLEN];
int n;
long filesize;
uint32_t fsize;
FILE *fp;
for ( ; ; )
{
n = recv(s, buf, BUFLEN, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("Received request from socket %03d :\n", s);
sscanf(buf, "GET %s\r\n", filename);
strcpy(buf, "+OK\r\n");
printf("%s",buf);
if(writen(s, buf, strlen(buf)) != strlen(buf))
printf("Write error while sending +OK\n");
// open file
fp = fopen(filename, "r");
if( fp == NULL){
//TODO close connection
}
// calculating dim of file
fseek(fp, 0L, SEEK_END);
filesize = ftell(fp);
rewind(fp); // go back at beginning of file
fsize = htonl(filesize); // size file in network byte order
// sending file size
if(writen(s, &fsize, 4) != 4)
printf("Write error while sending file size\n");
while(fread(buf, 1, BUFLEN - 1, fp) == BUFLEN - 1){
printf("%s", buf);
if(writen(s, buf, strlen(buf)) != strlen(buf))
printf("Write error while buf\n");
}
printf("%s", buf);
printf("I am here\n");
}
}
}
While here is my client.c
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "../errlib.h"
#include "../sockwrap.h"
#define BUFLEN 128 /* BUFFER LENGTH */
#define TIMEOUT 15 /* TIMEOUT*/
/* GLOBAL VARIABLES */
char *prog_name;
int main(int argc, char *argv[])
{
char request[BUFLEN]; /* request buffer */
char rbuf[BUFLEN]; /* reception buffer */
uint32_t taddr_n; /* server IP addr. (net/host ord) */
uint16_t tport_n, tport_h; /* server port number (net/host ord) */
int s, len;
int result;
struct sockaddr_in saddr; /* server address structure */
struct in_addr sIPaddr; /* server IP addr. structure */
fd_set cset; // variables for timeout
struct timeval tval;
size_t n;
prog_name = argv[0];
if(argc < 4)
err_sys("Wrong number of parameters!\n");
// read address from first argument
taddr_n = inet_addr(argv[1]);
if (taddr_n == INADDR_NONE)
err_sys("Invalid address");
// read port number from second argument
if (sscanf(argv[2], "%" SCNu16, &tport_h)!=1)
err_sys("Invalid port number");
tport_n = htons(tport_h);
/* create the socket */
printf("Creating socket\n");
s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
printf("done. Socket fd number: %d\n",s);
/* prepare address structure */
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = tport_n;
saddr.sin_addr = sIPaddr;
printf("trying to connect to the server...\n");
/* connect */
showAddr("Connecting to target address", &saddr);
Connect(s, (struct sockaddr *) &saddr, sizeof(saddr));
printf("done.\n");
// loop to request files
for (int i = 3 ; i < argc ; i++ ){ // i = 4 because the first file is the fourth argument
// check if file name is too big
if(strlen(argv[i]) >= BUFLEN - 6)
err_sys("The file name is too big for the buffer request!\n");
// create the string of bytes for the request
strcpy(request, "GET ");
strcat(request, argv[i]);
strcat(request, "\r\n");
len = strlen(request);
if(writen(s, request, len) != len){
printf("Write error\n");
break;
}
printf("waiting for response...\n");
// receive file from server
n = recv(s, rbuf, BUFLEN, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("Received reply from server\n");
uint32_t fsize;
printf("%s",rbuf);
if(strcmp(rbuf, "+OK\r\n") == 0){
n = recv(s, &fsize, 4, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
// received file dimension
fsize = ntohl(fsize);
}
while(fsize > 0){
printf("I am here1n\n");
// receive file
n = recv(s, rbuf, BUFLEN-1, 0);
if (n < 0) {
printf("Read error\n");
close(s);
printf("Socket %d closed\n", s);
break;
} else if (n == 0) {
printf("Connection closed by party on socket %d\n",s);
close(s);
break;
} else {
printf("I am here");
fsize -= n;
}
}
}
}
}
printf("===========================================================\n");
close(s);
exit(0);
}
The recv in the client where I am supposed to receive the file just blocks without receiving anything. I don't understand what I am missing...
The issue here is a common one: You're not being careful with message boundaries.
In your client, you do a recv and check whether the number of bytes is greater than 0. But then you don't do more length checking. You next do a strcmp on a particular string you're expecting to receive (+OK\r\n). But you might have received 3 bytes (+OK) or you might have received 10: (+OK\r\nXXXXX) or more [aside: also, recv doesn't guarantee your byte string is null-terminated]. There is nothing stopping the kernel on the far side from batching the preamble plus subsequent bytes into a single TCP packet. Likewise, there is nothing preventing the local side from aggregating multiple TCP packets into a single buffer.
You must provide message boundaries. If you're expecting your next message to be 5 bytes, then you should receive exactly 5 bytes (and retry if you get fewer -- being careful to check for EOF too in case the other side aborted early). Or, alternatively stick a buffering layer in front of your receive logic so that it will receive up to some large amount, return to you the number of bytes you want, and then save whatever is in excess for a subsequent "receive" call.
To restate this in a different way: Your server sends +OK\r\n, then it sends a four-byte length, then it starts sending the file. But that means your first recv on the client side could be receiving the preamble, plus the length, plus the first N bytes of the file all in one system call.
TCP does not respect, provide or enforce message boundaries.
I have written a proxy that accepts connections from host1 and forwards the connection toward server2.
I accept a connection and then I start two threads to handle the connections... One thread to receive from host 1 and send to server2, and another thread to receive form server2 and send to host1.
My program compiles with no errors, and when I run it and connect host 1 my program fails at the function WRITE after some short time with no error.
The connection is OK, it just fails after short period of time, before write.
Also you can find the written function that I am using.
The code is failing at the CONTROLLER thread, when the controller is writing to the socket.
Why does the program fail with no error message at all?
/*
* File Server0.c
* ECHO TCP SERVER with the following features:
* - Gets port from keyboard
* - SEQUENTIAL: serves one client at a time
*/
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "mysocket.h"
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h> /* POSIX threads */
#define RBUFLEN 16384
/* FUNCTION PROTOTYPES */
int mygetline(char * line, size_t maxline, char *prompt);
int writen(SOCKET, char *, size_t);
void *mininet(void *);
void *controller(void *);
SOCKET s,s1[100],d[100];
int y=0,z=0;
int main()
{
uint16_t lport_n, lport_h;
int result;
socklen_t addrlen;
struct sockaddr_in saddr, caddr;
//fd_set readfds;
SOCKET conn_request_skt;
int bklog = 2,t=0;
pthread_t tid1[100];
pthread_t tid[100];
/* Initialize socket API if needed */
SockStartup();
/* input server port number */
lport_h=8888;
lport_n = htons(lport_h);
/* create the MININET socket */
printf("Creating first socketn");
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
err_fatal("socket() failed");
printf("done, socket number %un",s);
/* bind the MININET socket to any local IP address */
saddr.sin_family = AF_INET;
saddr.sin_port = lport_n;
saddr.sin_addr.s_addr = INADDR_ANY;
showAddr("Binding to address first socket", &saddr);
result = bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
if (result == -1)
err_fatal("bind() failed");
printf("done.n");
/* listen on MININET socket */
printf ("Listening at socket %d with backlog = %d n",s,bklog);
result = listen(s, bklog);
if (result == -1)
err_fatal("listen() failed");
printf("done.n");
conn_request_skt=s;
/* accept next connection from mininet */
for(;;)
{
addrlen = sizeof(struct sockaddr_in);
z++;
y++;
t++;
d[t] = accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
if (d[t] == INVALID_SOCKET)
err_fatal("accept() failed");
showAddr("Accepted connection from", &caddr);
printf("new accepted connection socket: %un",d[t]);
/* serve the client on socket s */
pthread_create(&tid[t], NULL, mininet, &t);
pthread_create(&tid1[t], NULL, controller, &t);
sleep(1);
}
exit(0);
}
void *mininet (void *arg)
{
char buf[RBUFLEN]; /* reception buffer */
int n,t,k;
t=y;
k=z;
printf("MININET: m is: %d, c is: %d n ", t,k);
/* main server loop */
for (;;)
{
printf("MININET receiving on socket: %un",d[t]);
n=recv(d[t], buf, RBUFLEN-1, 0);
if (n < 0)
{
printf("MININET Read errorn");
closesocket(d[t]);
printf("MININET Socket %d closedn", d[t]);
return NULL;
}
else if (n==0)
{
printf("Connection closed by MININET on socket %dn",d[t]);
closesocket(d[t]);
break;
}
else
{
printf("Received line from MININET socket %03d :n", d[t]);
buf[n]=0;
printf("[%s]n",buf);
printf("MINET WRITING TO: %un",s1[k]);
if(writen(s1[k], buf, n) != n)
printf("Write error while replying TO CONTROLERn");
else
printf("Reply sent towards CONTROLERn");
}
}
return NULL;
}
void *controller (void *arg)
{
char buf[RBUFLEN]; /* reception buffer */
uint16_t lport_n1, lport_h1; /* port where the server listens (net/host byte ord resp.) */
int result, n,t,k;
struct sockaddr_in saddr1; /* server and client address structures */
t=y;
k=z;
printf("CONTROLLER: m is: %d, c is: %d n ", t,k);
/* Initialize socket API if needed */
SockStartup();
lport_h1=6633;
lport_n1 = htons(lport_h1);
printf("Creating CONTROLLER socketn");
s1[k] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s1[k] == INVALID_SOCKET)
err_fatal("socket() failed");
printf("done, socket number %un",s1[k]);
/* bind the socket to any local IP address */
saddr1.sin_family = AF_INET;
saddr1.sin_port = lport_n1;
saddr1.sin_addr.s_addr = INADDR_ANY;
/* connect */
showAddr("Connecting to target CONTROLER address", &saddr1);
result = connect(s1[k], (struct sockaddr *) &saddr1, sizeof(saddr1));
if (result == -1)
err_fatal("connect() failed");
printf("done.n");
/* main server loop */
for (;;)
{
printf("CONTROLER receiving on socket: %un",s1[k]);
n=recv(s1[k], buf, RBUFLEN-1, 0);
if (n < 0)
{
printf("CONTROLER Read errorn");
closesocket(s1[k]);
printf("Socket %d closedn", s1[k]);
return NULL;
}
else if (n==0)
{
printf("Connection closed by CONTROLER on socket %dn",s1[k]);
closesocket(s1[k]);
return NULL;
}
else
{
printf("Received line from CONTROLER socket %03d :n", s1[k]);
buf[n]=0;
printf("[%s]n",buf);
printf("CONTROLER writing on socket: %un",d[t]);
if(writen(d[t], buf, n) != n)
printf("Write error while replying TO MININETn");
else
printf("Reply sent towards MININETn");
}
}
return NULL;
}
/* Gets a line of text from standard input after having printed a prompt string Substitutes end of line with ''
Empties standard input buffer but stores at most maxline-1 characters in the passed buffer
*/
int mygetline(char *line, size_t maxline, char *prompt)
{
char ch;
size_t i;
printf("%s", prompt);
for (i=0; i< maxline-1 && (ch = getchar()) != 'n' && ch != EOF; i++)
*line++ = ch;
*line = '';
while (ch != 'n' && ch != EOF)
ch = getchar();
if (ch == EOF)
return(EOF);
else
return(1);
}
/* Writes nbytes from buffer ptr to stream socket s */
int writen(SOCKET s, char *ptr, size_t nbytes)
{
size_t nleft;
ssize_t nwritten;
for (nleft=nbytes; nleft > 0; )
{
nwritten = send(s, ptr, nleft, 0);
if (nwritten <=0)
return (nwritten);
else
{
nleft -= nwritten;
ptr += nwritten;
}
}
return (nbytes - nleft);
}
have a stand alone PC running VS6 on WinXP - yes ancient technology.
I am porting a C code app from Linux.
Stuck on multicast problem
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h> /* for printf(), fprintf() */
#include <conio.h>
#include <winsock.h> /* for socket(),... */
#include <stdlib.h> /* for exit() */
#define MAXRECVSTRING 255 /* Longest string to receive */
int main(int argc, char* argv[])
{
char msg[100];
char loopchar = 0;
int iOptVal = 0;
char iOptVal2 = 1;
int iLenOptVal = sizeof(int);
int result = -1;
int retval = -1;
int set_option_on = 1;
int sock; /* Socket */
struct sockaddr_in multicastAddr; /* Multicast Address */
char *multicastIP; /* IP Multicast Address */
unsigned short multicastPort; /* Port */
char recvString[MAXRECVSTRING+1]; /* Buffer for received string */
unsigned int recvStringLen; /* Length of received string */
struct ip_mreq multicastRequest; /* Multicast address join structure */
WSADATA wsaData; /* Structure for WinSock setup communication */
if (argc != 3) /* Test for correct number of arguments */
{
fprintf(stderr,"Usage: %s <Multicast IP> <Multicast Port>\n", argv[0]);
exit(1);
}
multicastIP = argv[1]; /* First arg: Multicast IP address (dotted quad) */
//WW Silversilsied //WW SilversilsiedmulticastIP = inet_addr("224.000.010.101"); /* First arg: Multicast IP address (dotted quad) */
//multicastIP = inet_addr("224.000.010.101"); /* First arg: Multicast IP address (dotted quad) */
multicastPort = atoi(argv[2]);/* Second arg: Multicast port */
//multicastPort = 6600);/* Second arg: Multicast port */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) /* Load Winsock 2.0 DLL */
{
fprintf(stderr, "WSAStartup() failed");
exit(1);
}
/* Create a best-effort datagram socket using UDP */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf("\nsocket() failed - error = %d\n", sock);
}
/* Construct bind structure */
memset(&multicastAddr, 0, sizeof(multicastAddr)); /* Zero out structure */
multicastAddr.sin_family = AF_INET; /* Internet address family */
multicastAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
multicastAddr.sin_port = htons(multicastPort); /* Multicast port */
/* Bind to the multicast port */
retval = bind(sock, (struct sockaddr *) &multicastAddr, sizeof(multicastAddr));
if (retval < 0)
{
printf("\nbind() failed - error = %d\n", retval);
}
#if 0
/* Specify the multicast group */
multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastIP);
/* Accept multicast from any interface */
multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
/* Join the multicast address */
//if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicastRequest, sizeof(multicastRequest)) < 0)
result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&set_option_on, sizeof(set_option_on));
if (result < 0)
{
printf("\n setsockopt() failed");
perror(" setsockopt ");
}
/* Receive a single datagram from the server */
while(1)
{
if ((recvStringLen = recvfrom(sock, recvString, MAXRECVSTRING, 0, NULL, 0)) < 0)
{
printf("\nrecvfrom() failed");
}
Sleep(1000);
}
#else
strcpy(msg,"default test message");
struct sockaddr_in address1;
int len;
int bytes_sent = -1;
memset(&address1, 0, sizeof(address1));
address1.sin_family = AF_INET;
address1.sin_port = multicastPort;
address1.sin_addr.s_addr = inet_addr(multicastIP);
//msg = "abcdefghijklmnopqrstuvwxyz";
//socklen_t len;
//size = strlen(msg);
if ((recvStringLen = recvfrom(sock, recvString, 1024, 0, (struct sockaddr*)&address1, &len)) < 0)
{
printf("\nrecvfrom() failed ");
perror(" recvfrom ");
}else{
recvString[recvStringLen] = '\0';
printf("Received: %d bytes %s\n", recvStringLen,recvString); /* Print the received string */
perror(" received from ");
}
bytes_sent = sendto(sock,
msg,
sizeof(msg),
0,
(struct sockaddr*)&address1,
sizeof(address1));
printf("bytes sent = %d \n", bytes_sent);
printf("size of msg = %d \n ", sizeof(msg));
perror( "sendto ");
#endif
getch();
closesocket(sock);
WSACleanup(); /* Cleanup Winsock */
exit(0);
return 0;
}
When I single step through, I get a successful socket creation and valid socket descriptor.
I get a successful bind, at which point the port shows up as udp when I do a cmd line netstat -p UDP -a
setsockopt also completes without error.
When I step through the recvfrom it receives 2^24 bytes all of which are the same -52
The machine is stand alone, not on a network.
recvString is 256 bytes long, but your recvFrom() is asking for up to 1024 bytes.
I wrote a very small C code to open an UDP multicast socket, it works well on
a 32 bits platform but when I recompile my code and try it on a linux 64
bits platform it doesn't work. The program is pending undefinitely on the
recvfrom() function. I checked if the udp frames were actually received on the
specified network interface with tcpdump, but everything works fine. Does
anybody have an idea on what is wrong with my code ?
Here is the first code (before your comments) :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <math.h>
#include <errno.h>
static char* server = "231.180.0.1";
static char* network = "66.46.40.10";
static int port = 50001;
static struct sockaddr_in socketAddr;
static unsigned int socketDesc;
long toLong (unsigned char* msg, int offset);
int main (void) {
struct ip_mreq mreq;
int bindDesc, socketOptDesc;
int reuse = 1;
unsigned int socketLength = sizeof(socketAddr);
// Allocation
memset((char *) &socketAddr, 0, sizeof(socketAddr));
memset(&mreq, 0, sizeof(struct ip_mreq));
/*
* Create a datagram socket on which to receive.
*/
printf("# Init socket (server=%s network=%s port=%d)\n", server, network, port);
socketDesc = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketDesc < 0) {
perror("socket() failed");
} else {
/*
* Enable SO_REUSEADDR to allow multiple instances of this
* application to receive copies of the multicast datagrams.
*/
socketOptDesc = setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse));
if (socketOptDesc < 0) {
perror("setsockopt() failed");
} else {
/*
* Bind to the proper port number with the IP address
* specified as INADDR_ANY.
*/
socketAddr.sin_family = AF_INET;
socketAddr.sin_port = htons(port);
socketAddr.sin_addr.s_addr = INADDR_ANY;
bindDesc = bind(socketDesc, (struct sockaddr*) &socketAddr, sizeof(socketAddr));
if (bindDesc < 0) {
perror("bind() failed");
} else {
/*
* Join the multicast group on the local interface.
* Note that this IP_ADD_MEMBERSHIP option must be
* called for each local interface over which the multicast
* datagrams are to be received.
*/
mreq.imr_multiaddr.s_addr = inet_addr(server);
mreq.imr_interface.s_addr = inet_addr(network);
socketOptDesc = setsockopt(socketDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
if (socketOptDesc < 0) {
perror("setsockopt() failed");
} else {
printf("# Socket created successfully !\n");
}
}
}
}
/*
* Acquisition Loop
*/
printf("# Starting reception loop...\n");
long lastFrameNumber = -1;
int nbDots = 0;
while (1) {
long frameNumber = -1;
unsigned char buffer[65536];
// Frame Acquisition
int ret = recvfrom(socketDesc, buffer, 65536, 0, (struct sockaddr *) &socketAddr, &socketLength);
if (ret < 0) {
perror("recvfrom() failed");
}
// Reading frame number
frameNumber = toLong(buffer, 28);
if (frameNumber < 0) {
// Context Frame
} else if (frameNumber == 0) {
printf("Invalid frame (frameNumber=0)\n");
} else {
if (frameNumber > 1 && frameNumber != (lastFrameNumber + 1)) {
printf("%ld frame(s) lost from frame %ld\n", frameNumber - lastFrameNumber - 1, lastFrameNumber + 1);
}
}
lastFrameNumber = frameNumber;
if (frameNumber == 1) {
if (nbDots > 50) {
printf(".\n");
nbDots = 0;
} else {
printf(".");
fflush(stdout);
}
nbDots++;
}
}
return EXIT_SUCCESS;
}
/* ======================================================================
* Read 4 bytes from the specified offset and convert it to a long value.
*
* #input msg
* Byte array representing the message.
* #input offset
* Byte offset.
* #return
* Long value representing the frame number.
* ====================================================================*/
long toLong (unsigned char* msg, int offset) {
long value;
int byte0; // bits 31..24
int byte1; // bits 23..16
int byte2; // bits 15..8
int byte3; // bits 7..0
byte0 = (0x000000FF & ((int) msg[offset + 0]));
byte1 = (0x000000FF & ((int) msg[offset + 1]));
byte2 = (0x000000FF & ((int) msg[offset + 2]));
byte3 = (0x000000FF & ((int) msg[offset + 3]));
value = ((long) (byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3)) & 0xFFFFFFFFL;
return value;
}
EDIT :
I updated my code with your comments but it doesn't work either :( Also, I forgot to say that the network is using VLAN. The network interface is eth.40 at 66.46.40.100 but it work on a 32 bit platform so it might not be the problem.
Here is the new code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <math.h>
#include <errno.h>
static char* server = "231.180.0.1";
static char* network = "66.46.40.100";
static uint16_t port = 50001;
long toLong (unsigned char* msg, int offset);
int main (void) {
struct sockaddr_in socketAddr;
struct ip_mreq mreq;
int bindDesc, socketDesc, socketOptDesc;
socklen_t reuse = 1;
socklen_t socketLength = sizeof(socketAddr);
// Allocation
memset((char *) &socketAddr, 0, sizeof(socketAddr));
memset(&mreq, 0, sizeof(struct ip_mreq));
/*
* Create a datagram socket on which to receive.
*/
printf("# Init socket (server=%s network=%s port=%d)\n", server, network, port);
socketDesc = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketDesc < 0) {
perror("socket() failed");
} else {
/*
* Enable SO_REUSEADDR to allow multiple instances of this
* application to receive copies of the multicast datagrams.
*/
socketOptDesc = setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, (void *) &reuse, sizeof(reuse));
if (socketOptDesc < 0) {
perror("setsockopt() failed");
} else {
/*
* Bind to the proper port number with the IP address
* specified as INADDR_ANY.
*/
socketAddr.sin_family = AF_INET;
socketAddr.sin_port = htons(port);
socketAddr.sin_addr.s_addr = INADDR_ANY;
bindDesc = bind(socketDesc, (struct sockaddr*) &socketAddr, sizeof(socketAddr));
if (bindDesc < 0) {
perror("bind() failed");
} else {
/*
* Join the multicast group on the local interface.
* Note that this IP_ADD_MEMBERSHIP option must be
* called for each local interface over which the multicast
* datagrams are to be received.
*/
mreq.imr_multiaddr.s_addr = inet_addr(server);
mreq.imr_interface.s_addr = inet_addr(network);
socketOptDesc = setsockopt(socketDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
if (socketOptDesc < 0) {
perror("setsockopt() failed");
} else {
printf("# Socket created successfully !\n");
}
}
}
}
/*
* Acquisition Loop
*/
printf("# Starting reception loop...\n");
long lastFrameNumber = -1;
int nbDots = 0;
while (1) {
unsigned char buffer[65536];
// Frame Acquisition
ssize_t ret = recvfrom(socketDesc, buffer, 65536, 0, (struct sockaddr *) &socketAddr, &socketLength);
if (ret < 0) {
perror("recvfrom() failed");
} else {
printf("# Receiving frame\n");
}
}
return EXIT_SUCCESS;
}
One obvious 64-bit problem that you have in the code is that the last argument to recvfrom should be a pointer to a socklen_t and not unsigned int that you have in your code. socklen_t will most likely be a 64 bit variable on 64 bit machines, while unsigned int will most likely be 32 bits.
Another problem is socketDesc being unsigned. File descriptors are always signed so that you can actually detect errors from functions that return them. Your checks for errors from all the functions will not work, so it's possible that your code failed much earlier and you didn't notice.
Another possible problem is your toLong function, long is quite often 64 bits on a 64 bits platform while you're treating it as a 32 bit value.
Try building with warnings, the compiler should be quite helpful. This is definitely something that your compiler will warn you about. If that doesn't help, double check the manual pages for all the functions you call and check that the types are right.
I'm trying to create an ICMP ping test program in C but am having difficulties with successfully sending the packets. The sendto function returns the # of bytes and everything but no packets are actually sent. I've verified this with WireShark on the destination computer. A regular ping on the host works fine and shows up in WireShark though.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
unsigned short cksum(unsigned short *addr, int len);
int main(int argc, char *argv[])
{
int sock;
char send_buf[400], recv_buf[400], src_name[256], src_ip[15], dst_ip[15];
struct ip *ip = (struct ip *)send_buf;
struct icmp *icmp = (struct icmp *)(ip + 1);
struct hostent *src_hp, *dst_hp;
struct sockaddr_in src, dst;
struct timeval t;
int on;
int num = 10;
int failed_count = 0;
int bytes_sent, bytes_recv;
int dst_addr_len;
int result;
fd_set socks;
/* Initialize variables */
on = 1;
memset(send_buf, 0, sizeof(send_buf));
/* Check for valid args */
if(argc < 2)
{
printf("\nUsage: %s <dst_server>\n", argv[0]);
printf("- dst_server is the target\n");
exit(EXIT_FAILURE);
}
/* Check for root access */
if (getuid() != 0)
{
fprintf(stderr, "%s: This program requires root privileges!\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Get source IP address */
if(gethostname(src_name, sizeof(src_name)) < 0)
{
perror("gethostname() error");
exit(EXIT_FAILURE);
}
else
{
if((src_hp = gethostbyname(src_name)) == NULL)
{
fprintf(stderr, "%s: Can't resolve, unknown source.\n", src_name);
exit(EXIT_FAILURE);
}
else
ip->ip_src = (*(struct in_addr *)src_hp->h_addr);
}
/* Get destination IP address */
if((dst_hp = gethostbyname(argv[1])) == NULL)
{
if((ip->ip_dst.s_addr = inet_addr(argv[1])) == -1)
{
fprintf(stderr, "%s: Can't resolve, unknown destination.\n", argv[1]);
exit(EXIT_FAILURE);
}
}
else
{
ip->ip_dst = (*(struct in_addr *)dst_hp->h_addr);
dst.sin_addr = (*(struct in_addr *)dst_hp->h_addr);
}
sprintf(src_ip, "%s", inet_ntoa(ip->ip_src));
sprintf(dst_ip, "%s", inet_ntoa(ip->ip_dst));
printf("Source IP: '%s' -- Destination IP: '%s'\n", src_ip, dst_ip);
/* Create RAW socket */
if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
{
perror("socket() error");
/* If something wrong, just exit */
exit(EXIT_FAILURE);
}
/* Socket options, tell the kernel we provide the IP structure */
if(setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0)
{
perror("setsockopt() for IP_HDRINCL error");
exit(EXIT_FAILURE);
}
/* IP structure, check the ip.h */
ip->ip_v = 4;
ip->ip_hl = 5;
ip->ip_tos = 0;
ip->ip_len = htons(sizeof(send_buf));
ip->ip_id = htons(321);
ip->ip_off = htons(0);
ip->ip_ttl = 255;
ip->ip_p = IPPROTO_ICMP;
ip->ip_sum = 0;
/* ICMP structure, check ip_icmp.h */
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_id = 123;
icmp->icmp_seq = 0;
/* Set up destination address family */
dst.sin_family = AF_INET;
/* Loop based on the packet number */
for(int i = 1; i <= num; i++)
{
/* Header checksums */
icmp->icmp_cksum = 0;
ip->ip_sum = cksum((unsigned short *)send_buf, ip->ip_hl);
icmp->icmp_cksum = cksum((unsigned short *)icmp,
sizeof(send_buf) - sizeof(struct icmp));
/* Get destination address length */
dst_addr_len = sizeof(dst);
/* Set listening timeout */
t.tv_sec = 5;
t.tv_usec = 0;
/* Set socket listening descriptors */
FD_ZERO(&socks);
FD_SET(sock, &socks);
/* Send packet */
if((bytes_sent = sendto(sock, send_buf, sizeof(send_buf), 0,
(struct sockaddr *)&dst, dst_addr_len)) < 0)
{
perror("sendto() error");
failed_count++;
printf("Failed to send packet.\n");
fflush(stdout);
}
else
{
printf("Sent %d byte packet... ", bytes_sent);
fflush(stdout);
/* Listen for the response or timeout */
if((result = select(sock + 1, &socks, NULL, NULL, &t)) < 0)
{
perror("select() error");
failed_count++;
printf("Error receiving packet!\n");
}
else if (result > 0)
{
printf("Waiting for packet... ");
fflush(stdout);
if((bytes_recv = recvfrom(sock, recv_buf,
sizeof(ip) + sizeof(icmp) + sizeof(recv_buf), 0,
(struct sockaddr *)&dst,
(socklen_t *)&dst_addr_len)) < 0)
{
perror("recvfrom() error");
failed_count++;
fflush(stdout);
}
else
printf("Received %d byte packet!\n", bytes_recv);
}
else
{
printf("Failed to receive packet!\n");
failed_count++;
}
fflush(stdout);
icmp->icmp_seq++;
}
}
/* Display success rate */
printf("Ping test completed with %d%% success rate.\n",
(((num - failed_count) / num) * 100));
/* close socket */
close(sock);
return 0;
}
/* One's Complement checksum algorithm */
unsigned short cksum(unsigned short *addr, int len)
{
int nleft = len;
int sum = 0;
unsigned short *w = addr;
unsigned short answer = 0;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
Any thoughts at what I'm doing wrong? Also, are the checksums alright? Is it fine to just use 0 for both?
EDIT: OK, so I've managed to get the packets sent properly thanks to the folks below! And the destination computer will send back an echo reply. However, now, my program doesn't pick up the reply. The select() function always times out. I've updated my code above.
EDIT 2: Alright, I've got it working! I needed to set the socket protocol to IPPROTO_ICMP instead of IPPROTO_RAW and it worked great! Thanks again you guys that commented! Really helped out! Looks like I can only mark one answer correct, but you all aided in fixing this. :)
Just one thing that I've noticed...
You've got this:
struct ip *ip = (struct ip *)send_buf;
Then, you are assigning destination field:
ip->ip_dst = (*(struct in_addr *)dst_hp->h_addr)
And then you are erasing it with memset (since send_buff points to the same thing):
memset(send_buf, 0, sizeof(send_buf));
So, when you are trying to get ip_dst here:
dst.sin_addr = ip->ip_dst;
you are getting 0 instead of what you set earlier.
At first glance: You can't rely on time struct after select().
You should also set usec.
So in the code, include the specification of t values inside the for loop:
for (i = 1; i <= num; i++) {
t.tv_sec = 5;
t.tv_usec = 0;
...
Else when you get on second iteration t (can have) changed.
In your sprintf(src_ip, ...) and dst_ip you have omitted format.
In addition to ebutusov's reply:
ip->ip_sum = 0;
icmp->icmp_cksum = htons(~(ICMP_ECHO << 8));
Are both incorrect.
You need to calculate the checksum properly (it's the same algorithm for both, but covers different fields).