(C++) EINVAL error when initializing MOCAP node - c++

I am trying to configure my MOCAP node (virtual machine) IP address to match that of MOTIVE software on my PC. The MOCAP.yaml file is intially set to 224.0.0.1 but every time I change it to match the IP address of my machine it cause an EINVAL error like this:
terminate called after throwing an instance of 'SocketException'
what(): Failed to set socket option: EINVAL
=========================================================================
REQUIRED process [mocap_node-1] has died!
process has died [pid 4575, exit code -6, cmd /home/radlab/mocap/devel/lib/mocap_optitrack/mocap_node __name:=mocap_node __log:=/home/radlab/.ros/log/3fe16008-4521-11e6-9638-080027e2597b/mocap_node-1.log].
log file: /home/radlab/.ros/log/3fe16008-4521-11e6-9638-080027e2597b/mocap_node-1*.log
Initiating shutdown!
=========================================================================
Here is the code for the socket.cpp
/*
* Socket.cpp
*
* Created on: 14.11.2008
* Author:
*/
// Implementation of the Socket class.
#include "mocap_optitrack/socket.h"
#include <cstring>
#include <cerrno>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <sstream>
#include <ros/ros.h>
UdpMulticastSocket::UdpMulticastSocket( const int local_port, const std::string multicast_ip )
{
// Create a UDP socket
ROS_INFO( "Creating socket..." );
m_socket = socket( AF_INET, SOCK_DGRAM, 0 );
if( m_socket < 0 )
throw SocketException( strerror( errno ) );
// Allow reuse of local addresses
ROS_INFO( "Setting socket options..." );
int option_value = 1;
int result = setsockopt( m_socket, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value, sizeof( int ) );
if( result == -1 )
{
std::stringstream error;
error << "Failed to set socket option: ";
switch( errno )
{
case EBADF:
error << "EBADF";
break;
case EFAULT:
error << "EFAULT";
break;
case EINVAL:
error << "EINVAL";
break;
case ENOPROTOOPT:
error << "ENOPROTOOPT";
break;
case ENOTSOCK:
error << "ENOTSOCK";
break;
default:
error << "unknown error";
break;
}
throw SocketException( error.str().c_str() );
}
// Fill struct for local address
memset ( &m_local_addr, 0, sizeof ( m_local_addr ) );
m_local_addr.sin_family = AF_INET;
m_local_addr.sin_addr.s_addr = htonl( INADDR_ANY );
m_local_addr.sin_port = htons( local_port );
ROS_INFO( "Local address: %s:%i", inet_ntoa( m_local_addr.sin_addr ), ntohs( m_local_addr.sin_port ) );
// Bind the socket
ROS_INFO( "Binding socket to local address..." );
result = bind( m_socket, (sockaddr*)&m_local_addr, sizeof( m_local_addr ));
if( result == -1 )
{
std::stringstream error;
error << "Failed to bind socket to local address:" << strerror( errno );
throw SocketException( error.str().c_str() );
}
// Join multicast group
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr( multicast_ip.c_str() );
mreq.imr_interface = m_local_addr.sin_addr;
ROS_INFO( "Joining multicast group %s...", inet_ntoa( mreq.imr_multiaddr ) );
result = setsockopt(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
if( result == -1 )
{
std::stringstream error;
error << "Failed to set socket option: ";
switch( errno )
{
case EBADF:
error << "EBADF";
break;
case EFAULT:
error << "EFAULT";
break;
case EINVAL:
error << "EINVAL";
break;
case ENOPROTOOPT:
error << "ENOPROTOOPT";
break;
case ENOTSOCK:
error << "ENOTSOCK";
break;
default:
error << "unknown error";
break;
}
throw SocketException( error.str().c_str() );
}
// Make socket non-blocking
ROS_INFO( "Enabling non-blocking I/O" );
int flags = fcntl( m_socket, F_GETFL , 0 );
result = fcntl(m_socket, F_SETFL, flags | O_NONBLOCK);
if( result == -1 )
{
std::stringstream error;
error << "Failed to enable non-blocking I/O: " << strerror( errno );
throw SocketException( error.str().c_str() );
}
}
UdpMulticastSocket::~UdpMulticastSocket()
{
close( m_socket );
}
int UdpMulticastSocket::recv()
{
memset ( buf, 0, MAXRECV + 1 );
sockaddr_in remote_addr;
int addr_len = sizeof(struct sockaddr);
int status = recvfrom(
m_socket,
buf,
MAXRECV,
0,
(sockaddr *)&remote_addr,
(socklen_t*)&addr_len);
if( status > 0 )
ROS_DEBUG( "%4i bytes received from %s:%i", status, inet_ntoa( remote_addr.sin_addr ), ntohs( remote_addr.sin_port ) );
else if( status == 0 )
ROS_INFO( "Connection closed by peer" );
return status;
}
Can anyone help me figure out why I am getting this error when I change the IP address?

I don't know what mocap or motiv is, but I think you're trying to use a non-multicast ip-address to join to multicast group in line 79. That's propably what's passed to the function with std::string multicast_ip from the .yaml file.
See man page:
IP_ADD_MEMBERSHIP (since Linux 1.2)
Join a multicast group. Argument is an ip_mreqn structure.
struct ip_mreqn {
struct in_addr imr_multiaddr; /* IP multicast group
address */
struct in_addr imr_address; /* IP address of local
interface */
int imr_ifindex; /* interface index */
};
imr_multiaddr contains the address of the multicast group the
application wants to join or leave. It must be a valid
multicast address (or setsockopt(2) fails with the error
EINVAL). imr_address is the address of the local interface
with which the system should join the multicast group; if it
is equal to INADDR_ANY, an appropriate interface is chosen by
the system. imr_ifindex is the interface index of the
interface that should join/leave the imr_multiaddr group, or 0
to indicate any interface.
The ip_mreqn structure is available only since Linux 2.2. For
compatibility, the old ip_mreq structure (present since Linux
1.2) is still supported; it differs from ip_mreqn only by not
including the imr_ifindex field. (The kernel determines which
structure is being passed based on the size passed in optlen.)
IP_ADD_MEMBERSHIP is valid only for setsockopt(2).

Related

winsock "invalid argument" error on listen

I was trying to make a simple client - server communication application, but I've come across a problem - I get error 10022 ( invalid argument ) on listen.
WSADATA wsaData;
int iResult;
sockaddr_in addr;
SOCKET sock, client;
addr.sin_family = AF_INET;
addr.sin_port = htons( 25565 );
addr.sin_addr.S_un.S_addr = inet_addr( "127.0.0.1" );
iResult = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
if( iResult )
{
std::cout << ( WSAGetLastError( ) );
_getch( );
}
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( sock == INVALID_SOCKET )
{
std::cout << ( WSAGetLastError( ) );
_getch( );
}
iResult = listen( sock, SOMAXCONN );
if( iResult )
{
std::cout << ( WSAGetLastError( ) );
_getch( );
}
Before you listen, you need to bind the socket to the port that will be listened on.
It looks like you have already built the address structure containing the information necessary to bind, so call bind(sock, &addr, sizeof(addr)) and perform appropriate error checking before the call to listen.
Documentation for bind
The answer is in the listen() documentation:
WSAEINVAL
The socket has not been bound with bind.
You need to bind() the socket before you can listen() on it.

select() returns -1 while reading from socket

I'm trying to solve reading from socket timeout problem using select(). Unfortunately this function returns -1 immediatly after getting called. What might be wrong?
commStatus communicate( const char * tx, char * rx, const int bufSize , const char * inetAddr, const int port )
{
commStatus r;
if (!sockInitialised) initSock();
if (sockInitialised)
{
SOCKET s;
struct sockaddr_in server;
server.sin_addr.s_addr = inet_addr(inetAddr);
server.sin_family = AF_INET;
server.sin_port = htons( port );
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
std:stringstream d; d <<"Could not create socket : " << WSAGetLastError();
LogIt(d,Level::Error);
} else
{
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
r= commStatus::COMM_NO_TRANSMIT ;
} else
{
int l =strlen(tx)+strlen("DATA ");
char* dtx ;
dtx = (char*) calloc(sizeof(char),strlen(tx)+strlen("DATA ") + 1 );
sprintf(dtx,"DATA %s",tx);
if( send(s , dtx , strlen(dtx) , 0) < 0)
{
puts("Send failed");
r= commStatus::COMM_NO_TRANSMIT;
} else
{
int recv_size = 0;
struct timeval selTimeout;
selTimeout.tv_sec = 20; /* timeout (secs.) */
selTimeout.tv_usec = 0; /* 0 microseconds */
fd_set readSet;
FD_ZERO(&readSet);
#define STDIN_FILENO 0
FD_SET(STDIN_FILENO, &readSet);//stdin manually trigger reading
FD_SET(s, &readSet);//tcp socket
int numReady = select(s+1, &readSet, NULL, NULL, &selTimeout);
if(numReady > 0)
{
if((recv_size = recv(s , rx , bufSize ,0)) == SOCKET_ERROR)
{
r= commStatus::COMM_NO_RECEIVE;
} else
{
rx[recv_size] = '\0';
r= commStatus::COMM_OK;
}
} else r=commStatus::COMM_NO_RECEIVE;
}
free(dtx);
}
}
} else r= commStatus::COMM_NO_TRANSMIT;
return r;
}
As far as I can tell, you're trying to pass stdin to Winsock's select() function.
Unfortunately, under Windows, select() only takes socket handles, not generic file descriptors.
If you were to call WSAGetLastError(), you'd probably see that it returns WSAENOTSOCK.
Under C, you can examine the errno variable, it should tell you the specific problem that caused your error.
Alternatively, you may have the perror() function which will give you a readable version:
#include <stdio.h>
:
perror ("select");
If you're under Windows, WSAGetLastError() will serve as the errno variable, with this page giving the possibilities and explanations:
WSANOTINITIALISED - A successful WSAStartup call must occur before using this function.
WSAEFAULT - The Windows Sockets implementation was unable to allocate needed resources for its internal operations, or the readfds, writefds, exceptfds, or timeval parameters are not part of the user address space.
WSAENETDOWN - The network subsystem has failed.
WSAEINVAL - The time-out value is not valid, or all three descriptor parameters were null.
WSAEINTR - A blocking Windows Socket 1.1 call was canceled through WSACancelBlockingCall.
WSAEINPROGRESS - A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.
WSAENOTSOCK - One of the descriptor sets contains an entry that is not a socket.

How to have two multicast sockets listen to two multicast channels with same port

I have broadly the following multicast socket code. It works fine. Now I need to join two multicast channels on the same machine like
224.10.13.18 - 55001
224.10.13.34 - 55001
and depending on which ip address it came from, I need to treat the message differently.
The question is to how to use create two sockets for multicast channels where the port values are same, such that each socket only returns read on data that is sent to that channel.
/* create socket to join multicast group on */
socket_file_descriptor_ = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( socket_file_descriptor_ < 0 )
{ // fprintf ( stderr, "cannot open socket \n");
exit(1);
}
/* set reuse port to on to allow multiple binds per host */
{
int flag_on = 1;
if ( ( setsockopt ( socket_file_descriptor_, SOL_SOCKET, SO_REUSEADDR, &flag_on,
sizeof(flag_on) ) ) < 0 )
{ // fprintf ( stderr, "MulticastReceiverSocket setsockopt() SOL_SOCKET SO_REUSEADDR failed\n");
exit(1);
}
}
struct ip_mreq mc_req;
inet_pton ( AF_INET, listen_ip_.c_str(), &(mc_req.imr_multiaddr.s_addr) );
mc_req.imr_interface.s_addr = htonl(INADDR_ANY);
/* send an ADD MEMBERSHIP message via setsockopt */
if ( ( setsockopt ( socket_file_descriptor_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(void*) &mc_req, sizeof(mc_req))) < 0)
{ // std::cerr << "setsockopt() failed in IP_ADD_MEMBERSHIP " << listen_ip_ << ": "<< listen_port_ << std::endl;
exit(1);
}
/* construct a multicast address structure */
struct sockaddr_in mcast_Addr;
bzero ( &mcast_Addr, sizeof(mcast_Addr) );
mcast_Addr.sin_family = AF_INET;
mcast_Addr.sin_addr.s_addr = htonl(INADDR_ANY);
mcast_Addr.sin_port = htons ( listen_port_ );
/* bind to specified port onany interface */
if ( bind ( socket_file_descriptor_, (struct sockaddr *) &mcast_Addr, sizeof ( struct sockaddr_in ) ) < 0 )
{ // fprintf ( stderr, "%s cannot bind %s:%d \n", "MulticastReceiverSocket", listen_ip_.c_str(), listen_port_ ) ;
exit(1);
}
You only need one socket for this. If you set the IP_PKTINFO option on a call to setsockopt, you can use recvmsg to get a struct in_pktinfo, which will contain the destination IP address. Then you can choose how to process the packet based on that.
Borrowing from https://stackoverflow.com/a/5309155/1687119 (error checking removed for brevity):
// sock is bound AF_INET socket, usually SOCK_DGRAM
// include struct in_pktinfo in the message "ancilliary" control data
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));
// the control data is dumped here
char cmbuf[0x100];
// the remote/source sockaddr is put here
struct sockaddr_in peeraddr;
// if you want access to the data you need to init the msg_iovec fields
struct msghdr mh = {
.msg_name = &peeraddr,
.msg_namelen = sizeof(peeraddr),
.msg_control = cmbuf,
.msg_controllen = sizeof(cmbuf),
};
recvmsg(sock, &mh, 0);
for ( // iterate through all the control headers
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
cmsg != NULL;
cmsg = CMSG_NXTHDR(&mh, cmsg))
{
// ignore the control headers that don't match what we want
if (cmsg->cmsg_level != IPPROTO_IP ||
cmsg->cmsg_type != IP_PKTINFO)
{
continue;
}
struct in_pktinfo *pi = CMSG_DATA(cmsg);
// at this point, peeraddr is the source sockaddr
// pi->ipi_spec_dst is the destination in_addr
// pi->ipi_addr is the receiving interface in_addr
}

Server/Client TCP asynchronous (winsock) // FD_WRITE issue

I need your help because I have to make two console application in C++ : a client able to send as many string as possible to a server (in order to send coordinates). I succeeded to make a blocking socket but as I have to integrate it after in a development platform (3D VIA Virtools) which call my script at each frame, I have no other solution than using asynchronous sockets.
*My problem is that I can only send string once, and after I don't receive FD_WRITE anymore...*
This begin to drive me crazy so any help will be highly appreciated (I'm a beginner in programming), thanks in advance to everyone who will feel a little bit concerned by my problem
Here is my code,
Server
#include <winsock2.h>
#include <Windows.h>
#include <conio.h>
#pragma comment(lib, "ws2_32.lib")
#define SOCKET_ERRNO WSAGetLastError()
#define ADDRESS "127.0.0.1"
#define PORT 1234
static SOCKET ListenFirstFreePort()
{
struct sockaddr_in addr;
int len = sizeof(addr);
SOCKET hSocket;
// Create socket
hSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( hSocket == INVALID_SOCKET )
{
printf( "socket() error %d\n", SOCKET_ERRNO );
exit(1);
}
// Connexion setting for local connexion
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = inet_addr(ADDRESS);
addr.sin_port = htons (PORT);
// bind socket
if ( bind( hSocket, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR )
{
printf( "bind() error %d\n", SOCKET_ERRNO );
exit(1);
}
// listen
if ( listen( hSocket, 100) == SOCKET_ERROR )
{
printf( "listen() error %d\n", SOCKET_ERRNO );
exit(1);
}
return hSocket;
}
void main()
{
WSADATA stack_info;
SOCKET ahSocket[2];
WSAEVENT ahEvents[2];
DWORD dwEvent;
WSANETWORKEVENTS NetworkEvents;
int rc;
// Initialize Winsock
WSAStartup(MAKEWORD(2,0), &stack_info) ;
// Create events
ahEvents[0] = WSACreateEvent();
ahEvents[1] = WSACreateEvent();
// Create listening socket
ahSocket[0] = ListenFirstFreePort();
rc = WSAEventSelect(ahSocket[0], ahEvents[0], FD_ACCEPT );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
while (TRUE)
{
// Waiting for so;ething to happen
// Basically we'll firstly receive the connexion of the client socket
// and then we'll be notificated when there will be some data to read
// look for events
dwEvent = WSAWaitForMultipleEvents( 2, ahEvents, FALSE, WSA_INFINITE, FALSE);
switch (dwEvent)
{
case WSA_WAIT_FAILED:
printf("WSAEventSelect: %d\n", WSAGetLastError());
break;
case WAIT_IO_COMPLETION:
case WSA_WAIT_TIMEOUT:
break;
default:
//if there is one dwEvent-WSA_WAIT_EVENT_0 has to be substracted so as to dwEvent correspond to the index of the concerned socket
dwEvent -= WSA_WAIT_EVENT_0;
// enumeration of the events on the socket[dwEvent]
if (SOCKET_ERROR == WSAEnumNetworkEvents(ahSocket[dwEvent], ahEvents[dwEvent], &NetworkEvents))
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n",
WSAGetLastError(), NetworkEvents.lNetworkEvents);
NetworkEvents.lNetworkEvents = 0;
}
else
{
if (FD_CLOSE & NetworkEvents.lNetworkEvents)
{
printf( "FD_CLOSE ok (dwEvent=%d)\n", dwEvent );
printf( "press a key to exit\n" );
getch(); // require conio.h
WSACloseEvent( ahEvents[0] );
WSACloseEvent( ahEvents[1] );
exit(0);
}
if (FD_READ & NetworkEvents.lNetworkEvents)
{
char szBuffer[256]; int cbRecv;
// Only the second socket expect to receive data
printf( "FD_READ ok (dwEvent=%d)\n", dwEvent );
// read data
cbRecv = recv( ahSocket[dwEvent], szBuffer, sizeof(szBuffer) - 1, 0 );
if( cbRecv <= 0 )
{
printf( "recv() error %d\n", SOCKET_ERRNO );
exit(1);
}
// On ecrit ce paquet (On remet le 0 au cas ou le paquet
// ait ete coupe en 2 - je sais, ca n'arrivera jamais en local)
// we put the 0 in case it has been cut - unlikey to happen on local network
szBuffer[cbRecv] = 0;
// write data in console window
printf( "socket %d : '%s'\n", dwEvent, szBuffer );
}
}
if (FD_ACCEPT & NetworkEvents.lNetworkEvents)
{
struct sockaddr_in addrAccept;
int lenAccept;
lenAccept = sizeof( addrAccept );
// we should have dwEvent=0
printf( "accept ok (dwEvent=%d)\n", dwEvent );
// we create another socket to accept the connexion with the client socket
ahSocket[1] = accept(ahSocket[dwEvent], (struct sockaddr *)&addrAccept, &lenAccept);
// we want to be informed on when we'll be able read data from it
rc = WSAEventSelect(ahSocket[1], ahEvents[1], FD_READ|FD_CLOSE );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
}
}
}
Client
#include <winsock2.h>
#include <conio.h>
#include <time.h>
#pragma comment(lib, "ws2_32.lib")
#define SOCKET_ERRNO WSAGetLastError()
#define ADDRESS "127.0.0.1"
#define PORT 1234
SOCKET ConnectToPort()
{
struct sockaddr_in addr;
SOCKET hSocket;
u_long arg; int err;
// Create socket
hSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( hSocket == INVALID_SOCKET )
{
printf( "socket() error %d\n", SOCKET_ERRNO );
exit(1);
}
// Connexion setting for local connexion
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = inet_addr(ADDRESS);
addr.sin_port = htons (PORT);
// Connect
if( connect( hSocket, (struct sockaddr *)&addr, sizeof(addr) ) == SOCKET_ERROR )
{
// As we are in non-blocking mode we'll always have the error
// WSAEWOULDBLOCK whichis actually not one
if( SOCKET_ERRNO != WSAEWOULDBLOCK )
{
printf( "connect() error (%d)\n", SOCKET_ERRNO );
exit(1);
}
}
return hSocket;
}
void main()
{
int initClockTime;
WSADATA stack_info;
SOCKET ahSocket[1];
WSAEVENT ahEvents[1];
DWORD dwEvent;
WSANETWORKEVENTS NetworkEvents;
int rc;
// Initialize Winsock
WSAStartup(MAKEWORD(2,0), &stack_info) ;
// Create event
ahEvents[0] = WSACreateEvent();
// Create and connect a socket on the server socket
ahSocket[0]= ConnectToPort();
// not sure if I have to use or not
/*u_long arg = 1;
ioctlsocket( ahSocket[0] , FIONBIO, &arg );*/
// the application wants to receive notification of a completed connection
rc = WSAEventSelect(ahSocket[0], ahEvents[0], FD_CONNECT );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
while (TRUE)
{
// look for events
dwEvent = WSAWaitForMultipleEvents( 1, ahEvents, FALSE, 1000, FALSE);
switch (dwEvent)
{
case WSA_WAIT_FAILED:
printf("WSAEventSelect: %d\n", WSAGetLastError());
break;
case WAIT_IO_COMPLETION:
case WSA_WAIT_TIMEOUT:
break;
default:
printf("while\n");
//if there is one dwEvent-WSA_WAIT_EVENT_0 has to be substracted so as to dwEvent correspond to the index of the concerned socket
dwEvent -= WSA_WAIT_EVENT_0;
// enumeration of the events on the socket[dwEvent]
if (SOCKET_ERROR == WSAEnumNetworkEvents(ahSocket[dwEvent], ahEvents[dwEvent], &NetworkEvents))
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n", WSAGetLastError(), NetworkEvents.lNetworkEvents);
NetworkEvents.lNetworkEvents = 0;
}
else
{
if (FD_CONNECT & NetworkEvents.lNetworkEvents)
{
//connexion is OK
printf( "FD_CONNECT ok (dwEvent=%d)\n", dwEvent );
// now that we are connected we want to send data or be aware when the other socket is disconnected
rc = WSAEventSelect(ahSocket[dwEvent], ahEvents[dwEvent], FD_CLOSE | FD_WRITE );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
if (FD_CLOSE & NetworkEvents.lNetworkEvents)
{
printf( "FD_CLOSE ok (dwEvent=%d)\n", dwEvent );
printf( "press a key to exit\n" );
getch();
WSACloseEvent( ahEvents[0] );
exit(0);
}
if (FD_WRITE & NetworkEvents.lNetworkEvents)
{
char szBuffer[256]; int cbBuffer;
printf( "FD_WRITE ok (dwEvent=%d)\n", dwEvent );
// create string and return the size
cbBuffer = sprintf( szBuffer, "Coucou", dwEvent );
// send the string with 0 at the end
rc = send( ahSocket[dwEvent], szBuffer, cbBuffer + 1, 0 );
if (SOCKET_ERROR == rc)
{
printf("WSAEnumNetworkEvent: %d lNetworkEvent %X\n", WSAGetLastError(), NetworkEvents.lNetworkEvents);
}
// not sure if I have to use it
//WSAResetEvent(ahEvents[0]);
}
}
}
}
}
download .cpp files : https://www.dropbox.com/s/pjuipz7v4iwr5ea/Clientserver%20TCP.zip
You are not getting FD_WRITE notifications after the first one because you are not taking into account the following paragraph from the documentation:
The FD_WRITE network event is handled slightly differently. An
FD_WRITE network event is recorded when a socket is first connected
with a call to the connect, ConnectEx, WSAConnect, WSAConnectByList,
or WSAConnectByName function or when a socket is accepted with accept,
AcceptEx, or WSAAccept function and then after a send fails with
WSAEWOULDBLOCK and buffer space becomes available. Therefore, an
application can assume that sends are possible starting from the first
FD_WRITE network event setting and lasting until a send returns
WSAEWOULDBLOCK. After such a failure the application will find out
that sends are again possible when an FD_WRITE network event is
recorded and the associated event object is set.
After your first call to send(), the socket is still writable since its outbound buffer is not full. As long as you still have data to send, keep calling send() until it reports an WSAWOULDBLOCK error indicating the buffer is full. At that point, you have to keep track of your remaining data until you get an FD_WRITE notification indicating the socket is writable again so you can continue sending your remaining data from where you left off.
I would recommend to look at regular select() for non-blocking I/O first. Here's couple of links for you to get started:
Non-blocking I/O and select() (the link is broken)
Non-Blocking Sockets in TCP/IP

Listening for IPv6 multicasts on Linux

I'm trying to get a simple multicasting example to work on Linux (I've
tried both RHEL 4 2.6.9 and Ubuntu 8.04 2.6.24). The general idea is
that I would like the server to bind to a unicast address and then add
itself to the group ff02::1. I would then like it to receive
multicasts sent to ff02::1. The code below works on Mac OS X 10.5 (in
fact, a server running on OS X gets multicasts sent from Linux
clients), but I can't get the Linux server side to work. It doesn't
get any multicasts. If I change the code to bind to :: (INADDR6_ANY)
rather than a unicast address (I've tried both link-local and global
addresses), it does get the multicasts. I was wondering if someone
could point out what I'm doing wrong.
server:
memset( &hint, 0, sizeof( hint ) );
hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_DGRAM;
// argv[1] is either a link-local or a global address
err = getaddrinfo( argv[1], NULL, &hint, &info );
if( err != 0 ) {
perror( "getaddrinfo" );
exit( 1 );
}
struct sockaddr_in6 * addr = (struct sockaddr_in6*)info->ai_addr;
//addr->sin6_addr = in6addr_any; // if this is uncommented, multicasts are received
addr->sin6_port = htons( 7890 );
s = socket( AF_INET6, SOCK_DGRAM, 0 );
if( bind( s, (struct sockaddr*) addr, info->ai_addrlen ) != 0 ) {
close( s );
perror( "bind" );
exit( 1 );
}
if( getaddrinfo( "ff02::1", NULL, &hint, &multi ) != 0 ) {
close( s );
perror( "getaddrinfo" );
exit( 1 );
}
struct ipv6_mreq mreq;
memset( &mreq, 0, sizeof(mreq) );
memcpy( &mreq.ipv6mr_multiaddr, &((struct sockaddr_in6 *) multi->ai_addr)->sin6_addr, sizeof(mreq.ipv6mr_multiaddr) );
mreq.ipv6mr_interface = 2; // 2 happens to be the interface ID; I've tried other values here
freeaddrinfo( multi );
if( setsockopt( s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq) ) != 0 ) {
close( s );
perror( "IPV6_JOIN_GROUP" );
exit( 1 );
}
for( ; ; ) {
char data[6];
size_t len;
len = recvfrom( s, data, 5, 0, NULL, NULL );
data[5] = '\0';
printf( "Received %s\n", data );
if( strcmp( data, "exitt" ) == 0 ) {
break;
}
}
The client code is as follows:
memset( &hint, 0, sizeof( hint ) );
hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = 0;
err = getaddrinfo( "ff02::1", NULL, &hint, &info );
if( err != 0 ) {
perror( "getaddrinfo" );
return 0;
}
struct sockaddr_in6 * addr = (struct sockaddr_in6*)info->ai_addr;
addr->sin6_port = htons( 7890 );
addr->sin6_scope_id = 2; // 2 happens to be the interface ID
s = socket( AF_INET6, SOCK_DGRAM, 0 );
for( ; ; ) {
char data[6];
size_t len;
scanf( "%5s", data );
data[5] = '\0';
printf( "Sending %s\n", data );
if( sendto( s, data, 5, 0, info->ai_addr, info->ai_addrlen ) != 5 ) {
printf( "Error sending\n" );
}
if( strcmp( data, "exitt" ) == 0 ) {
break;
}
}
close( s );
Binding filters incoming addresses, so if you bind to an adapter address you only get packets with matching destination address: i.e. unicast packets, if you bind to a multicast address you will only get multicast packets; to get multicast and unicast packets you must bind to INADDR_ANY or IN6ADDR_ANY.