Gerald Jacobson
Registered
Here an example of code used to listen for UDP trame. As C language is not my programming language my code can be far from best.
This code works in 32bit and 64bit (Use VC++ 2012 express - much easier to build DLL for 32bits and 64bits than VC++ 2010)
Notes:
- This example take the ISI example plugin as code base
- In C when a variable is declared, it is not initialized with classical values (so if you do not explicitly set a variable default value in the constructor, a new created variable will have a random value) -> Main source of issue for JAVA, C#, ... developpers
- This example use Naming Resolution (to covnert a DNS name into an IP address), and as "gethostbyname" is obsolete, i need to use "getaddrinfo" instead. This method needs to include <WinSock2.h>. But as this version contains structure also declared in the <windows.h> include, you need to specify #include <WinSock2.h> before #include <windows.h>
- This example also use WINAPI to read ini files.
Here we go:
- in the Example.hpp add some variables
Now in the constructor, initialize the variables that need to have defined init values
Now in the Example.cpp, add the includes for socket. The #include <WinSock2.h> must be inserted before the #include "Example.hpp"
The include part looks like:
As i use INI file to configure the plugin and i want the ini file are stored in the <rF2Data>/UserData/<profile> directory and not in the <rF2Code>/plugins directory. To achieve that from inside the plugin, i use the rF2 SetEnvironment API method to retrieve profile path.
Now to send data throw UDP you can use this kind of code
This code works in 32bit and 64bit (Use VC++ 2012 express - much easier to build DLL for 32bits and 64bits than VC++ 2010)
Notes:
- This example take the ISI example plugin as code base
- In C when a variable is declared, it is not initialized with classical values (so if you do not explicitly set a variable default value in the constructor, a new created variable will have a random value) -> Main source of issue for JAVA, C#, ... developpers
- This example use Naming Resolution (to covnert a DNS name into an IP address), and as "gethostbyname" is obsolete, i need to use "getaddrinfo" instead. This method needs to include <WinSock2.h>. But as this version contains structure also declared in the <windows.h> include, you need to specify #include <WinSock2.h> before #include <windows.h>
- This example also use WINAPI to read ini files.
Here we go:
- in the Example.hpp add some variables
Code:
// socket variables
bool environmentAlreadySet;
int senderSocket; // socket to data
struct sockaddr_in sadSender;
char serverHostname[256];
u_short serverPort;
char identificationData[22];
Now in the constructor, initialize the variables that need to have defined init values
Code:
ExampleInternalsPlugin() {
environmentAlreadySet = false;
senderSocket = 0;
}
Now in the Example.cpp, add the includes for socket. The #include <WinSock2.h> must be inserted before the #include "Example.hpp"
The include part looks like:
Code:
// socket WinSock2.h must be included before <windows.h>
#include <WinSock2.h>
#include "Example.hpp" // corresponding header file
#include <math.h> // for atan2, sqrt
#include <stdio.h> // for sample output
#include <limits>
#include <string> // std::string
// socket
#include <ws2tcpip.h>
// thread
#include <process.h>
#pragma comment(lib, "Ws2_32.lib")
As i use INI file to configure the plugin and i want the ini file are stored in the <rF2Data>/UserData/<profile> directory and not in the <rF2Code>/plugins directory. To achieve that from inside the plugin, i use the rF2 SetEnvironment API method to retrieve profile path.
Code:
void ExampleInternalsPlugin::SetEnvironment( const EnvironmentInfoV01 &info ) {
// as the SetEnvironment can be called several times at launch
if (environmentAlreadySet) {
return;
}
// retrieve the ini filename (full path)
std::string str = info.mPath[1];
unsigned found = str.find_last_of("/\\");
str = str.substr(0,found);
str.append("\\ExampleInternalsPlugin.ini");
// read ini
serverPort = (u_short)GetPrivateProfileInt("Server", "Port", 666, str.c_str());
GetPrivateProfileString("Server", "Address", "localhost", serverHostname, 255, str.c_str());
senderSocket = socket(PF_INET, SOCK_DGRAM, 0);
if (senderSocket < 0) {
return;
}
//gethostbyname by getaddrinfo replacement
ADDRINFO hints = {sizeof(addrinfo)};
hints.ai_flags = AI_ALL;
hints.ai_family = PF_INET;
hints.ai_protocol = IPPROTO_IPV4;
ADDRINFO* pResult = NULL;
int errcode = getaddrinfo(serverHostname, NULL, &hints, &pResult);
//if(errcode != 0)
// return ERROR;
memset(&sadSender, 0, sizeof(sadSender));
sadSender.sin_family = AF_INET;
sadSender.sin_addr.S_un.S_addr = *((ULONG*)&(((sockaddr_in*)pResult->ai_addr)->sin_addr));
sadSender.sin_port = htons(serverPort);
environmentAlreadySet = true;
}
Now to send data throw UDP you can use this kind of code
Code:
// send a trame containing 12 bytes.
memcpy(&identificationData[0], &mSession, sizeof(long));
memcpy(&identificationData[4], &mCurrentET, sizeof(double));
sendto(senderSocket, identificationData, 12, 0, (struct sockaddr *) &sadSender, sizeof(struct sockaddr));
Last edited by a moderator: