For example when devices need a fixed reply port.
This is possible with OpenNetworkConnection from Purebasic. But then unfortunately only with one connection, because you cannot use the same local port several times with the OpenNetworkConnection function.
So we are still missing the network function SendTo for CreateNetworkServer. I have made this available for all OS.
If the server is running in the thread and the SendTo functions are used outside, they must be protected with mutex.
You can find an example here: UDP Local Network Short Text Sending
Update v1.01.2
- Added IPv6 support
Update v1.02.1
- Added GetConnectionIP
Code: Select all
; *************************************************
; Comment : Network SendTo for UDP Server (All OS)
; Author : mk-soft
; Version : v1.02.1
; Create : 30.12.2022
; Update : 08.01.2023
; Link : https://www.purebasic.fr/english/viewtopic.php?t=80367
; Description
; Socket = ServerID(Server) / ConnectionID(Client)
;-- Contants
#AF_INET = 2
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
#AF_INET6 = 23
CompilerCase #PB_OS_Linux
#AF_INET6 = 10
CompilerCase #PB_OS_MacOS
#AF_INET6 = 30
CompilerEndSelect
;-- Structures
CompilerIf Not Defined(in_addr, #PB_Structure)
Structure in_addr
StructureUnion
s_b.a[4]
s_w.u[2]
s_addr.l
EndStructureUnion
EndStructure
CompilerEndIf
CompilerIf Not Defined(in6_addr, #PB_Structure)
Structure in6_addr
s6_addr.a[16]
EndStructure
CompilerEndIf
CompilerIf Not Defined(SOCKADDR, #PB_Structure)
Structure SOCKADDR
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
sa_len.a
sa_family.a
CompilerElse
sin_family.w
CompilerEndIf
sa_data.b[14]
EndStructure
CompilerEndIf
CompilerIf Not Defined(SOCKADDR_IN4, #PB_Structure)
Structure SOCKADDR_IN4
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
sin_len.a
sin_family.a
CompilerElse
sin_family.w
CompilerEndIf
sin_port.u
sin_addr.in_addr
sin_zero.b[8]
EndStructure
CompilerEndIf
CompilerIf Not Defined(SOCKADDR_IN6, #PB_Structure)
Structure SOCKADDR_IN6
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
sin6_len.a
sin6_family.a
CompilerElse
sin6_family.w
CompilerEndIf
sin6_port.u
sin6_flowinfo.l
sin6_addr.in6_addr
sin6_scope_id.l
EndStructure
CompilerEndIf
CompilerIf Not Defined(SOCKADDR_STORAGE, #PB_Structure)
Structure SOCKADDR_STORAGE
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
ss_len.a
ss_family.a
CompilerElse
ss_family.w
CompilerEndIf
ss_port.u
ss_data.a[24]
EndStructure
CompilerEndIf
;-- Functions
Procedure SendNetworkStringTo(Socket, IP.s, Port, Text.s, Format = #PB_UTF8, Protocol = #PB_Network_IPv4)
Protected r1, *ip, *sendbuf, lenbuf, *RecvAddrIP4.SOCKADDR_IN4, *RecvAddrIP6.SOCKADDR_IN6
Select Format
Case #PB_Ascii
*sendbuf = Ascii(Text)
lenbuf = StringByteLength(Text, #PB_Ascii)
Case #PB_UTF8, 0
*sendbuf = UTF8(Text)
lenbuf = StringByteLength(Text, #PB_UTF8)
Case #PB_Unicode
*sendbuf = @Text
lenbuf = Len(Text)
EndSelect
*ip = Ascii(IP)
Select Protocol
Case #PB_Network_IPv4
*RecvAddrIP4 = AllocateStructure(SOCKADDR_IN4)
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
*RecvAddrIP4\sin_len = SizeOf(SOCKADDR_IN4)
CompilerEndIf
*RecvAddrIP4\sin_family = #AF_INET
*RecvAddrIP4\sin_port = htons_(Port)
*RecvAddrIP4\sin_addr\s_addr = inet_addr_(*ip)
r1 = sendto_(socket, *sendbuf, lenbuf, 0, *RecvAddrIP4, SizeOf(SOCKADDR_IN4))
FreeStructure(*RecvAddrIP4)
Case #PB_Network_IPv6
*RecvAddrIP6 = AllocateStructure(SOCKADDR_IN6)
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
*RecvAddrIP6\sin6_len = SizeOf(SOCKADDR_IN6)
CompilerEndIf
*RecvAddrIP6\sin6_family = #AF_INET6
*RecvAddrIP6\sin6_port = htons_(Port)
*RecvAddrIP6\sin6_flowinfo = 0
inet_pton_(#AF_INET6, *ip, @*RecvAddrIP6\sin6_addr)
r1 = sendto_(socket, *sendbuf, lenbuf, 0, *RecvAddrIP6, SizeOf(SOCKADDR_IN6))
FreeStructure(*RecvAddrIP6)
EndSelect
If *sendbuf
FreeMemory(*sendbuf)
EndIf
FreeMemory(*ip)
ProcedureReturn r1
EndProcedure
; ----
Procedure SendNetworkDataTo(Socket, IP.s, Port, *Buffer, Size, Protocol = #PB_Network_IPv4)
Protected r1, *ip, *RecvAddrIP4.SOCKADDR_IN4, *RecvAddrIP6.SOCKADDR_IN6
*ip = Ascii(IP)
Select Protocol
Case #PB_Network_IPv4
*RecvAddrIP4 = AllocateStructure(SOCKADDR_IN4)
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
*RecvAddrIP4\sin_len = SizeOf(SOCKADDR_IN4)
CompilerEndIf
*RecvAddrIP4\sin_family = #AF_INET
*RecvAddrIP4\sin_port = htons_(Port)
*RecvAddrIP4\sin_addr\s_addr = inet_addr_(*ip)
r1 = sendto_(socket, *Buffer, Size, 0, *RecvAddrIP4, SizeOf(SOCKADDR_IN4))
FreeStructure(*RecvAddrIP4)
Case #PB_Network_IPv6
*RecvAddrIP6 = AllocateStructure(SOCKADDR_IN6)
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
*RecvAddrIP6\sin6_len = SizeOf(SOCKADDR_IN6)
CompilerEndIf
*RecvAddrIP6\sin6_family = #AF_INET6
*RecvAddrIP6\sin6_port = htons_(Port)
*RecvAddrIP6\sin6_flowinfo = 0
inet_pton_(#AF_INET6, *ip, @*RecvAddrIP6\sin6_addr)
r1 = sendto_(socket, *Buffer, Size, 0, *RecvAddrIP6, SizeOf(SOCKADDR_IN6))
FreeStructure(*RecvAddrIP6)
EndSelect
FreeMemory(*ip)
ProcedureReturn r1
EndProcedure
; ----
Procedure.s GetConnectionIP(Socket)
Protected addr.SOCKADDR_STORAGE
Protected *s4.SOCKADDR_IN4, *s6.SOCKADDR_IN6
Protected errCode.l, len, port, *ipstr, ip.s, *error
len = SizeOf(SOCKADDR_STORAGE)
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
addr\ss_len = SizeOf(SOCKADDR_STORAGE)
CompilerEndIf
errCode = getpeername_(Socket, addr, @len)
If errCode >= 0
*ipstr = AllocateMemory(256)
Select addr\ss_family
Case #AF_INET
*s4 = addr
port = ntohs_(*s4\sin_port)
If inet_ntop_(#AF_INET, @*s4\sin_addr, *ipstr, 256);
ip = PeekS(*ipstr, -1, #PB_Ascii)
EndIf
Case #AF_INET6
*s6 = addr
port = ntohs_(*s6\sin6_port)
If inet_ntop_(#AF_INET6, @*s6\sin6_addr, *ipstr, 256);
ip = PeekS(*ipstr, -1, #PB_Ascii)
EndIf
Default
ip = "Unknown protocol"
EndSelect
FreeMemory(*ipstr)
Else
IP = "Unknown"
EndIf
ProcedureReturn ip
EndProcedure
; *************************************************