Access Docker API on Windows via Named Pipes - c#

According to the Docker for Windows FAQ, " clients can connect to the Docker Engine through a named pipe: npipe:////./pipe/docker_engine"
I have been trying to connect to the API via named pipes to no avail:
public class DockerNamedPipeTest
{
private const string PIPE_PATH = "docker_engine";
public void Test()
{
using (NamedPipeClientStream pipeClient =
new NamedPipeClientStream(
".",
PIPE_PATH,
PipeDirection.InOut,
PipeOptions.WriteThrough,
TokenImpersonationLevel.Impersonation))
{
pipeClient.Connect(30);
Send(pipeClient);
Receive(pipeClient);
}
}
public void Send(NamedPipeClientStream pipeClient)
{
if (pipeClient.IsConnected)
{
byte[] buffer = Encoding.UTF8.GetBytes("GET /containers/json");
pipeClient.Write(buffer, 0, buffer.Length);
pipeClient.WaitForPipeDrain();
pipeClient.Flush();
}
}
public void Receive(NamedPipeClientStream pipeClient)
{
string result = string.Empty;
if (pipeClient.IsConnected && pipeClient.CanRead)
{
do
{
byte b = (byte)pipeClient.ReadByte(); // <-- Hangs here
result += Convert.ToChar(b).ToString();
}
while (!pipeClient.IsMessageComplete);
}
Console.WriteLine(result);
}
}
Can anyone tell me what I am doing wrong?

Microsoft's .NET client library for Docker supports named pipes, have you looked at that?
Here's an example:
using Docker.DotNet;
DockerClient client = new DockerClientConfiguration(new Uri("npipe://./pipe/docker_engine"))
.CreateClient();

It turns out that the answer can be found inside the source of the Docker.DotNet code, specifically in the DockerPipeStream.cs class in the method called CloseWrite():
(https://github.com/Microsoft/Docker.DotNet/blob/master/src/Docker.DotNet/DockerPipeStream.cs)
// The Docker daemon expects a write of zero bytes to signal the end of writes. Use native
// calls to achieve this since CoreCLR ignores a zero-byte write.
I adapted this method to my code and the code no longer hangs.
I now get a 400 Bad Request but at least now I know why the communication with the docker daemon was hanging. It would have been nice if the Docker for Windows FAQ had mentioned this nuance.

Related

Xamarin Mac FFmpeg launch path not accessible

I have a Xamarin Forms project with Mac support and I am trying to implement FFmpeg, so I have downloaded the Static build from its official page and added it as in the resources folder of the Mac project with the build action in Content, then I have created a service that will basically remove the audio from a video that I indicate in a path with a FFmpeg command, to do the service I have based on the following answer and I have adapted it to C #:
https://stackoverflow.com/a/37422688/8496520
The problem is that when I try to execute the command I get the following error:
"NSInvalidArgumentException: launch path not accessible"
And I can't find out why this happens, I use the following code in the service (The error occurs when calling the Launch () method of the NSTask):
public void ExecuteFFmpeg()
{
try
{
var launchPath = NSBundle.MainBundle.PathForResource("ffmpeg", ofType: "");
var compressTask = new NSTask();
compressTask.LaunchPath = launchPath;
compressTask.Arguments = new string[] {
"-i",
"downloads/test.mp4",
"-c",
"copy",
"-an",
"nosound.mp4" };
compressTask.StandardInput = NSFileHandle.FromNullDevice();
compressTask.Launch();
compressTask.WaitUntilExit();
}
catch (Exception ex)
{
}
I have also uploaded the project to GitHub in case someone needs to consult the repository in its entirety: https://github.com/nacompllo/FFmpegSample
If you are not tied to NSTask you could use CliWrapper instead.
public static async ValueTask FfmpegRemoveAudio(string ffmpegPath, string inputFilePath, string outputFilePath)
{
await Cli.Wrap(ffmpegPath).WithArguments(new[] { "-i", inputFilePath, "-c", "copy", "-an", outputFilePath }).ExecuteAsync();
}
Beside of CliWrapper I also tested FfmpegCore and FFmpget.NET that also threw some similar exceptions like you describe. I have no glue, why they behavior different. See the complete working POC for details.

'The method or operation is not implemented' in Xamarin Forms when using Named Pipe

First of all, hello everyone as it's my first post.
Getting to the case: I'm trying to send message between two apps - one on computer and the other on Android through Named Pipes and executing the following code ends up with an "The method or operation is not implemented" exception.
The code fragment is an Button Clicked event - the idea is to open a pipe, send through a button text (buttons texts are "Up", "Down", "Left" and "Right) and then close the pipe.
I've tested this and it works as long as the project is a WinForms project using standard System.IO.Pipes.
private void Button_Clicked(object sender, EventArgs e)
{
header.Text = "Pressed: " + (sender as Button).Text;
try
{
using (var pipeClient = new NamedPipeClientStream(SERVERNAME, "testpipe", PipeDirection.Out))
{
header.Text = "Connected with: " + SERVERNAME;
using (var stream = new StreamWriter(pipeClient))
{
pipeClient.Connect();
stream.Write((sender as Button).Text);
}
}
}
catch(Exception exc)
{
Debug.WriteLine(exc.StackTrace);
Debug.WriteLine(exc.Message);
}
}
The line creating an exception is
using (var pipeClient = new NamedPipeClientStream(SERVERNAME, "testpipe", PipeDirection.Out))
I've tested servername (const string) being an IP address, "localhost" or computer name and nothing changes.
Am I doing something wrong or is this a Xamarin error?
Looking in the mono source for NamedPipeClientStream this is only implemented for win32. So it makes sense that you are getting a NotImplementedException.
Not every API that you have available on the desktop is supported on mobile.
Instead of using NamedPipeClientStream you could use TCP Sockets or something more high level as a ASP.NET Core server exposing what you need as a RESTful API or similar and consuming it with HttpClient or any other REST client.

tranfer file via bluetooth to iphone using 32feet

I am trying to transfer a file to my iphone using 32feet bluetooth, but cannot seem to get past the ObexWebResponse.
I have read many post on this but none of the solutions seem to work for me.
The Error i get is
// Connect failed
// The requested address is not valid in its context "address:Guid"
private BluetoothClient _bluetoothClient;
private BluetoothComponent _bluetoothComponent;
private List<BluetoothDeviceInfo> _inRangeBluetoothDevices;
private BluetoothDeviceInfo _hlkBoardDevice;
private EventHandler<BluetoothWin32AuthenticationEventArgs> _bluetoothAuthenticatorHandler;
private BluetoothWin32Authentication _bluetoothAuthenticator;
public BTooth() {
_bluetoothClient = new BluetoothClient();
_bluetoothComponent = new BluetoothComponent(_bluetoothClient);
_inRangeBluetoothDevices = new List<BluetoothDeviceInfo>();
_bluetoothAuthenticatorHandler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(_bluetoothAutenticator_handlePairingRequest);
_bluetoothAuthenticator = new BluetoothWin32Authentication(_bluetoothAuthenticatorHandler);
_bluetoothComponent.DiscoverDevicesProgress += _bluetoothComponent_DiscoverDevicesProgress;
_bluetoothComponent.DiscoverDevicesComplete += _bluetoothComponent_DiscoverDevicesComplete;
ConnectAsync();
}
public void ConnectAsync() {
_inRangeBluetoothDevices.Clear();
_hlkBoardDevice = null;
_bluetoothComponent.DiscoverDevicesAsync(255, true, true, true, false, null);
}
private void PairWithBoard() {
Console.WriteLine("Pairing...");
bool pairResult = BluetoothSecurity.PairRequest(_hlkBoardDevice.DeviceAddress, null);
if (pairResult) {
Console.WriteLine("Success");
Console.WriteLine($"Authenticated equals {_hlkBoardDevice.Authenticated}");
} else {
Console.WriteLine("Fail"); // Instantly fails
}
}
private void _bluetoothComponent_DiscoverDevicesProgress(object sender, DiscoverDevicesEventArgs e) { _inRangeBluetoothDevices.AddRange(e.Devices); }
private void _bluetoothComponent_DiscoverDevicesComplete(object sender, DiscoverDevicesEventArgs e) {
for (int i = 0; i < _inRangeBluetoothDevices.Count; ++i) {
if (_inRangeBluetoothDevices[i].DeviceName == "Uranus") {
_hlkBoardDevice = _inRangeBluetoothDevices[i];
PairWithBoard();
TransferFile();
return;
}
}
// no devices found
}
private void _bluetoothAutenticator_handlePairingRequest(object sender, BluetoothWin32AuthenticationEventArgs e) {
e.Confirm = true; // Never reach this line
}
// not working
// transfers a file to the phone
public void TransferFile() {
string file = "E:\\test.txt",
filename = System.IO.Path.GetFileName(file);
string deviceAddr = _hlkBoardDevice.DeviceAddress.ToString();
BluetoothAddress addr = BluetoothAddress.Parse(deviceAddr);
_bluetoothClient.Connect(BluetoothAddress.Parse(deviceAddr), BluetoothService.SerialPort);
Uri u = new Uri($"obex://{deviceAddr}/{file}");
ObexWebRequest owr = new ObexWebRequest(u);
owr.ReadFile(file);
// error:
// Connect failed
// The requested address is not valid in its context ...
var response = (ObexWebResponse)owr.GetResponse();
Console.WriteLine("Response Code: {0} (0x{0:X})", response.StatusCode);
response.Close();
}
The pairing and authentication works just fine, and I can get the BluetoothService.Handsfree to make a call for me but the transferring of the file fails. Not knowing what the actual error is, I tried almost every service available with no luck.
Can you help me figure out what is going on? This is my first attempt working with Bluetooth services so I still have a ton to learn.
Is it possible to transfer a file from iPhone to Windows desktop via Bluetooth?
However, in case you need to transfer media files (images, videos, etc) from Android device, you can use ObexListener class provided by 32Feet library for this purpose, and then you can simply call _obexListener.GetContext() method that will block and wait for incoming connections.
Once a new connection is received, you can save the received file to local storage, as shown in the below example:
ObexListener _listener = new ObexListener();
_listener.Start();
// This method will block and wait for incoming connections
ObexListenerContext _context = _listener.GetContext();
// Once new connection is received, you can save the file to local storage
_context.Request.WriteFile(#"c:\sample.jpg");
NOTE: When working with OBEX on Windows, make sure to disable the "Bluetooth OBEX Service" Windows service, in order not to let it handle the incoming OBEX requests instead of the desired application.
I walked away from this for a while. and started Trying to use xamiren but then had to create a virtual Mac so that I could have the apple store to just load software on my phone. From there xamerin 'should' work well but its another field and tons more to firgure out.

Creating a web server in C# UWP

I am writing a web server as a Universal Windows Platform app in C#. Here is my code so far:
sealed partial class App : Application
{
int port = 8000;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
StartServer();
}
private void StartServer()
{
StreamSocketListener listener = new StreamSocketListener();
listener.BindServiceNameAsync(port.ToString());
Debug.WriteLine("Bound to port: " + port.ToString());
listener.ConnectionReceived += async (s, e) =>
{
Debug.WriteLine("Got connection");
using (IInputStream input = e.Socket.InputStream)
{
var buffer = new Windows.Storage.Streams.Buffer(2);
await input.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.Partial);
}
using (IOutputStream output = e.Socket.OutputStream)
{
using (Stream response = output.AsStreamForWrite())
{
response.Write(Encoding.ASCII.GetBytes("Hello, World!"), 0, 1);
}
}
};
}
}
I tried connecting to the server using this address:
http://127.0.0.1:8000/C:/pathtohtmlfile/htmlfile.html
However, the connection times out. I am not sure if it is a problem with the C# code or with something else.
Raymond Zuo's solution really works. But the main thing not to forget are capabilities in Packages.appxmanifest. In order to run the server in Private networks one should add:
<Capability Name="privateNetworkClientServer" />
And in order to run the server in Public network:
<Capability Name="internetClientServer" />
If you want to host a server in uwp app, be sure these things:
your device which run this code (Device A) and device which your web browser run (Device B) must at a same LAN. And you cannot use the browser in Device A to access your service.
use WIFI to access your service.
your app must be at the state of running.
you should write a method to get ip address, but not 127.0.0.1:
public static string FindIPAddress()
{
List<string> ipAddresses = new List<string>();
var hostnames = NetworkInformation.GetHostNames();
foreach (var hn in hostnames)
{
//IanaInterfaceType == 71 => Wifi
//IanaInterfaceType == 6 => Ethernet (Emulator)
if (hn.IPInformation != null &&
(hn.IPInformation.NetworkAdapter.IanaInterfaceType == 71
|| hn.IPInformation.NetworkAdapter.IanaInterfaceType == 6))
{
string ipAddress = hn.DisplayName;
ipAddresses.Add(ipAddress);
}
}
if (ipAddresses.Count < 1)
{
return null;
}
else if (ipAddresses.Count == 1)
{
return ipAddresses[0];
}
else
{
return ipAddresses[ipAddresses.Count - 1];
}
}
It is possible to host a web service on phone/tablet.
It is possible to host a web service in a Window Universal App. I followed the example from http://www.dzhang.com/blog/2012/09/18/a-simple-in-process-http-server-for-windows-8-metro-apps , also followed the three first steps from Raymond Zuo's solution and finally I also put the firewall down. Unfortunately, I was not able to run on localhost even though I followed the answers from here Cannot connect to localhost in windows store application . I am currently doing java http requests to the Universal Platform App. Definitely, server and client seem to be required to run on different hosts.

How to start an Amazon EC2 instance programmatically in .NET

I have been attempting to start an instance of EC2 in C# without luck.
When passing in an instance id to start the instance I get an error that the instance cannot be found despite that I am passing in an instance ID that I have obtained from the object property.
Amazon made huge efforts to integrate its AWS Cloud .Net SDK To VS2008 & VS 2010
1 - Download and Install the AWS SDK msi
2 - Create an AWS Console project, enter your credentials (available from your AWS Console under your login name menu on the top right corner)
3 - Add the following code (see below images).
4 - Your're done. It's very straightforward. You can check the programmatic start/stop success by refreshing your AWS Console Screen.
AmazonEC2 ec2 = AWSClientFactory.CreateAmazonEC2Client();
//Start Your Instance
ec2.StartInstances(new StartInstancesRequest().WithInstanceId("i-00000000"));
//Stop it
ec2.StopInstances(new StopInstancesRequest().WithInstanceId("i-00000000"));
You just need to replace "i-00000000" by your instance Id (available in your AWS Management Console)
Hope this helps those googling this and stumbling upon this question (as I did myself) start off quickly. Following these simple steps via these wizards will spare you considerable headaches.
Try something like this with the AWSSDK to start new instances of an "image id":
RunInstancesResponse response = Client.RunInstances(new RunInstancesRequest()
.WithImageId(ami_id)
.WithInstanceType(instance_type)
.WithKeyName(YOUR_KEYPAIR_NAME)
.WithMinCount(1)
.WithMaxCount(max_number_of_instances)
.WithUserData(Convert.ToBase64String(Encoding.UTF8.GetBytes(bootScript.Replace("\r", ""))))
);
(Note: The .WithUserData() is optional and is used above to pass a short shell script.)
If the call is successful the response should contain a list of instances. You can use something like this to create a list of "instance ids":
if (response.IsSetRunInstancesResult() && response.RunInstancesResult.IsSetReservation() && response.RunInstancesResult.Reservation.IsSetRunningInstance())
{
List<string> instance_ids = new List<string>();
foreach (RunningInstance ri in response.RunInstancesResult.Reservation.RunningInstance)
{
instance_ids.Add(ri.InstanceId);
}
// do something with instance_ids
...
}
Be mindful that Amazon AWS instances exist only in one region. If your instance id i-12345 is in the EU-West-1 region, and you just make a new EC2Client and tell the client to start i-12345 it may well complain that it cannot find that instance, because the client started up in the us-east-1 region, which does not have i-12345 instance.
Your call that creates the client should specify the region, if it is not the default region (I've no idea which AWS region is default, so I specify every time):
AmazonEC2 ec2 = AWSClientFactory.CreateAmazonEC2Client(
new Amazon.EC2.AmazonEC2Config().WithServiceURL("https://eu-west-1.ec2.amazonaws.com")
);
Ok, this is the FULL, end-to-end instructions.
1. Install AWSSDK.Core and AWSSDK.EC2 using Nuget Package Manager.
2. Then copy this whole class to your project. AccessKey and Secret are obtained in AWS IAM. You will need to ensure the user you create has "AmazonEC2FullAccess" (You can probably use a lower-level permission policy, I am just lazy here :D). region is your AW S EC2 instance region. and Instance ID can be found in the EC2 dashboard list. Simple, works perfectly... You can also write extra code to manage the response object.
3. Be mindful if you are behind a proxy, you will have to configure it (I havent included code here).
public class AWSClass : IDisposable
{
Amazon.EC2.AmazonEC2Client _client;
public AWSClass(string region, string AccessKey, string Secret)
{
RegionEndpoint EndPoint = RegionEndpoint.GetBySystemName(region);
Amazon.Runtime.BasicAWSCredentials Credentials = new Amazon.Runtime.BasicAWSCredentials(AccessKey, Secret);
_client = new AmazonEC2Client(Credentials, EndPoint);
}
public void Dispose()
{
_client = null;
}
public void StopInstance(string InstanceID)
{
StopInstancesResponse response = _client.StopInstances(new StopInstancesRequest
{
InstanceIds = new List<string> {InstanceID }
});
//Can also do something with the response object too
}
public void StartInstance(string InstanceID)
{
StartInstancesResponse response = _client.StartInstances(new StartInstancesRequest
{
InstanceIds = new List<string> { InstanceID }
});
}
}
try this.
var startRequest = new StartInstancesRequest
{
InstanceIds = new List<string>() { instanceId }
};
bool isError = true;
StartInstancesResponse startInstancesResponse = null;
while (isError)
{
try
{
startInstancesResponse=amazonEc2client.StartInstances(startRequest);
isError = false;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
isError = true;
}
}

Categories

Resources