aboutsummaryrefslogtreecommitdiff
path: root/nimbluez/bluetoothnativesockets.nim
diff options
context:
space:
mode:
authorElectric-Blue <Electric-Blue@users.noreply.github.com>2016-01-26 02:03:48 +0300
committerElectric-Blue <Electric-Blue@users.noreply.github.com>2016-01-26 02:03:48 +0300
commit0c4a1cc1c2083a871562364de5df4f9d88ec321e (patch)
treeddb8428845b663c078359eda4ec81bdcc157414f /nimbluez/bluetoothnativesockets.nim
parent27a7a2a18a6db8b67cbe0e86c37cb174de2a1295 (diff)
downloadNimBluez-0c4a1cc1c2083a871562364de5df4f9d88ec321e.tar.gz
NimBluez-0c4a1cc1c2083a871562364de5df4f9d88ec321e.zip
First version.
Diffstat (limited to 'nimbluez/bluetoothnativesockets.nim')
-rw-r--r--nimbluez/bluetoothnativesockets.nim433
1 files changed, 433 insertions, 0 deletions
diff --git a/nimbluez/bluetoothnativesockets.nim b/nimbluez/bluetoothnativesockets.nim
new file mode 100644
index 0000000..b079b42
--- /dev/null
+++ b/nimbluez/bluetoothnativesockets.nim
@@ -0,0 +1,433 @@
+# Copyright (c) 2016, Maxim V. Abramov
+# All rights reserved.
+# Look at license.txt for more info.
+
+## This module implements a low-level cross-platform sockets interface for
+## Bluetooth.
+
+import os, nativesockets
+
+const useWinVersion = defined(Windows) or defined(nimdoc)
+
+when useWinVersion:
+ import winlean
+ import msbt/ms_bluetoothapis, msbt/ms_ws2bth
+ import bluetoothmsbt
+else:
+ from posix import InvalidSocket, getsockname, getpeername
+ import bluez/bz_bluetooth, bluez/bz_rfcomm, bluez/bz_l2cap
+ import bluetoothbluez
+
+export SocketHandle, SockAddr, SockLen, SockType, Port
+export
+ connect, close, listen, accept, send, recv, sendto, recvfrom, `==`, bindAddr,
+ getSockOptInt, setSockOptInt
+export InvalidSocket
+export
+ SOL_L2CAP, SOL_RFCOMM,
+ SO_ERROR,
+ SOMAXCONN,
+ SO_ACCEPTCONN, SO_BROADCAST, SO_DEBUG, SO_DONTROUTE,
+ SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR
+ #MSG_PEEK
+
+
+type
+ ProtocolFamily* = enum ## Protocol family of the socket.
+ PF_BLUETOOTH = 31 ## for Bluetooth socket.
+
+ BluetoothDomain* = enum ## Address family of the socket. This extends Domain
+ ## form the nativesockets.
+ AF_BLUETOOTH = 31 ## for Bluetooth socket.
+
+ BluetoothProtocol* = enum ## third argument to `socket` proc
+ BTPROTO_L2CAP = 0, ## Logical link control and adaptation protocol.
+ ## Unsupported on Windows.
+ BTPROTO_RFCOMM = 3 ## Radio frequency communication.
+
+ RfcommPort* = 0..30 ## RFCOMM channel. The valid range for requesting
+ ## a specific RFCOMM port is 1 through 30 or 0 for
+ ## automatic assign.
+
+ L2capPort* = 0..32767 ## L2CAP port (Protocol Service Multiplexer) can take
+ ## on odd-numbered values between 1 and 32767. Reserved
+ ## (well known) port numbers are between 1 and 4095.
+
+
+when useWinVersion:
+ type
+ RfcommAddr* = SOCKADDR_BTH
+ L2capAddr* = object
+else:
+ type
+ RfcommAddr* = sockaddr_rc
+ L2capAddr* = sockaddr_l2
+
+
+type
+ RfcommAddrRef* = ref RfcommAddr
+ L2capAddrRef* = ref L2capAddr
+
+
+
+when useWinVersion:
+ const
+ nativePfBluetooth* = ms_ws2bth.PF_BTH
+ nativeAfBluetooth* = ms_ws2bth.AF_BTH
+ WSAEPROTONOSUPPORT = OSErrorCode(10043)
+else:
+ const
+ nativePfBluetooth* = bz_bluetooth.PF_BLUETOOTH
+ nativeAfBluetooth* = bz_bluetooth.AF_BLUETOOTH
+
+
+proc toInt*(family: ProtocolFamily): cint
+ ## Converts the ProtocolFamily enum to a platform-dependent ``cint``.
+
+
+proc toInt*(domain: BluetoothDomain): cint
+ ## Converts the BluetoothDomain enum to a platform-dependent ``cint``.
+
+
+proc toInt*(protocol: BluetoothProtocol): cint
+ ## Converts the BluetoothProtocol enum to a platform-dependent ``cint``.
+
+
+when useWinVersion:
+ proc toInt*(family: ProtocolFamily): cint =
+ case family
+ of PF_BLUETOOTH: result = cint(ms_ws2bth.PF_BTH)
+ else: discard
+
+ proc toInt*(domain: BluetoothDomain): cint =
+ case domain
+ of AF_BLUETOOTH: result = cint(ms_ws2bth.AF_BTH)
+
+
+ proc toInt*(protocol: BluetoothProtocol): cint =
+ case protocol
+ of BTPROTO_L2CAP: result = cint(ms_ws2bth.BTHPROTO_L2CAP)
+ of BTPROTO_RFCOMM: result = cint(ms_ws2bth.BTHPROTO_RFCOMM)
+
+else:
+ proc toInt*(family: ProtocolFamily): cint =
+ case family
+ of PF_BLUETOOTH: result = cint(bz_bluetooth.PF_BLUETOOTH)
+
+
+ proc toInt*(domain: BluetoothDomain): cint =
+ case domain
+ of AF_BLUETOOTH: result = cint(bz_bluetooth.AF_BLUETOOTH)
+
+
+ proc toInt*(protocol: BluetoothProtocol): cint =
+ case protocol
+ of BTPROTO_L2CAP: result = cint(bz_bluetooth.BTPROTO_L2CAP)
+ of BTPROTO_RFCOMM: result = cint(bz_bluetooth.BTPROTO_RFCOMM)
+
+
+proc htobs*(d: int16): int16 =
+ ## Converts 16-bit integers from host to Bluetooth byte order.
+ ## On machines where the host byte order is the same as Bluetooth byte order,
+ ## this is a no-op; otherwise, it performs a 2-byte swap operation.
+ when cpuEndian == bigEndian:
+ swapEndian16(result, d)
+ else:
+ result = d
+
+
+proc htobl*(d: int32): int32 =
+ ## Converts 32-bit integers from host to Bluetooth byte order.
+ ## On machines where the host byte order is the same as Bluetooth byte order,
+ ## this is a no-op; otherwise, it performs a 4-byte swap operation.
+ when cpuEndian == bigEndian:
+ swapEndian32(result, d)
+ else:
+ result = d
+
+
+proc htobll*(d: int64): int64 =
+ ## Converts 64-bit integers from host to Bluetooth byte order.
+ ## On machines where the host byte order is the same as Bluetooth byte order,
+ ## this is a no-op; otherwise, it performs a 8-byte swap operation.
+ when cpuEndian == bigEndian:
+ swapEndian64(result, d)
+ else:
+ result = d
+
+
+template btohs*(d: expr): expr =
+ ## Converts 16-bit integers from Bluetooth to host byte order.
+ ## On machines where the host byte order is the same as Bluetooth byte order,
+ ## this is a no-op; otherwise, it performs a 2-byte swap operation.
+ htobs(d)
+
+
+template btohl*(d: expr): expr =
+ ## Converts 32-bit integers from Bluetooth to host byte order.
+ ## On machines where the host byte order is the same as Bluetooth byte order,
+ ## this is a no-op; otherwise, it performs a 4-byte swap operation.
+ htobl(d)
+
+
+template btohll*(d: expr): expr =
+ ## Converts 64-bit integers from Bluetooth to host byte order.
+ ## On machines where the host byte order is the same as Bluetooth byte order,
+ ## this is a no-op; otherwise, it performs a 8-byte swap operation.
+ htobll(d)
+
+
+when not useWinVersion:
+ proc htob_bdaddr*(d: bdaddr_t): bdaddr_t =
+ ## Converts bdaddr_t from host toBluetooth byte order.
+ ## On machines where the host byte order is the same as Bluetooth,
+ ## this is a no-op; otherwise, it performs a 6-byte swap operation.
+ when cpuEndian == bigEndian:
+ for i in countup(0, 5):
+ result[5 - i] = d[i]
+ else:
+ result = d
+
+ template btoh_bdaddr*(d: expr): expr =
+ ## Converts bdaddr_t from Bluetooth to host byte order.
+ ## On machines where the host byte order is the same as Bluetooth,
+ ## this is a no-op; otherwise, it performs a 6-byte swap operation.
+ htob_bdaddr(d)
+
+
+proc newBluetoothNativeSocket*(sockType: SockType = SOCK_STREAM,
+ protocol: BluetoothProtocol = BTPROTO_RFCOMM):
+ SocketHandle =
+ ## Creates a new Bluetooth socket; returns `InvalidSocket` if an error occurs.
+ result =
+ newNativeSocket(toInt(ProtocolFamily.PF_BLUETOOTH),
+ toInt(sockType),
+ toInt(protocol))
+
+
+proc getRfcommAddr*(port = RfcommPort(0), address = ""): RfcommAddr
+ ## Creates and fills Bluetooth address structure for RFCOMM protocol.
+
+
+proc getL2capAddr*(port = L2capPort(0), address = ""): L2capAddr
+ ## Creates and fills Bluetooth address structure for L2CAP protocol.
+
+
+proc getRfcommLocalName*(socket: SocketHandle): RfcommAddr
+ ## Returns the RFCOMM socket's associated port number.
+
+
+proc getL2capLocalName*(socket: SocketHandle): L2capAddr
+ ## Returns the L2CAP socket's associated port number.
+
+
+proc getRfcommPeerName*(socket: SocketHandle): RfcommAddr
+ ## Returns the RFCOMM socket's associated port number.
+
+
+proc getL2capPeerName*(socket: SocketHandle): L2capAddr
+ ## Returns the L2CAP socket's associated port number.
+
+
+proc getAddrString*(sockAddr: RfcommAddr): string
+ ## Returns the string representation of a Bluetooth address.
+
+
+proc getAddrString*(sockAddr: L2capAddr): string
+ ## Returns the string representation of a Bluetooth address.
+
+
+proc getAddrPort*(sockAddr: RfcommAddr): RfcommPort
+ ## Returns port of a Bluetooth address.
+
+
+proc getAddrPort*(sockAddr: L2capAddr): L2capPort
+ ## Returns port of a Bluetooth address.
+
+
+when useWinVersion:
+ proc getRfcommAddr*(port = RfcommPort(0), address = ""): RfcommAddr =
+ result.addressFamily = htobs(
+ toInt(BluetoothDomain.AF_BLUETOOTH).int16).uint16
+ if address != nil and address != "":
+ result.btAddr = htobll(
+ parseBluetoothAddress(address).ano_116103095.ullLong.int32).uint32
+ #result.serviceClassId =
+ #TODO: use htob... proc there.
+ result.port = htobl(if port == 0: -1'i32 else: int32(port))
+ #result.port = htobl(ULONG(port))
+
+
+ proc getL2capAddr*(port = L2capPort(0), address = ""): L2capAddr =
+ raiseOSError(WSAEPROTONOSUPPORT)
+
+
+ proc getRfcommLocalName*(socket: SocketHandle): RfcommAddr =
+ var name = getRfcommAddr()
+ var nameLen = sizeof(name).SockLen
+ if getsockname(socket,
+ cast[ptr SockAddr](addr(name)),
+ addr(nameLen)) == -1'i32:
+ raiseOSError(osLastError())
+ result = name
+
+
+ proc getL2capLocalName*(socket: SocketHandle): L2capAddr =
+ raiseOSError(WSAEPROTONOSUPPORT)
+
+
+ proc getRfcommPeerName*(socket: SocketHandle): RfcommAddr =
+ var name = getRfcommAddr()
+ var nameLen = sizeof(name).SockLen
+ if getpeername(socket,
+ cast[ptr SockAddr](addr(name)),
+ addr(nameLen)) == -1'i32:
+ raiseOSError(osLastError())
+ result = name
+
+
+ proc getL2capPeerName*(socket: SocketHandle): L2capAddr =
+ raiseOSError(WSAEPROTONOSUPPORT)
+
+
+ proc getAddrString*(sockAddr: RfcommAddr): string =
+ result = $cast[BLUETOOTH_ADDRESS](btohll(sockAddr.btAddr.int64))
+
+
+ proc getAddrString*(sockAddr: L2capAddr): string =
+ raiseOSError(WSAEPROTONOSUPPORT)
+
+
+ proc getAddrPort*(sockAddr: RfcommAddr): RfcommPort =
+ result = btohl(sockAddr.port)
+
+
+ proc getAddrPort*(sockAddr: L2capAddr): L2capPort =
+ raiseOSError(WSAEPROTONOSUPPORT)
+
+
+else:
+ proc getRfcommAddr*(port = RfcommPort(0), address = ""): RfcommAddr =
+ result.rc_family = htobs(toInt(BluetoothDomain.AF_BLUETOOTH).uint16)
+ if address != nil and address != "":
+ result.rc_bdaddr = htob_bdaddr(parseBluetoothAddress(address))
+ if port != RfcommPort(0):
+ result.rc_channel = uint8(port)
+
+
+ proc getL2capAddr*(port = L2capPort(0), address = ""): L2capAddr =
+ result.l2_family = htobs(toInt(BluetoothDomain.AF_BLUETOOTH).uint16)
+ if address != nil and address != "":
+ result.l2_bdaddr = htob_bdaddr(parseBluetoothAddress(address))
+ if port != L2capPort(0):
+ result.l2_psm = htobs(cushort(port))
+
+
+ proc getRfcommLocalName*(socket: SocketHandle): RfcommAddr =
+ var name = getRfcommAddr()
+ var nameLen = sizeof(name).SockLen
+ if getsockname(socket,
+ cast[ptr SockAddr](addr(name)),
+ addr(namelen)) == -1'i32:
+ raiseOSError(osLastError())
+ result = name
+
+
+ proc getL2capLocalName*(socket: SocketHandle): L2capAddr =
+ var name = getL2capAddr()
+ var nameLen = sizeof(name).SockLen
+ if getsockname(socket,
+ cast[ptr SockAddr](addr(name)),
+ addr(nameLen)) == -1'i32:
+ raiseOSError(osLastError())
+ result = name
+
+
+ proc getRfcommPeerName*(socket: SocketHandle): RfcommAddr =
+ var name = getRfcommAddr()
+ var nameLen = sizeof(name).SockLen
+ if getpeername(socket,
+ cast[ptr SockAddr](addr(name)),
+ addr(nameLen)) == -1'i32:
+ raiseOSError(osLastError())
+ result = name
+
+
+ proc getL2capPeerName*(socket: SocketHandle): L2capAddr =
+ var name = getL2capAddr()
+ var nameLen = sizeof(name).SockLen
+ if getpeername(socket,
+ cast[ptr SockAddr](addr(name)),
+ addr(nameLen)) == -1'i32:
+ raiseOSError(osLastError())
+ result = name
+
+
+ proc getAddrString*(sockAddr: RfcommAddr): string =
+ result = $btoh_bdaddr(sockAddr.rc_bdaddr)
+
+
+ proc getAddrString*(sockAddr: L2capAddr): string =
+ result = $btoh_bdaddr(sockAddr.l2_bdaddr)
+
+
+ proc getAddrPort*(sockAddr: RfcommAddr): RfcommPort =
+ result = sockAddr.rc_channel
+
+
+ proc getAddrPort*(sockAddr: L2capAddr): L2capPort =
+ result = btohs(sockAddr.l2_psm)
+
+
+proc getRfcommSockName*(socket: SocketHandle): RfcommPort =
+ ## Returns the RFCOMM socket's associated port number.
+ var name = getRfcommLocalName(socket)
+ result = getAddrPort(name)
+
+
+proc getL2capSockName*(socket: SocketHandle): L2capPort =
+ ## Returns the L2CAP socket's associated port number.
+ var name = getL2capLocalName(socket)
+ result = getAddrPort(name)
+
+
+proc getRfcommLocalAddr*(socket: SocketHandle): (string, RfcommPort) =
+ ## Returns the socket's local address and port number.
+ ##
+ ## Similar to POSIX's `getsockname`:idx:.
+ var name = getRfcommLocalName(socket)
+ result = (getAddrString(name), getAddrPort(name))
+
+
+proc getL2capLocalAddr*(socket: SocketHandle): (string, L2capPort) =
+ ## Returns the socket's local address and port number.
+ ##
+ ## Similar to POSIX's `getsockname`:idx:.
+ var name = getL2capLocalName(socket)
+ result = (getAddrString(name), getAddrPort(name))
+
+
+proc getRfcommPeerAddr*(socket: SocketHandle): (string, RfcommPort) =
+ ## Returns the socket's peer address and port number.
+ ##
+ ## Similar to POSIX's `getpeername`:idx:
+ var name = getRfcommAddr()
+ var nameLen = sizeof(name).SockLen
+ if getpeername(socket,
+ cast[ptr SockAddr](addr(name)),
+ addr(namelen)) == -1'i32:
+ raiseOSError(osLastError())
+ result = (getAddrString(name), getAddrPort(name))
+
+
+proc getL2capPeerAddr*(socket: SocketHandle): (string, L2capPort) =
+ ## Returns the socket's peer address and port number.
+ ##
+ ## Similar to POSIX's `getpeername`:idx:
+ var name = getL2capAddr()
+ var nameLen = sizeof(name).SockLen
+ if getpeername(socket,
+ cast[ptr SockAddr](addr(name)),
+ addr(namelen)) == -1'i32:
+ raiseOSError(osLastError())
+ result = (getAddrString(name), getAddrPort(name))