Hi,
I am currently facing a strange Problem with UDP Sockets when launching on Android…
The code works perfectly fine on a Windows Devices but on Android it Returns the socket-error SE_EINVAL. Google says it stand for Invalid Address which shouldn’t be a problem, since i am binding to the Platforms AnyAddress…
I tested systematically all possible Socket options with each binding-call returning true but no luck on actually receiving data on these ports. ( Even though true means success the socketsubsystem always returned an error)
I tested it on two different devices (Asus Memo FH10 and a fairphone) both running Android 4.2.2.
The permissions are correct and i am able to open sockets with a little java app i wrote…
Here is my code which should be correct since i used the same methodes as the FUdpSocketBuilder…
void AUDPActor::BeginPlay() {
ISocketSubsystem* theSocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
theSocket = theSocketSubsystem->CreateSocket(NAME_DGram,TEXT("someDescrition"),true);
theSocket->SetNonBlocking();
theSocket->SetReuseAddr();
TSharedRef<FInternetAddr, ESPMode::NotThreadSafe> IAddr = theSocketSubsystem->CreateInternetAddr();
IAddr->SetAnyAddress();
IAddr->SetPort(22123);
bool bIsBound = theSocket->Bind(*IAddr);
GEngine->AddOnScreenDebugMessage(3, 10.0f, FColor::Red,FString::Printf(TEXT("Binding Result: %d, with %s"),(int32)bIsBound, theSocketSubsystem->GetSocketError()));
// returns Error SE_EINVAL (invalid Address) but successful bind
}
void AUDPActor::Tick(float DeltaTime) {
uint32 Size;
if (theSocket != nullptr) {
if (theSocket->HasPendingData(Size)) {
GEngine->AddOnScreenDebugMessage(4, 10.0f, FColor::Red, FString::Printf(TEXT("Received %u Bytes"),Size));
}
}
}
Thanks for your Help
i just wrote a workaround in plain c and it works… so there must be an error in the latest (4.4.3) codebase because i didn’t work from source but from install…
unfortunately I do not have any free time on my hands to locate the bug and commit on github…
here is my working code:
#if PLATFORM_ANDROID
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
void AUDPActor::BeginPlay() {
GEngine->AddOnScreenDebugMessage(1,5.0f,FColor::White, TEXT("HEEELLLLOOOO Android-Only Code!"));
SocketFront = socket(AF_INET,SOCK_DGRAM,0);
if (SocketFront < 0 ) {
GEngine->AddOnScreenDebugMessage(2,5.0f,FColor::Red,FString::Printf(TEXT("something went wrong: %s"),strerror(errno)));
}
struct sockaddr_in theAddress;
theAddress.sin_family = AF_INET;
theAddress.sin_port = htons(22123);
theAddress.sin_addr.s_addr = INADDR_ANY;
int flags = fcntl(SocketFront, F_GETFL);
flags |= O_NONBLOCK;
fcntl(SocketFront, F_SETFL, flags);
int32 isBound = bind(SocketFront,(struct sockaddr*)&theAddress,sizeof(theAddress));
if (isBound < 0 ) {
GEngine->AddOnScreenDebugMessage(2,5.0f,FColor::Red,FString::Printf(TEXT("something went wrong: %s"),strerror(errno)));
}
}
void AUDPActor::BeginDestroy() {
close(SocketFront);
}
void AUDPActor::Tick(float DeltaTime ) {
struct sockaddr_in SenderAddress;
int32 len;
int32 n = 0;
memset(buffer,0,1400);
len = sizeof(SenderAddress);
if (SocketFront >= 0){
n = recvfrom(SocketFront, buffer, 1400,0,(struct sockaddr*)&SenderAddress, &len);
if (n > 0){
GEngine->AddOnScreenDebugMessage(3,1.0f, FColor::Green, FString::Printf(TEXT("%d bytes Received!"),n));
} else {
GEngine->AddOnScreenDebugMessage(4,1.0f, FColor::Yellow, TEXT("noothing..."));
}
}
}
#endif
Hi Dave,
The fact that bind returns true indicates that one of the previous socket operations is the one that actually set the error code (GetSocketError on Android just checks the global errno
). To narrow it down, try checking GetSocketError() after the other socket operations as well - CreateSocket, SetNonBlocking, and SetReuseAddr.
Also, the workaround code isn’t setting SO_REUSEADDR on the socket - you can try removing the SetReuseAddr call if you don’t need to reuse the port.