How to set up two UDP sockets in one executable? - c

I am new to the topic of network communication, but would like to set up an UDP server client connection, with one participant continuously broadcasting data whether anyone is listening in on it or not and two participants that start receiving and storing these information whenever they are ready to do so (It's fine if they miss what has been sent before that point). The idea is that there is no other communication than one participant sending data (fire and forget) and two participants receiving them, without any form of feedback to the sending part. For now I would like to get it running on my local host, but would like to use it on a network.
I have been looking into a solution for quite some time now and decided to have a client broadcast the file stream continuously on two separate ports so, so that the receiving two servers can bind to a port respectively without blocking each other (If there is a better way, I am open for suggestions).
So far I have been able to set up this kind of communication with one client and one server, following these instructions. However, when I try to set up a second socket in my client executable, I always receive the error message Invalid argument once I reach the sendto() part.
Seeing as I have not been able to find a solution myself, yet I would like to ask for some help.
My code so far consists of the
Client:
/** set up socket_1 properties */
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
/** Read address information of incoming connection */
int status;
struct addrinfo *servinfo;
if ((status = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 1;
}
/** loop through all the results and bind to the first we can */
int sockfd;
struct addrinfo *p;
for ( p = servinfo; p != NULL; p = p->ai_next ) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
break;
}
if (p == NULL) {
printf("[ERROR]: Failed to bind broadcaster socket 1: %s.\n", strerror(errno) );
return 2;
}
/** set up socket_2 */
// ( reuse socket_1 hints and change the port number )
/** Read address information of incoming connection */
int status_2;
struct addrinfo *servinfo_2;
if ((status_2 = getaddrinfo(NULL, MYPORT_2, &hints, &servinfo_2)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status_2));
return 1;
}
/** loop through all the results and bind to the first we can */
int sockfd_2;
struct addrinfo *p_2;
for ( p_2 = servinfo_2; p_2 != NULL; p_2 = p_2->ai_next ) {
if ((sockfd_2 = socket(p_2->ai_family, p_2->ai_socktype, p_2->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
break;
}
if (p_2 == NULL) {
printf("[ERROR]: Failed to bind broadcaster socket 2: %s.\n", strerror(errno) );
return 2;
}
...
some file read/write related stuff
...
while ( /* some condition */ )
{
if ( ( readBytes = pread( fd, buf, BUFFER_SIZE, offset ) ) == -1 ){
printf("[ERROR]: %s.\n", strerror(errno) );
free( buf );
close( fd );
close( sockfd );
exit(1);
}
// the next line is generating the error message
if ( ( numbytes = sendto( sockfd, buf, readBytes, 0, p->ai_addr, p->ai_addrlen ) ) == -1 )
{
perror("sender_1: sendo.\n");
free( buf );
close( fd );
close( sockfd );
exit(1);
}
if ( ( numbytes = sendto( sockfd_2, buf, readBytes, 0, p_2->ai_addr, p_2->ai_addrlen ) ) == -1 )
{
perror("sender_2: sendo.\n");
free( buf );
close( fd );
close( sockfd_2 );
exit(1);
}
}
.
.
.
free( buf );
freeaddrinfo(servinfo);
freeaddrinfo(servinfo_2);
printf( "Broadcasting complete.\n" );
/** Clean what is not necessary anymore */
close( fd );
close( sockfd );
return 0;
}
I tried to add the reuse port and IP functionality to make sure that there is nothing blocking the setup of the new socket, but this did not solve my problem
My server side seems to work fine, but just in case I will post it here, too:
int main(int argc, char **argv)
{
if (argc < 2){
printf("Please provide image Name ID.\n");
exit(1);
}
struct addrinfo hints;
struct addrinfo *servinfo = NULL; // will point to getaddrinfo() results
memset(&hints, 0, sizeof hints); // make sure struct is empty
hints.ai_family = AF_UNSPEC; // don't care if IPv4 or IPv6
hints.ai_socktype = SOCK_DGRAM; // Use UDP protocol
hints.ai_flags = AI_PASSIVE;
int res;
if ((res = getaddrinfo( NULL, argv[1]/* SERVERPORT*/, &hints, &servinfo )) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(res));
return 1;
}
/** Get socket file descriptor */
int sockfd;
struct addrinfo *p = NULL;
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
/** Allow the reuse of an IP */
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
exit(1);
}
/** Allow the reuse of a socket */
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
exit(1);
}
/** Bind found socket to desired port */
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
printf("[ERROR]: Failed to bind socket to desired port: %s.\n", strerror( errno ) );
continue;
}
break;
}
struct timeval read_timeout;
read_timeout.tv_sec = 30;
read_timeout.tv_usec = 500;
if ( setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof read_timeout) < 0 ){
printf( "[ERROR]: %s.\n", strerror(errno) );
}
...
some file read/write stuff
...
while ( ( numbytes = recvfrom(sockfd, buf, BUFFER_SIZE, 0, (struct sockaddr *)&their_addr, &addr_len ) ) != -1)
{
.
.
.
}
printf("Done broadcasting.\n");
freeaddrinfo(servinfo);
close(sockfd);
return 0;
}
It would be much appreciated if anybody could provide me some help or point me into the right direction where to look for a solution.
Best regards

Related

How to get client IP by the socket number in C

I'm writing a simple client-server code in C.
i was asked for the server to print the IP address of the client that connected to it.
However, i can't seem to find a way to know the client's IP address from the server console.
Is there a way to do that?
// Initialize Winsock.
if ( StartupRes != NO_ERROR )
{
printf( "error %ld at WSAStartup( ), ending program.\n", WSAGetLastError() );
// Tell the user that we could not find a usable WinSock DLL.
return;
}
/* The WinSock DLL is acceptable. Proceed. */
// Create a socket.
MainSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( MainSocket == INVALID_SOCKET )
{
printf( "Error at socket( ): %ld\n", WSAGetLastError( ) );
return;
}
// Create a sockaddr_in object and set its values.
// Declare variables
Address = inet_addr(CHANNEL_IP);
if ( Address == INADDR_NONE )
{
printf("The string \"%s\" cannot be converted into an ip address. ending program.\n",
CHANNEL_IP);
return;
}
service.sin_family = AF_INET;
service.sin_addr.s_addr = Address;
service.sin_port = htons(clientinfo->senderPort);
//Bind the socket
bindRes = bind( MainSocket, ( SOCKADDR* ) &service, sizeof( service ) );
if ( bindRes == SOCKET_ERROR )
{
printf( "Channel-bind( ) failed with error %ld. Ending program\n", WSAGetLastError( ) );
return;
}
// Listen on the Socket.
ListenRes = listen( MainSocket, SOMAXCONN );
if ( ListenRes == SOCKET_ERROR )
{
printf( "Failed listening on socket, error %ld.\n", WSAGetLastError() );
return;
}
printf("Channel waiting for sender to connect...\n");
//Accepting connection
SenderSocket = accept( MainSocket, NULL, NULL );
if ( SenderSocket == INVALID_SOCKET ){
printf( "Accepting connection with client failed, error %ld\n", WSAGetLastError() ) ;
return;}
else
printf( "Sender Connected.\n" );
You need to pass in non-null values for the second and third parameters to accept:
struct sockaddr_in client_addr;
socklen_t slen = sizeof(client_addr);
SenderSocket = accept( MainSocket, (struct sockaddr *)&client_addr, &slen );
You can then get the client's IP and port from client_addr.

listen(): invalid argument

Trying to create a server-client application, and I'm having quite a bit of trouble setting up the connection on the server-side. After setting up the socket, and bind()ing the socket, my listen()-call fails with the error message
listen: Invalid argument
which I get from perror()-ing the case where listen() returns -1.
The synopsis of the program is the following: I use getaddrinfo() to generate a linked list of struct addrinfo's, loop through that until I find one that I can successfully create a socket with, then bind() and finally listen().
The listen() call goes as follows:
if ((status = listen(socket_fd, BACKLOG_SIZE)) == -1) {
perror("listen");
close(socket_fd);
freeaddrinfo(res);
exit(EXIT_FAILURE);
}
To be sure, I've printed the values of socket_fd and BACKLOG_SIZE, turning out to be 3 and 5, respectively. Have been debugging for hours now, and I simply cannot find out where the problem lies. Haven't found anyone with the same issue on stackOverflow, either...
Thank you in advance for any help!
Full program:
int main(int argc, char* argv[]) {
int port_no = server_usage(argc, argv);
ready_connection(port_no);
/* Synopsis:
getaddrinfo()
socket()
bind()
listen()
accept()
*/
int socket_fd = setup_socket(NULL, port_no);
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
int new_fd = 0;
// Allow reuse of sockets
int activate=1;
setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &activate, sizeof(int));
if ((status = bind(socket_fd, res->ai_addr, res->ai_addrlen)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
if ((status = connect(socket_fd, res->ai_addr, res->ai_addrlen)) == -1) {
perror("connect");
close(socket_fd);
freeaddrinfo(res); // free the linked-list
exit(EXIT_FAILURE);
}
if ((status = listen(socket_fd, BACKLOG_SIZE)) == -1) {
perror("listen");
close(socket_fd);
freeaddrinfo(res); // free the linked-list
exit(EXIT_FAILURE);
}
if ((new_fd == accept(socket_fd, (struct sockaddr *)&their_addr, &addr_size)) == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
char buffer[BUFSIZE];
recv(new_fd, buffer, BUFSIZE, 0);
close(socket_fd);
close(new_fd);
freeaddrinfo(res); // free the linked-list
return 0;
}
setup_socket()-function:
int setup_socket(char* hostname, int port_no) {
// hints is mask struct, p is loop variable
struct addrinfo hints, *p;
memset(&hints, 0, sizeof hints); // make sure the struct is empty
// TODO IPv6-support?
hints.ai_family = AF_INET; // only IPv4 supported
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
char port_str[6]; // max port size is 5 digits + 0-byte
memset(port_str, 0, 6);
sprintf(port_str, "%d", port_no);
if ((status = getaddrinfo(hostname, port_str, &hints, &res)) == -1) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(EXIT_FAILURE);
}
int socket_fd = 0;
for (p = res; p != NULL; p = p->ai_next) {
if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
}
if (socket_fd == 0) {
errno = ENOTSOCK;
perror("no socket");
exit(EXIT_FAILURE);
}
return socket_fd;
}
You cannot connect(), then listen() on the same socket. Lose the connect().

C lang, Multi-Client Server, error: Socket operation on non-socket

I've got an assignment to write a server program that accepts multiple clients. I'm writing in C language and trying to accomplish this using a select() statement. I am able to compile, but whenever I telnet in, I get a "Socket operation on non-socket error." I've tried researching the error, but can't find anything too helpful. Any assistance would be appreciated.
The output of my server is:
$ ./assign2 33333
Waiting for connection...
fd is 0
EchoServ recv error: Socket operation on non-socket
fd is 1
EchoServ recv error: Socket operation on non-socket
EchoServ recv error: Socket operation on non-socket
The output of telnet is:
$ telnet localhost 33333
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
Welcome to EchoServ chat.
My server code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define PORT 50000
main( int argc, char *argv[] )
{
char buf[ BUFSIZ ], /* buffer for incoming data */
*endptr, /* for strtol() */
*message = "Welcome to EchoServ chat. \r\n"; /* welcome message */
int masterSocket, /* main listening socket for server */
newSocket, /* new sockets for connecting clients */
opt = 1, /* for port reuse code */
nBytes, /* # of incoming bytes */
addrlen;
int i,j; /* temp vars */
short int port; /* port number */
fd_set master; /* master file descriptor list */
fd_set temp_fds; /* temp file descriptor list for select() */
int fdmax; /* maximum file descriptor number */
struct sockaddr_in sin;
/* Get port number from the command line, or
set to default port if no arguments were supplied */
if ( argc == 2 ) {
port = strtol(argv[1], &endptr, 0);
if ( *endptr ) {
fprintf(stderr, "EchoServ: Invalid port number.\n");
exit(EXIT_FAILURE);
}
}
else {
port = PORT;
}
FD_ZERO(&master); /* clear the master and temp sets */
FD_ZERO(&temp_fds);
/* Get an internet domain socket */
if ( ( masterSocket = socket( AF_INET, SOCK_STREAM, 0) ) == -1 ) {
perror( "EchoServ socket error" );
exit( 1 );
}
/* Complete the socket structure */
memset( &sin, 0, sizeof(sin) );
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
/* Bind the socket to the port number */
if ( bind( masterSocket, ( struct sockaddr *) &sin, sizeof( sin ) ) == -1) {
perror( "EchoServ bind failed" );
exit( 1 );
}
/* Allow port reuse */
if ( setsockopt( masterSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) ) == -1 ) {
perror( "EchoServ setsockopt error" );
exit(1);
}
/* Listen for clients that want to connect. */
if ( listen( masterSocket, 5 ) == -1 ) {
perror( "EchoServ listen error" );
exit( 1 );
}
/* add masterSocket to the master set */
FD_SET(masterSocket, &master);
/* track largest file descriptor, starting with masterSocket */
fdmax = masterSocket;
/* Wait for a client connection, then accept it. */
puts ( "Waiting for connection..." );
while(1){
temp_fds = master; /* copy master set to temp set */
//addrlen = sizeof(sin);
/* wait for activity on a socket */
if (select(fdmax+1, &temp_fds, NULL, NULL, NULL) == -1) {
perror("EchoServ select error");
exit(1);
}
for ( i = 0; i <= fdmax; i++ ){
printf("fd is %d\n", i); /*debug*/
if ( FD_ISSET( i, &temp_fds ) ){ /* true if file descriptor is in set */
/* accept new connection */
if ( i == masterSocket ){
addrlen = sizeof( sin );
if ( (newSocket = accept( masterSocket, ( struct sockaddr *) &sin, &addrlen )) == -1 )
perror("EchoServ: accept error");
else {
printf("New connection accepted\n"); /*debug*/
FD_SET( newSocket, &master ); /* add new connection to master set */
if ( newSocket > fdmax ) /* update max descriptor */
fdmax = newSocket;
//print details of new connection
printf("New connection on %s:%d, socket fd is %d \n",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), newSocket );
//send new connection greeting message
if( send( newSocket, message, strlen( message ), 0) == -1 )
{
perror("EchoServ welcome message error");
}
puts("Welcome message sent successfully");
}
}
}
/* handle incoming data */
else{
if ( ( nBytes = recv( i, buf, sizeof( buf ), 0 ) ) <= 0 ){ /* error or closed connection */
if ( nBytes == 0 ) /* connection closed */
printf( "EchoServ: socket %d closed by client\n", i );
else /* recv error */
perror("EchoServ recv error");
close( i ); /* close socket */
FD_CLR( i, &master ); /* remove from master set */
}
else { /* got some data */
for( j = 0; j <= fdmax; j++ ){
if ( FD_ISSET( j, &master ) ){ /* send data to all sockets */
if( j != i && j != masterSocket ){ /* except self and masterSocket */
if ( send( j, buf, nBytes, 0) == -1)
perror("EchoServ send error");
}
}
}
}
}
}
}
return( 0 );
}
Thanks for helping.
So you test if (FD_ISSET(i, &temp_fds)) and on the else branch you attempt to recv on i. So basically you're only trying to receive if i is invalid or would block.
This all of course stems from the unbounded use of blocks and braces. You probably meant that else to be paired with if (i == masterSocket).

gethostbyname, connecting to the internet at large?

I'm writing a basic proxy server in C for class.
I'm testing with firefox, and I've got the server successfully receiving the browser's requests.
But now I need to send them out to the internet to get the pages the browser wants, and I'm hesitant.
Here is my present code for connecting.
I'm not sure if port 8080 is correct, and I'm not sure what to put for "gethostbyname".
That's the portion I was hoping to get some advice on.
int sock = socket( PF_INET, SOCK_STREAM, 0 );
if ( sock < 0 )
{
perror( "socket() failed" );
return EXIT_FAILURE;
}
struct sockaddr_in server;
struct hostent * hp;
server.sin_family = PF_INET;
hp = gethostbyname( "localhost" );
if ( hp == NULL )
{
perror( "Unknown host" );
return EXIT_FAILURE;
}
bcopy( (char *)hp->h_addr, (char *)&server.sin_addr, hp->h_length );
int port = 8080;
server.sin_port = htons( port );
if ( connect( sock, (struct sockaddr *)&server, sizeof( server ) ) < 0 )
{
perror( "connect() failed" );
return EXIT_FAILURE;
}
That entire gethostbyname, copying around (ha - even with the overly old bcopy)... just use getaddrinfo (extensive error checking left out for brevity):
int ret = getaddrinfo("localhost", "80" /* (or 8080, whichever applies) */, NULL, &res);
if (ret == 0) {
const struct addrinfo *r;
for (r = res; r != NULL || ret != 0; r = r->ai_next)
ret = connect(fd, res->ai_addr, res->ai_addrlen);
}
freeaddrinfo(res);

Error receiving in UDP: Connection refused

I am trying to send a string HI to a server over UDP in a particular port and then to receive a response. However, after I try to get the response using recvfrom() I was stuck in blocking state. I tried using connected UDP but I got:
Error receiving in UDP: Connection refused
What could be the reasons for this? The server is not under my control, but I do know its working fine.
I have added the code
int sockfdudp;
char bufudp[MAXDATASIZE], port[6];
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage addr;
int rv;
char s[INET6_ADDRSTRLEN];
int bytes_recv, bytes_sent;
socklen_t len;
scanf("%s",port);
printf("UDP Port: %s \n", port);
// Start connecting to datagram server
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(SERVER_NAME, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfdudp = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("Creating datagram socket");
continue;
}
if (connect(sockfdudp, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfdudp);
perror("Connecting stream socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "ClientUDP: failed to bind socket\n");
return 2;
}
freeaddrinfo(servinfo);
if ((bytes_sent = sendto(sockfdudp, UDP_MSG, strlen(UDP_MSG), 0, p->ai_addr, p->ai_addrlen)) == -1) {
perror("ClientUDP: Error sending data");
exit(1);
}
printf("Data %s sent\n", UDP_MSG );
len = sizeof(struct sockaddr_storage);
if ((bytes_recv = recvfrom(sockfdudp, bufudp, MAXDATASIZE-1, 0,(struct sockaddr*)&addr, &len)) == -1) {
perror("Error receiving in UDP");
exit(1);
}
printf("Bytes recv %d\n", bytes_recv);
bufudp[bytes_recv] = '\0';
printf("ClientUDP: Received\n %s \n",bufudp );
close(sockfdudp);
return 0;
Chances are your're sending something to a server who does not listen on that particular port.
That would cause an icmp message to be sent back , and your next recvfrom will return an error in the case where you connect the socket.
Check with tcpdump or wireshark what's going on on the wire.
My guess would be that your ip address is bad somehow, or the port is already in use somehow. UDP is connectionless, so there really isn't any "connection" to fail.

Resources