I tried to make an example of simple socket server.
Build and run successfully. However it doesn't work well.
Client couldn't connect to this server.
How to solve this problem? I need your help, thanks.
import Foundation
let BUFF_SIZE = 1024
func initStruct<S>() -> S {
let struct_pointer = UnsafePointer<S>.alloc(1)
let struct_memory = struct_pointer.memory
struct_pointer.destroy()
return struct_memory
}
func sockaddr_cast(p: ConstUnsafePointer<sockaddr_in>) -> UnsafePointer<sockaddr> {
return UnsafePointer<sockaddr>(p)
}
func socklen_t_cast(p: UnsafePointer<Int>) -> UnsafePointer<socklen_t> {
return UnsafePointer<socklen_t>(p)
}
var server_socket: Int32
var client_socket: Int32
var server_addr_size: Int
var client_addr_size: Int
var server_addr: sockaddr_in = initStruct()
var client_addr: sockaddr_in = initStruct()
var buff_rcv: Array<CChar> = []
var buff_snd: String
server_socket = socket(PF_INET, SOCK_STREAM, 0);
if server_socket == -1
{
println("[Fail] Create Server Socket")
exit(1)
}
else
{
println("[Success] Created Server Socket")
}
server_addr_size = sizeof(server_addr.dynamicType)
memset(&server_addr, 0, UInt(server_addr_size));
server_addr.sin_family = sa_family_t(AF_INET)
server_addr.sin_port = 4000
server_addr.sin_addr.s_addr = UInt32(0x00000000) // INADDR_ANY = (u_int32_t)0x00000000 ----- <netinet/in.h>
let bind_server = bind(server_socket, sockaddr_cast(&server_addr), socklen_t(server_addr_size))
if bind_server == -1
{
println("[Fail] Bind Port");
exit(1);
}
else
{
println("[Success] Binded Port");
}
if listen(server_socket, 5) == -1
{
println("[Fail] Listen");
exit(1);
}
else
{
println("[Success] Listening : \(server_addr.sin_port) Port ...");
}
var n = 0
while n < 1
{
client_addr_size = sizeof(client_addr.dynamicType)
client_socket = accept(server_socket, sockaddr_cast(&client_addr), socklen_t_cast(&client_addr_size))
if client_socket == -1
{
println("[Fail] Accept Client Connection");
exit(1);
}
else
{
println("[Success] Accepted Client : \(inet_ntoa(client_addr.sin_addr)) : \(client_addr.sin_port)");
}
read(client_socket, &buff_rcv, UInt(BUFF_SIZE))
println("[Success] Received : \(buff_rcv)")
buff_snd = "\(strlen(buff_rcv)) : \(buff_rcv)"
write(client_socket, &buff_snd, strlen(buff_snd) + 1)
close(client_socket)
}
The port number in the socket address must be in big-endian byte order:
server_addr.sin_port = UInt16(4000).bigEndian
So your program actually listens on port 40975 (hex 0xA00F) and not
on port 4000 (hex 0x0FA0).
Another problem is here:
var buff_rcv: Array<CChar> = []
// ...
read(client_socket, &buff_rcv, UInt(BUFF_SIZE))
Your buffer is an empty array, but recv() expects a buffer of size BUFF_SIZE.
The behaviour is undefined. To get a buffer of the required size, use
var buff_rcv = [CChar](count:BUFF_SIZE, repeatedValue:0)
// ...
read(client_socket, &buff_rcv, UInt(buff_rcv.count))
Remark: Here you cast the address of an Int to the address of an socklen_t
and pass that to the accept() function:
client_socket = accept(server_socket, sockaddr_cast(&client_addr), socklen_t_cast(&client_addr_size))
That is not safe. If Int and socklen_t have different sizes then the behaviour
will be undefined. You should declare server_addr_size and client_addr_size
as socklen_t and remove the socklen_t_cast() function:
client_socket = accept(server_socket, sockaddr_cast(&client_addr), &client_addr_size)
As Martin R commented before, the write command shouldn't be using the swift string as that. Something like this will work properly:
write(client_socket, buff_snd.cStringUsingEncoding(NSUTF8StringEncoding)!, countElements(buff_snd) + 1)
Related
I am trying to download my hex file of size 1500KB via UDS with CAPL test module,
p2 timer = 50ms
p2* timer = 5000ms
Here is snippet of my code for data transfer :
void TS_transferData()
{
byte transferData_serviceid = 0x36;
byte blockSequenceCounter = 0x1;
byte buffer[4093];
byte binarydata[4095];
long i,ret1,ret2,ret3,temp,timeout = 0,Counter = 0;
char filename[30] = "xxx.bin";
dword readaccess_handle;
diagrequest ECU_QUALIFIER.* request;
long valueleft;
readaccess_handle = OpenFileRead(filename,1);
if (readaccess_handle != 0 )
{
while( (valueleft = fileGetBinaryBlock(buffer,elcount(buffer),readaccess_handle))==4093 )
{
binarydata[0] = transferData_serviceid;
binarydata[1] = blockSequenceCounter;
for(i=0;i<elcount(buffer);i++)
{
binarydata[i+2] = buffer[i];
}
diagResize(request, elCount(binarydata));
DiagSetPrimitiveData(request,binarydata,elcount(binarydata));
DiagSendRequest(request);
write("length of binarydata %d ",elcount(binarydata));
// Wait until the request has been completely sent
ret1 = TestWaitForDiagRequestSent(request, 20000);
if(ret1 == 1) // Request sent
{
ret2=TestWaitForDiagResponse(request,50);
if(ret2==1) // Response received
{
ret3=DiagGetLastResponseCode(request); // Get the code of the response
if(ret3==-1) // Is it a positive response?
{
;
}
else
{
testStepFail(0, "4.0","Binary Datatransfer on server Failed");
break;
}
}
else if(ret2 == timeout)
{
testStepFail(0, "4.0","Binary Datatransfer on server Failed");
write("timeout occured while TestWaitForDiagResponse with block %d ",blockSequenceCounter);
}
}
else if(ret1 == timeout)
{
testStepFail(0, "4.0","Binary Datatransfer on server Failed");
write("timeout occured while TestWaitForDiagRequestSent %d ",blockSequenceCounter);
}
if(blockSequenceCounter == 255)
blockSequenceCounter = 0;
else
++blockSequenceCounter;
}
}
//handle the rest of the bytes to be transmitted
fileClose (readaccess_handle);
}
The software downloading is happening but it is taking a long.... time for download.
For TestWaitForDiagRequestSent() function any value for timeout less than 20000 is giving me timeout error.
Is there any other way I can reduce the software transfer time or where am I going wrong with calculation?
Is there any example I can refer to see How to transmit such a long data using CAPL ?
Sorry, I am a beginner to CAPL and UDS protocol.
When I tried using Ocelot as a WebSocket proxy, I could not get it working for wss. I was able to see it working for ws.
When we are trying to proxy for wss getting decrypt operation failed while reading the bytes at the server side socket. With plan ws I am able to get this working.
Ocelot config as follows, where wss proxying is specified:
{
"Routes": [
{
"DownstreamPathTemplate": "/ws",
"UpstreamPathTemplate": "/{anything}",
"DownstreamScheme": "wss",
"DownstreamHostAndPorts": [
{
"Host": "127.0.0.1",
"Port": 8080
}
]
}
]
}
Websocket Server code which listens on port 8080:
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
class Server
{
public static void Main()
{
string ip = "127.0.0.1";
int port = 8080;
var server = new TcpListener(IPAddress.Parse(ip), port);
server.Start();
Console.WriteLine("Server has started on {0}:{1}, Waiting for a connection...", ip, port);
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("A client connected.");
byte[] pfxData = File.ReadAllBytes(#"C:\Users\e409316\Desktop\test.pfx");
var cert = new X509Certificate2(pfxData, "Password1", X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.Exportable);
Stream sourceTcpStream = new SslStream(client.GetStream(), false);
(sourceTcpStream as SslStream).AuthenticateAsServer(
cert,
false,
SslProtocols.Tls12, true);
Stream stream = sourceTcpStream;//client.GetStream();
//Stream stream = client.GetStream();
// enter to an infinite cycle to be able to handle every change in stream
while (true)
{
//while (!stream.DataAvailable) ;
while (client.Available < 3) ; // match against "get"
byte[] bytes = new byte[client.Available];
stream.Read(bytes, 0, client.Available);
string s = Encoding.UTF8.GetString(bytes);
if (Regex.IsMatch(s, "^GET", RegexOptions.IgnoreCase))
{
Console.WriteLine("=====Handshaking from client=====\n{0}", s);
// 1. Obtain the value of the "Sec-WebSocket-Key" request header without any leading or trailing whitespace
// 2. Concatenate it with "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (a special GUID specified by RFC 6455)
// 3. Compute SHA-1 and Base64 hash of the new value
// 4. Write the hash back as the value of "Sec-WebSocket-Accept" response header in an HTTP response
string swk = Regex.Match(s, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim();
string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka));
string swkaSha1Base64 = Convert.ToBase64String(swkaSha1);
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker
byte[] response = Encoding.UTF8.GetBytes(
"HTTP/1.1 101 Switching Protocols\r\n" +
"Connection: Upgrade\r\n" +
"Upgrade: websocket\r\n" +
"Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n");
stream.Write(response, 0, response.Length);
}
else
{
bool fin = (bytes[0] & 0b10000000) != 0,
mask = (bytes[1] & 0b10000000) != 0; // must be true, "All messages from the client to the server have this bit set"
int opcode = bytes[0] & 0b00001111, // expecting 1 - text message
msglen = bytes[1] - 128, // & 0111 1111
offset = 2;
if (msglen == 126)
{
// was ToUInt16(bytes, offset) but the result is incorrect
msglen = BitConverter.ToUInt16(new byte[] { bytes[3], bytes[2] }, 0);
offset = 4;
}
else if (msglen == 127)
{
Console.WriteLine("TODO: msglen == 127, needs qword to store msglen");
// i don't really know the byte order, please edit this
// msglen = BitConverter.ToUInt64(new byte[] { bytes[5], bytes[4], bytes[3], bytes[2], bytes[9], bytes[8], bytes[7], bytes[6] }, 0);
// offset = 10;
}
if (msglen == 0)
Console.WriteLine("msglen == 0");
else if (mask)
{
byte[] decoded = new byte[msglen];
byte[] masks = new byte[4] { bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3] };
offset += 4;
for (int i = 0; i < msglen; ++i)
decoded[i] = (byte)(bytes[offset + i] ^ masks[i % 4]);
string text = Encoding.UTF8.GetString(decoded);
Console.WriteLine("{0}", text);
}
else
Console.WriteLine("mask bit not set");
Console.WriteLine();
}
}
}
}
Websocket Client code which tries to connect to ocelot endpoint (upstream endpoint on port 5000):
ClientWebSocket client = new ClientWebSocket();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
client.ConnectAsync(new Uri("wss://127.0.0.1:5000/"), CancellationToken.None).Wait();
var buffer = new byte[]{1,2,3};
client.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true,CancellationToken.None);
Error: The decryption operation failed
Found it to be a certificate validity issue. Solved it by using a trusted certificate.
I am now using FileStreamResult and it works to stream a video, but can't seek it. It always starts again from the beginning.
I was using ByteRangeStreamContent but it seems that it is not available anymore with dnxcore50.
So how to proceed ?
Do i need to manually parse the request range headers and write a custom FileResult that sets the response Content-Range and the rest of the headers and writes the buffer range to the response body or is there something already implemented and i'm missing it ?
Here is a naive implementation of a VideoStreamResult. I am using at the moment (the multipart content part is not tested):
public class VideoStreamResult : FileStreamResult
{
// default buffer size as defined in BufferedStream type
private const int BufferSize = 0x1000;
private string MultipartBoundary = "<qwe123>";
public VideoStreamResult(Stream fileStream, string contentType)
: base(fileStream, contentType)
{
}
public VideoStreamResult(Stream fileStream, MediaTypeHeaderValue contentType)
: base(fileStream, contentType)
{
}
private bool IsMultipartRequest(RangeHeaderValue range)
{
return range != null && range.Ranges != null && range.Ranges.Count > 1;
}
private bool IsRangeRequest(RangeHeaderValue range)
{
return range != null && range.Ranges != null && range.Ranges.Count > 0;
}
protected async Task WriteVideoAsync(HttpResponse response)
{
var bufferingFeature = response.HttpContext.Features.Get<IHttpBufferingFeature>();
bufferingFeature?.DisableResponseBuffering();
var length = FileStream.Length;
var range = response.HttpContext.GetRanges(length);
if (IsMultipartRequest(range))
{
response.ContentType = $"multipart/byteranges; boundary={MultipartBoundary}";
}
else
{
response.ContentType = ContentType.ToString();
}
response.Headers.Add("Accept-Ranges", "bytes");
if (IsRangeRequest(range))
{
response.StatusCode = (int)HttpStatusCode.PartialContent;
if (!IsMultipartRequest(range))
{
response.Headers.Add("Content-Range", $"bytes {range.Ranges.First().From}-{range.Ranges.First().To}/{length}");
}
foreach (var rangeValue in range.Ranges)
{
if (IsMultipartRequest(range)) // I don't know if multipart works
{
await response.WriteAsync($"--{MultipartBoundary}");
await response.WriteAsync(Environment.NewLine);
await response.WriteAsync($"Content-type: {ContentType}");
await response.WriteAsync(Environment.NewLine);
await response.WriteAsync($"Content-Range: bytes {range.Ranges.First().From}-{range.Ranges.First().To}/{length}");
await response.WriteAsync(Environment.NewLine);
}
await WriteDataToResponseBody(rangeValue, response);
if (IsMultipartRequest(range))
{
await response.WriteAsync(Environment.NewLine);
}
}
if (IsMultipartRequest(range))
{
await response.WriteAsync($"--{MultipartBoundary}--");
await response.WriteAsync(Environment.NewLine);
}
}
else
{
await FileStream.CopyToAsync(response.Body);
}
}
private async Task WriteDataToResponseBody(RangeItemHeaderValue rangeValue, HttpResponse response)
{
var startIndex = rangeValue.From ?? 0;
var endIndex = rangeValue.To ?? 0;
byte[] buffer = new byte[BufferSize];
long totalToSend = endIndex - startIndex;
int count = 0;
long bytesRemaining = totalToSend + 1;
response.ContentLength = bytesRemaining;
FileStream.Seek(startIndex, SeekOrigin.Begin);
while (bytesRemaining > 0)
{
try
{
if (bytesRemaining <= buffer.Length)
count = FileStream.Read(buffer, 0, (int)bytesRemaining);
else
count = FileStream.Read(buffer, 0, buffer.Length);
if (count == 0)
return;
await response.Body.WriteAsync(buffer, 0, count);
bytesRemaining -= count;
}
catch (IndexOutOfRangeException)
{
await response.Body.FlushAsync();
return;
}
finally
{
await response.Body.FlushAsync();
}
}
}
public override async Task ExecuteResultAsync(ActionContext context)
{
await WriteVideoAsync(context.HttpContext.Response);
}
}
And parse request headers range:
public static RangeHeaderValue GetRanges(this HttpContext context, long contentSize)
{
RangeHeaderValue rangesResult = null;
string rangeHeader = context.Request.Headers["Range"];
if (!string.IsNullOrEmpty(rangeHeader))
{
// rangeHeader contains the value of the Range HTTP Header and can have values like:
// Range: bytes=0-1 * Get bytes 0 and 1, inclusive
// Range: bytes=0-500 * Get bytes 0 to 500 (the first 501 bytes), inclusive
// Range: bytes=400-1000 * Get bytes 500 to 1000 (501 bytes in total), inclusive
// Range: bytes=-200 * Get the last 200 bytes
// Range: bytes=500- * Get all bytes from byte 500 to the end
//
// Can also have multiple ranges delimited by commas, as in:
// Range: bytes=0-500,600-1000 * Get bytes 0-500 (the first 501 bytes), inclusive plus bytes 600-1000 (401 bytes) inclusive
// Remove "Ranges" and break up the ranges
string[] ranges = rangeHeader.Replace("bytes=", string.Empty).Split(",".ToCharArray());
rangesResult = new RangeHeaderValue();
for (int i = 0; i < ranges.Length; i++)
{
const int START = 0, END = 1;
long endByte, startByte;
long parsedValue;
string[] currentRange = ranges[i].Split("-".ToCharArray());
if (long.TryParse(currentRange[END], out parsedValue))
endByte = parsedValue;
else
endByte = contentSize - 1;
if (long.TryParse(currentRange[START], out parsedValue))
startByte = parsedValue;
else
{
// No beginning specified, get last n bytes of file
// We already parsed end, so subtract from total and
// make end the actual size of the file
startByte = contentSize - endByte;
endByte = contentSize - 1;
}
rangesResult.Ranges.Add(new RangeItemHeaderValue(startByte, endByte));
}
}
return rangesResult;
}
FYI, built-in support for range requests will be present in .NET Core 2.1
https://github.com/aspnet/Mvc/pull/6895
Is it possible to get the MAC address using Swift?
The MAC address being the primary address for the Wi-Fi or Airport.
I'm trying to make a OS X application.
Apple's sample code from https://developer.apple.com/library/mac/samplecode/GetPrimaryMACAddress/Introduction/Intro.html to retrieve the Ethernet MAC address can
be translated to Swift. I have preserved only the most important
comments, more explanations can be found in the original code.
// Returns an iterator containing the primary (built-in) Ethernet interface. The caller is responsible for
// releasing the iterator after the caller is done with it.
func FindEthernetInterfaces() -> io_iterator_t? {
let matchingDictUM = IOServiceMatching("IOEthernetInterface");
// Note that another option here would be:
// matchingDict = IOBSDMatching("en0");
// but en0: isn't necessarily the primary interface, especially on systems with multiple Ethernet ports.
if matchingDictUM == nil {
return nil
}
let matchingDict = matchingDictUM.takeUnretainedValue() as NSMutableDictionary
matchingDict["IOPropertyMatch"] = [ "IOPrimaryInterface" : true]
var matchingServices : io_iterator_t = 0
if IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &matchingServices) != KERN_SUCCESS {
return nil
}
return matchingServices
}
// Given an iterator across a set of Ethernet interfaces, return the MAC address of the last one.
// If no interfaces are found the MAC address is set to an empty string.
// In this sample the iterator should contain just the primary interface.
func GetMACAddress(intfIterator : io_iterator_t) -> [UInt8]? {
var macAddress : [UInt8]?
var intfService = IOIteratorNext(intfIterator)
while intfService != 0 {
var controllerService : io_object_t = 0
if IORegistryEntryGetParentEntry(intfService, "IOService", &controllerService) == KERN_SUCCESS {
let dataUM = IORegistryEntryCreateCFProperty(controllerService, "IOMACAddress", kCFAllocatorDefault, 0)
if dataUM != nil {
let data = dataUM.takeRetainedValue() as! NSData
macAddress = [0, 0, 0, 0, 0, 0]
data.getBytes(&macAddress!, length: macAddress!.count)
}
IOObjectRelease(controllerService)
}
IOObjectRelease(intfService)
intfService = IOIteratorNext(intfIterator)
}
return macAddress
}
if let intfIterator = FindEthernetInterfaces() {
if let macAddress = GetMACAddress(intfIterator) {
let macAddressAsString = ":".join(macAddress.map( { String(format:"%02x", $0) } ))
println(macAddressAsString)
}
IOObjectRelease(intfIterator)
}
The only "tricky" part is how to work with Unmanaged objects, those
have the suffix UM in my code.
Instead of returning an error code, the functions return an optional
value which is nil if the function failed.
Update for Swift 3:
func FindEthernetInterfaces() -> io_iterator_t? {
let matchingDict = IOServiceMatching("IOEthernetInterface") as NSMutableDictionary
matchingDict["IOPropertyMatch"] = [ "IOPrimaryInterface" : true]
var matchingServices : io_iterator_t = 0
if IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &matchingServices) != KERN_SUCCESS {
return nil
}
return matchingServices
}
func GetMACAddress(_ intfIterator : io_iterator_t) -> [UInt8]? {
var macAddress : [UInt8]?
var intfService = IOIteratorNext(intfIterator)
while intfService != 0 {
var controllerService : io_object_t = 0
if IORegistryEntryGetParentEntry(intfService, "IOService", &controllerService) == KERN_SUCCESS {
let dataUM = IORegistryEntryCreateCFProperty(controllerService, "IOMACAddress" as CFString, kCFAllocatorDefault, 0)
if let data = dataUM?.takeRetainedValue() as? NSData {
macAddress = [0, 0, 0, 0, 0, 0]
data.getBytes(&macAddress!, length: macAddress!.count)
}
IOObjectRelease(controllerService)
}
IOObjectRelease(intfService)
intfService = IOIteratorNext(intfIterator)
}
return macAddress
}
if let intfIterator = FindEthernetInterfaces() {
if let macAddress = GetMACAddress(intfIterator) {
let macAddressAsString = macAddress.map( { String(format:"%02x", $0) } )
.joined(separator: ":")
print(macAddressAsString)
}
IOObjectRelease(intfIterator)
}
Update for Swift 4.2
func FindEthernetInterfaces() -> io_iterator_t? {
let matchingDictUM = IOServiceMatching("IOEthernetInterface");
// Note that another option here would be:
// matchingDict = IOBSDMatching("en0");
// but en0: isn't necessarily the primary interface, especially on systems with multiple Ethernet ports.
if matchingDictUM == nil {
return nil
}
let matchingDict = matchingDictUM! as NSMutableDictionary
matchingDict["IOPropertyMatch"] = [ "IOPrimaryInterface" : true]
var matchingServices : io_iterator_t = 0
if IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &matchingServices) != KERN_SUCCESS {
return nil
}
return matchingServices
}
// Given an iterator across a set of Ethernet interfaces, return the MAC address of the last one.
// If no interfaces are found the MAC address is set to an empty string.
// In this sample the iterator should contain just the primary interface.
func GetMACAddress(_ intfIterator : io_iterator_t) -> [UInt8]? {
var macAddress : [UInt8]?
var intfService = IOIteratorNext(intfIterator)
while intfService != 0 {
var controllerService : io_object_t = 0
if IORegistryEntryGetParentEntry(intfService, kIOServicePlane, &controllerService) == KERN_SUCCESS {
let dataUM = IORegistryEntryCreateCFProperty(controllerService, "IOMACAddress" as CFString, kCFAllocatorDefault, 0)
if dataUM != nil {
let data = (dataUM!.takeRetainedValue() as! CFData) as Data
macAddress = [0, 0, 0, 0, 0, 0]
data.copyBytes(to: &macAddress!, count: macAddress!.count)
}
IOObjectRelease(controllerService)
}
IOObjectRelease(intfService)
intfService = IOIteratorNext(intfIterator)
}
return macAddress
}
func getMacAddress() -> String? {
var macAddressAsString : String?
if let intfIterator = FindEthernetInterfaces() {
if let macAddress = GetMACAddress(intfIterator) {
macAddressAsString = macAddress.map( { String(format:"%02x", $0) } ).joined(separator: ":")
print(macAddressAsString!)
}
IOObjectRelease(intfIterator)
}
return macAddressAsString
}
Different approach via if_msghdr
func MACAddressForBSD(bsd : String) -> String?
{
let MAC_ADDRESS_LENGTH = 6
let separator = ":"
var length : size_t = 0
var buffer : [CChar]
let bsdIndex = Int32(if_nametoindex(bsd))
if bsdIndex == 0 {
print("Error: could not find index for bsd name \(bsd)")
return nil
}
let bsdData = Data(bsd.utf8)
var managementInfoBase = [CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, bsdIndex]
if sysctl(&managementInfoBase, 6, nil, &length, nil, 0) < 0 {
print("Error: could not determine length of info data structure");
return nil;
}
buffer = [CChar](unsafeUninitializedCapacity: length, initializingWith: {buffer, initializedCount in
for x in 0..<length { buffer[x] = 0 }
initializedCount = length
})
if sysctl(&managementInfoBase, 6, &buffer, &length, nil, 0) < 0 {
print("Error: could not read info data structure");
return nil;
}
let infoData = Data(bytes: buffer, count: length)
let indexAfterMsghdr = MemoryLayout<if_msghdr>.stride + 1
let rangeOfToken = infoData[indexAfterMsghdr...].range(of: bsdData)!
let lower = rangeOfToken.upperBound
let upper = lower + MAC_ADDRESS_LENGTH
let macAddressData = infoData[lower..<upper]
let addressBytes = macAddressData.map{ String(format:"%02x", $0) }
return addressBytes.joined(separator: separator)
}
MACAddressForBSD(bsd: "en0")
Update to Martin R's entry. There are a couple of lines that won't compile with Swift 2.1.
Change:
let matchingDict = matchingDictUM.takeUnretainedValue() as NSMutableDictionary
To:
let matchingDict = matchingDictUM as NSMutableDictionary
Change:
let macAddressAsString = ":".join(macAddress.map( { String(format:"%02x", $0) } ))
To:
let macAddressAsString = macAddress.map( { String(format:"%02x", $0) } ).joinWithSeparator(":")
You can also use 'SystemConfiguration' framework
import SystemConfiguration
func collectMACAddresses() -> [String] {
guard let interfaces = SCNetworkInterfaceCopyAll() as? [SCNetworkInterface] else {
return []
}
return interfaces
.map(SCNetworkInterfaceGetHardwareAddressString)
.compactMap { $0 as String? }
}
DISCLAIMER: this is not production-ready. It would probably be rejected by the App Store. It's also subject to errors if the output of ifconfig changes in the future. I've made this because I lacked the skills to translate the C code given in the links. It does not replace a full Swift solution. That being said, it works...
Get ifconfig's output and parse it to get the MAC address associated with an interface (en0 in this example):
let theTask = NSTask()
let taskOutput = NSPipe()
theTask.launchPath = "/sbin/ifconfig"
theTask.standardOutput = taskOutput
theTask.standardError = taskOutput
theTask.arguments = ["en0"]
theTask.launch()
theTask.waitUntilExit()
let taskData = taskOutput.fileHandleForReading.readDataToEndOfFile()
if let stringResult = NSString(data: taskData, encoding: NSUTF8StringEncoding) {
if stringResult != "ifconfig: interface en0 does not exist" {
let f = stringResult.rangeOfString("ether")
if f.location != NSNotFound {
let sub = stringResult.substringFromIndex(f.location + f.length)
let range = Range(start: advance(sub.startIndex, 1), end: advance(sub.startIndex, 18))
let result = sub.substringWithRange(range)
println(result)
}
}
}
Right! Here is my attempt at a circular buffer (For use in a graphing program, using the canvas element). Have yet to get round to testing it out.
Question is - Can anyone see any flaws in my logic? Or bottlenecks?
/**
* A circular buffer class.
* #To add value -> bufferObject.addValue(xValue, yValue);
* #To get the First-in value use -> bufferObject.getValue(0);
* #To get the Last-in value use -> bufferObject.getValue(bufferObject.length);
**/
var circularBuffer = function (bufferSize) {
this.bufferSize = bufferSize;
this.buffer = new Array(this.bufferSize); // After testing on jPerf -> 2 x 1D array seems fastest solution.
this.end = 0;
this.start = 0;
// Adds values to array in circular.
this.addValue = function(xValue, yValue) {
this.buffer[this.end] = {x : xValue, y: yValue};
if (this.end != this.bufferSize) this.end++;
else this.end = 0;
if(this.end == this.start) this.start ++;
};
// Returns a value from the buffer
this.getValue = function(index) {
var i = index+this.start;
if(i >= this.bufferSize) i -= this.bufferSize; //Check here.
return this.buffer[i]
};
// Returns the length of the buffer
this.getLength = function() {
if(this.start > this.end || this.start == this.bufferSize) {
return this.xBuffer.length;
} else {
return this.end - this.start;
}
};
// Returns true if the buffer has been initialized.
this.isInitialized = function() {
if(this.end != this.start) return true;
else return false;
};
}
Please feel free to reuse this code.
Updated twice (and tested!).
Update: Found another implementation Circular buffer in JavaScript
Made class variables private, corrected old xBuffer reference. Will do more edits tonight.
/**
* A circular buffer class.
* #To add value -> bufferObject.addValue(xValue, yValue);
* #To get the First-in value use -> bufferObject.getValue(0);
* #To get the Last-in value use -> bufferObject.getValue(bufferObject.length);
**/
var circularBuffer = function (buffer_size) {
var bufferSize = buffer_size;
var buffer = new Array(bufferSize); // After testing on jPerf -> 2 x 1D array seems fastest solution.
var end = 0;
var start = 0;
// Adds values to array in circular.
this.addValue = function(xValue, yValue) {
buffer[end] = {x : xValue, y: yValue};
if (end != bufferSize) end++;
else end = 0;
if(end == start) start++;
};
// Returns a value from the buffer
this.getValue = function(index) {
var i = index+start;
if(i >= bufferSize) i -= bufferSize; //Check here.
return buffer[i];
};
// Returns the length of the buffer
this.getLength = function() {
if(start > end || start == bufferSize) {
return buffer.length;
} else {
return end - start;
}
};
// Returns true if the buffer has been initialized.
this.isInitialized = function() {
return (end != start) ? true : false;
};
}
I implemented Vogomatix's code above, and got a few bugs. The code writes off the end of the buffer, expanding the buffer size automatically, and the addValue function is bound to a particular type. I've adjusted the code to work with any object type, added some private subroutines to simplify, and added a function to dump the contents out to a string, with an optional delimiter. Also used a namespace.
What's missing is a removeValue() but it would be just a check of count to be greater than zero, then a call to _pop().
This was done because I needed a rolling, scrolling text buffer for inbound messages, that did not grow indefinitely. I use the object with a textarea, so I get behaviour like a console window, a scrolling text box that does not chew up memory indefinitely.
This has been tested with expediency in mind, in that I am coding quickly, posted here in the hope that fellow OverFlow-ers use and anneal the code.
///////////////////////////////////////////////////////////////////////////////
// STYLE DECLARATION
// Use double quotes in JavaScript
///////////////////////////////////////////////////////////////////////////////
// Global Namespace for this application
//
var nz = nz || {};
nz.cbuffer = new Object();
///////////////////////////////////////////////////////////////////////////////
// CIRCULAR BUFFER
//
// CREDIT:
// Based on...
// Vogomatix http://stackoverflow.com/questions/20119513/attempt-at-circular-buffer-javascript
// But re-written after finding some undocumented features...
/**
* A circular buffer class, storing any type of Javascript object.
* To add value -> bufferObject.addValue(obj);
* To get the First-in value use -> bufferObject.getValue(0);
* To get the Last-in value use -> bufferObject.getValue(bufferObject.length);
* To dump to string use -> bufferObject.streamToString(sOptionalDelimiter); // Defaults to "\r\n"
**/
nz.cbuffer.circularBuffer = function (buffer_size) {
var bufferSize = buffer_size > 0 ? buffer_size : 1; // At worst, make an array of size 1
var buffer = new Array(bufferSize);
var end = 0; // Index of last element.
var start = 0; // Index of first element.
var count = 0; // Count of elements
// 'Private' function to push object onto buffer.
this._push = function (obj) {
buffer[end] = obj; // Write
end++; // Advance
if (end == bufferSize) {
end = 0; // Wrap if illegal
}
count++;
}
// 'Private' function to pop object from buffer.
this._pop = function () {
var obj = buffer[start];
start++;
if (start == bufferSize) {
start = 0; // Wrap
}
count--;
return obj;
}
// Adds values to buffer.
this.addValue = function (obj) {
if (count < bufferSize) {
// Just push
this._push(obj);
}
else {
// Pop, then push
this._pop();
this._push(obj);
}
}
// Returns a value from the buffer. Index is relative to current notional start.
this.getValue = function (index) {
if (index >= count || index < 0) return; // Catch attempt to access illegal index
var i = index + start;
if (i >= bufferSize) {
i -= bufferSize;
}
return buffer[i];
}
// Returns the length of the buffer.
this.getLength = function () {
return count;
}
// Returns all items as strings, separated by optional delimiter.
this.streamToString = function (delim) {
delim = (typeof delim === "undefined") ? "\r\n" : delim; // Default syntax; Default to CRLF
var strReturn = "";
var once = 0;
var index = 0;
var read = index + start;
for (; index < count; ++index) {
if (once == 1) strReturn += delim.toString();
strReturn += buffer[read].toString();
read++;
if (read >= bufferSize) read = 0;
once = 1;
}
return strReturn;
}
}