Firebird connection to remote server using FbConnectionStringBuilder - client-server

We're having trouble connecting to a remote Firebird server using the .NET provider FbConnectionStringBuilder class. We can connect to a local database file in either embedded or server mode however when it comes to establishing a connection to a remote server we can't establish the connection.
We assign properties of the FbConnectionStringBuilder class with the following code (server mode). I have omitted the code which assigns properties for embedded mode.
var cs = new FbConnectionStringBuilder
{
Database = databaseSessionInfo.PathAbsoluteToDatabase,
Charset = "UTF8",
Dialect = 3,
};
cs.DataSource = databaseSessionInfo.Hostname;
cs.Port = databaseSessionInfo.Port;
cs.ServerType = (FbServerType)databaseSessionInfo.Mode;
cs.Pooling = true;
cs.ConnectionLifeTime = 30;
if (databaseSessionInfo.UseCustomUserAccount)
{
cs.UserID = databaseSessionInfo.Username;
cs.Password = databaseSessionInfo.Password;
}
else
{
cs.UserID = Constants.DB_DefaultUsername;
cs.Password = Constants.DB_DefaultPassword;
}
Pretty straightforward. Our software contains a connection configuration screen whereby a user can supply different connection properties. These properties get assigned to the FbConnectionStringBuilder class using the code above.
The connection builder class outputs a connection string in the following format:
initial catalog="P:\Source\database.fdb";character set=UTF8;dialect=3;data source=localhost;port number=3050;server type=Default;pooling=True;connection lifetime=30;user id=USER;password=example
However literature on Firebird connection strings as indicated on this page (Firebird Connection Strings) talk of a different structure. I can only assume the FbConnectionStringBuilder class builds a Firebird connection string satisfying the requirements of Firebird.
Does the FbConnectionStringBuilder class append the hostname to the connection string correctly?
The Firebird server is running on the server. I assume there is no need to install it on the client?
What libraries need to be installed with the client to support a remote server connection?
Are we doing this right?
Any advice is appreciated.

Answering your questions:
1) Yes it will.
2) Correct, the client library will connect over the network.
3) If you use the ADO library, just FirebirdSql.Data.FirebirdClient.dll
4) Maybe, I dont know if this will help but this is how I connect.
FbConnectionStringBuilder ret = new FbConnectionStringBuilder();
ret.DataSource = Host;
ret.Port = Port;
ret.Database = Database;
ret.UserID = User;
ret.Password = Password;
ret.Charset = CharacterSet;
FbConnection ret = new FbConnection(connectionString);
Interestingly, what is the absolute path you are providing to the StringBuilder ? Is it the server absolute path, or some kind of network mapped drive?
Also, I assume you've reviewed firewall settings and allowing port 3050 inbound.

Related

Embarcadero Rad Studio Firemonkey Indy POP3 IPv6 socket error 11004

I have the following problem. I use Embarcadero Rad Studio 10.1 Berlin Firemonkey. I want to connect to a POP3 server within an IPv6 network where IPv4 is not enabled and I get the socket error # 11004 error. My code is:
int port = 110;
pop3->Host = ...
pop3->Username = ...
pop3->Password = ..
pop3->AuthType = patUserPass;
pop3->IOHandler = iOHandlerStack;
iOHandlerStack->IPVersion = TIdIPVersion::Id_IPv6;
pop3->UseTLS = utNoTLSSupport;
pop3->Port = port;
iOHandlerStack->Port = port;
try
{
pop3->ConnectTimeout = 5000;
pop3->Connect();
int msgc = pop3->CheckMessages();
pop3->Disconnect();
ShowMessage("OK: " + IntToStr(msgc));
}
catch (Exception &exc)
{
ShowMessage(exc.Message);
}
If I use the application within an IPv4 network then after connecting the IPVersion property is set to Id_IPv4 automatically and there is no problem.
Interesting thing is that the following code works within IPv6 network:
IdTCPClient->IPVersion = TIdIPVersion::Id_IPv6;
IdTCPClient->Host = ...
IdTCPClient->Port = 80;
IdTCPClient->Connect();
IdTCPClient->Disconnect();
ShowMessage("OK");
Any suggestion?
You need to set the pop3->IPVersion property (which is inherited from TIdTCPClient) instead of the iOHandlerStack->IPVersion property directly.
Connect() overrides the IOHandler's IPVersion property value with the higher layer TIdTCPClient::IPVersion property value.
So, if you are leaving pop3->IPVersion to its default value of Id_IPv4, that would explain why you can't connect using IPv6. And why your TIdTCPClient example works.
Also, you don't need to set the iOHandlerStack->Port property manually, Connect() handles that as well.

What are the AppName, AppPublisher and AppVersion header values for a WSE 2012 R2 WebApi call?

I'm trying to query my Server 2012 Essentials R2 server to determine the most recent Client Backup time for a given Device, so I can display nag screens at signon for forgetful users. (They're on laptops, so I can't depend on the machine being available during the automatic window.)
The closest thing in the way of documentation I've been able to find is this: (https://msdn.microsoft.com/en-us/library/jj713757.aspx)
GET services/builtin/DeviceManagement.svc/devices/index/{index}/count/{count}
But it requires a preceding call to get the token: (https://msdn.microsoft.com/en-us/library/jj713753.aspx)
GET https://www.contoso.com/services/builtin/session.svc/login HTTP/1.1
Accept: application/xml
Host: servername
Authorization: Basic VXNlcjpQYXNzd29yZCE=
AppName: Sample App Name
AppPublisher: publisher
AppVersion: 1.0
Does anyone know what the values for those last three headers should be—or how to discover them—for a standard WSE 2012 R2 installation? The documentation provides no assistance here.
Or if someone knows a better way to accomplish this, please let me know.
OK, I got it working. The code is below.
As it turns out, the value of the AppName header is irrelevant—it can be any string, but it can't be empty.
I already knew it couldn't be empty from a look at the WSE source in Wssg.WebApi.Framework in the GAC, but the code is decoupled to the point that it's next to impossible to find out what process picks up the the RemoteConnectionClientInfo object once it gets dropped into the HTTP session.
The part that was misleading me was—go figure—the documentation itself.
There's a bang (!) after the password on the Authentication page, suggesting that it should trail the actual password prior to encoding. This was why I was getting an authentication error, which in turn I was (mistakenly) attributing to the statement in the documentation: "Add Appname, Apppublisher, and Appversion values in HTTP header fields. These values are also required to log on."
So once I cleared all that up, I sailed right in.
And there are other errors in the documentation. On the Devices page we are told that the Host header should be set to the domain name, and that a Content-Length header should be added.
These are both incorrect. The Host header should be the server's hostname and there should be no Content-Length header (that's a response header, not a request header).
AND...! After all this, I find that the Device info returned doesn't contain the most recent backup time. I'll have to dig further for that. But at least now I can connect.
So Microsoft's incomplete, inaccurate and sloppy documentation has cost me a day's work. Hopefully somebody else can use this and avoid the pain I went through.
Module Main
Public Sub Main()
Dim aCredentials() As Byte
Dim _
oAuthenticateUri,
oDeviceListUri As Uri
Dim _
sCanary,
sCookie,
sDevices As String
aCredentials = Encoding.ASCII.GetBytes($"{USERNAME}:{PASSWORD}")
Using oClient As New HttpClient
oAuthenticateUri = New Uri($"https://{HOST}/services/builtin/session.svc/login")
oDeviceListUri = New Uri($"https://{HOST}/services/builtin/devicemanagement.svc/devices/index/0/count/99")
oClient.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/xml"))
oClient.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Basic", Convert.ToBase64String(aCredentials))
oClient.DefaultRequestHeaders.Host = HOST
oClient.DefaultRequestHeaders.Add("AppPublisher", String.Empty)
oClient.DefaultRequestHeaders.Add("AppVersion", String.Empty)
oClient.DefaultRequestHeaders.Add("AppName", "None")
Using oAuthenticateResponse As HttpResponseMessage = oClient.GetAsync(oAuthenticateUri).Result
If oAuthenticateResponse.IsSuccessStatusCode Then
sCanary = oAuthenticateResponse.Headers.Single(Function(Pair) Pair.Key = CANARY_HEADER).Value(0)
sCookie = Split(oAuthenticateResponse.Headers.Single(Function(Pair) Pair.Key = COOKIE_HEADER).Value(0), ";")(0)
oClient.DefaultRequestHeaders.Clear()
oClient.DefaultRequestHeaders.Host = HOST
oClient.DefaultRequestHeaders.Add(CANARY_HEADER, sCanary)
oClient.DefaultRequestHeaders.Add(COOKIE_HEADER, sCookie)
Using oDeviceListResponse As HttpResponseMessage = oClient.GetAsync(oDeviceListUri).Result
If oDeviceListResponse.IsSuccessStatusCode Then
sDevices = oDeviceListResponse.Content.ReadAsStringAsync.Result
Else
Console.WriteLine("{0} ({1})", oDeviceListResponse.StatusCode, oDeviceListResponse.ReasonPhrase)
End If
End Using
Else
Console.WriteLine("{0} ({1})", oAuthenticateResponse.StatusCode, oAuthenticateResponse.ReasonPhrase)
End If
End Using
End Using
End Sub
Private Const CANARY_HEADER As String = "Canary"
Private Const COOKIE_HEADER As String = "Set-Cookie"
Private Const USERNAME As String = "domain.admin"
Private Const PASSWORD As String = "admin.password"
Private Const HOST As String = "server"
End Module

Serial Ports /dev/tty.* are not working when /dev/cu.* ports are accessed firstly

I am trying to create a Processing application connected with an Arduino.
Due to the fact that I want the connection between the two to be established automatically, meaning that I do not specify the name of the port, but I'm using Serial.list() to get the names of the ports available and then with a for loop I will check which one is printing the correct string.
The problem is that when I access firstly the /dev/cu.* then all the /dev/tty.* ports are busy and vice versa. This is quite strange and I do not want this to happen.
You should be able to use one(/dev/tty.*) or the other(/dev/cu.*), but not both at the same time as they might point to the same resource in different ways.
I recommend listing the ports, checking the port prefix (agains let's say /dev/tty.*, but not /dev/cu.*), initialising the Serial port, then exiting the loop that traverses the listed serial ports:
import processing.serial.*;
Serial arduino;
final int BAUD_RATE = 9600;
void setup(){
String[] ports = Serial.list();
for(int i = 0 ; i < ports.length; i++){//go through each port
if(ports[i].contains("tty.usbmodem")){//find one that looks like an Arduino on OSX
try{
arduino = new Serial(this,ports[i],BAUD_RATE);//initialize the connection
i = ports.length;//exit the loop, break; should also work
println("Arduino connection succesfully initialized");
}catch(Exception e){
System.err.println("Error opening Serial port!\nPlease check USB connection and ensure the port is not already open in another application.");
e.printStackTrace();
}
}
}
if(arduino == null) System.err.println("Serial connection to Arduino failed!");
}

Error while configuring EMS with Database in Fault Tolerant mode

I am trying to setup my EMS in FT Mode, I have configured all the parameters in the 2 EMS config files.
But Im getting the warning:
Unable to initialize fault tolerant connection, remote server returned 'invalid user name'
Servername and password are exactly the same in both config files,so I don't know where the error is.
I am attaching the EMS config files that i am using for the EMS servers:
tibemsd.conf:
authorization = enabled
password =
server=EMS-HakanLAL
listen=tcp://7222
Ft_active=tcp://8222
users = users.conf
groups = groups.conf
topics = topics.conf
queues = queues.conf
acl_list = acl.conf
factories = factories.conf
routes = routes.conf
bridges = bridges.conf
transports = transports.conf
tibrvcm = tibrvcm.conf
durables = durables.conf
channels = channels.conf
stores = stores.conf
store = "C:/temp"
tibemsdft.conf:
authorization = enabled
password =
server=EMS-HakanLAL
listen=tcp://8222
Ft_active=tcp://7222
users = C:\Tibco\ems\8.1\BackUp\users.conf
groups = C:\Tibco\ems\8.1\BackUp\groups.conf
topics = C:\Tibco\ems\8.1\BackUp\topics.conf
queues = C:\Tibco\ems\8.1\BackUp\queues.conf
acl_list = C:\Tibco\ems\8.1\BackUp\acl.conf
factories = C:\Tibco\ems\8.1\BackUp\factories.conf
routes = C:\Tibco\ems\8.1\BackUp\routes.conf
bridges = C:\Tibco\ems\8.1\BackUp\bridges.conf
transports = C:\Tibco\ems\8.1\BackUp\transports.conf
tibrvcm = C:\Tibco\ems\8.1\BackUp\tibrvcm.conf
durables = C:\Tibco\ems\8.1\BackUp\durables.conf
channels = C:\Tibco\ems\8.1\BackUp\channels.conf
stores = C:\Tibco\ems\8.1\BackUp\stores.conf
store = "C:\ProgramData\TIBCO3\tibco\cfgmgmt\ems\data"
your tibemsd.conf and tibemsdft.conf looks fine. What you are probably missing is registering the server-name as a user within the users.conf.
If you make that entry, both servers should be able to connect to each other.

Get FQDN in C# running on Mono

I'm using Xamarin.mac. I need to get the fully qualified domain name of the local computer. On Windows this code works:
public string GetFQDN()
{
string domainName = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
string hostName = Dns.GetHostName();
string fqdn = "";
if (!hostName.Contains(domainName))
fqdn = hostName + "." + domainName;
else
fqdn = hostName;
return fqdn;
}
On a mac this code causes this error: System.NotSupportedException: This platform is not supported.
So, what is the equivalent in Xamarin.mac? Or just in Mono?
Just getting the computer name would be a good start.
To do this, you can pretty much do the same you'd do in C on a UNIX system, which is to retrieve the hostname with gethostname() and then use a DNS lookup to find the canonical network name for the host. Luckily, System.Net has ready-made calls for this. The following code should work on both OS X and Linux (in fact, on Linux it is more or less what hostname --fqdn does):
using System;
using System.Net;
class Program {
static void Main() {
// Step 1: Get the host name
var hostname = Dns.GetHostName();
// Step 2: Perform a DNS lookup.
// Note that the lookup is not guaranteed to succeed, especially
// if the system is misconfigured. On the other hand, if that
// happens, you probably can't connect to the host by name, anyway.
var hostinfo = Dns.GetHostEntry(hostname);
// Step 3: Retrieve the canonical name.
var fqdn = hostinfo.HostName;
Console.WriteLine("FQDN: {0}", fqdn);
}
}
Note that with a misconfigured DNS, the DNS lookup may fail, or you may get the rather useless "localhost.localdomain".
If you wish to emulate your original approach, you can use the following code to retrieve the domainname:
var domainname = new StringBuilder(256);
Mono.Unix.Native.Syscall.getdomainname(domainname,
(ulong) domainname.Capacity - 1);
You will need to add the Mono.Posix assembly to your build for this.

Resources