Does setting CURLOPT_URL force to create a second FTP connection? - libcurl

I want to open a connection with an FTP server and download 2 different files. Names are totally different and I cannot use wildcards.
I expected I could set the hostname and the file, then call curl_easy_perform, then set the file again and call curl_easy_perform one last time.
However it seems I have to use the CURLOPT_URL which includes both the hostname and the filename.
My fear is that the following code (lacks the error checking just to be short here):
...
curl_easy_setopt(handle, CURLOPT_URL, "ftp://myserver//foo.dat");
curl_easy_perform(handle);
curl_easy_setopt(handle, CURLOPT_URL, "ftp://myserver//bar.png");
curl_easy_perform(handle);
opens the FTP connection twice, giving a lot of avoidable overhead.
So am I missing something here? Will libcurl notice that the hostname part is the same, thus avoiding to open the same connection twice? If not how can I open the connection only once?

Enabling CURLOPT_VERSBOSE showed that:
* Connection #0 to host 127.0.0.1 left intact
* Re-using existing connection! (#0) with host 127.0.0.1
* Connected to 127.0.0.1 (127.0.0.1) port 21 (#0)
* Request has same path as previous transfer
Also, wireshark showed that connection to port 21 is made only once and lasts throughout the whole transfer (including the two files).
However one connection per-file is made on another port because of the ftp passive mode, but I think this is not curl's fault.

Related

Slow Performance with libcurl when changing Ip Address

First time developing with libcurl and got some unexpected results:
I'm trying to reuse the same CURL handle in order to reuse it's connections associated with it. However, I noticed a huge performance drop when I constantly change the Ip address of my request.
When I keep the IP address unchanged everything is fine, I'm pretty sure there's something I'm missing, but I don't know what and where to search for.
Here's my code:
// curl init
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &RestClientPool::WriteCallBack); // custom write function
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 200L);
// perform request, curl handle is stored and reused
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(curl, CURLOPT_URL, req_url.c_str()); // here req_url is something like http://123.123.123.123:8080/api/api
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode res = curl_easy_perform(curl);
Problem:
say i have 3 hosts with ip: a, b and c, if i send requests to a,b,c,a,b,c,a... 100 times V.S. a,a,a,a,a,a... 100 times with the same handle, performance is around 9s to 1s (service on all hosts are identical, no host issues needs to be considered)
PS: I can tell that libcurl handle is reusing the connections by monitoring(and by verbose), because i monitored the servers. So, new connections when ip change shouldn't be the problem here.
Environment:
libcurl:
curl 7.86.0 (x86_64-pc-linux-gnu) libcurl/7.86.0 OpenSSL/1.0.2k-fips zlib/1.2.7
Release-Date: 2022-10-26
Protocols: dict file ftp ftps gophergophers http https imap imaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS HSTS HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL UnixSockets
os:
CentOS 7.6.1810
What I tried:
1、I trie using CURLOPT_RESOLVE(cause i thought it might have something do with DNS cache), but nothing changed.
2、I made three handle and fired off 3 threads, where each handle would request to same ip(host A for example) repeatedly(no handle were shared across threads). And it worked fine.
However, when I change the ip for each handle(thread 1 would now repeatedly make request to host A, thread 2 to B and thread 3 to C), the performance drop appears again.

What is the POSIX call to determine the intended IP of a redirected socket open request?

I am modifying my hosts file to change the IP address of (for example a database call) to a local proxy that I am writing.
10.1.2.3 localhost
10.1.2.4 localhost
I want the proxy listening on the socket to work out which machine the socket opening request intended to go to. eg in my client I am calling.
dbPort = 4000;
openDatabaseConnection("10.1.2.3", dbPort);
...
openDatabaseConnection("10.1.2.4", dbPort);
So both call on the same socket. I want my proxy server to listen on 4000 and redirect the one going to 10.1.2.3 to the correct server by intended IP address.
Is there a POSIX call to get this from the socket header?
My question is: What is the POSIX call to determine the intended IP of a redirected socket open request?
No there is no way of knowing which IP-address was used in the client program. The hosts-file defines a set of aliases, and the aliases are replaced with the actual address (in your case localhost) by the name/address resolver, making you lose all information about the alias used. There is no "redirection" made, the alias substitution is made before the client even connects.
The simplest way to solve your problem is not to use IP-address aliasing through the hosts file, but to use different port numbers.
You could probably also add "virtual" interfaces for the different addresses, and have the proxy-server listen for connections on both those interfaces.

Firebird remote connection failure

I have a C++ application that used to read the data from the Firebird SQL server.
when I changed port from 3050 to 3053 it shows error like
DB Error : 0 : Unable to complete network request to host "192.168.1.47".
Failed to establish a connection.
unknown Win32 error 10060
Invalid connection string attribute
conf file is changed like
# Type: string, integer
#
RemoteServiceName = gds_db
RemoteServicePort = 3053
Fb connection string is
Driver=Firebird/InterBase(r) driver;DBNAME=192.168.1.47:CWNPFB;PORT=3053;UID=SYSDBA;PWD=********
Is there any modification is required to solve this? Application can read the data if the port is 3050.
The problem is with your connection string:
You need to
Remove PORT=3053 from the connection string (this causes the "Invalid connection string attribute" message)
Modify DBNAME=192.168.1.47:CWNPFB to DBNAME=192.168.1.47/3053:CWNPFB (to specify the right port)
You might also want to comment out (or remove) the line RemoteServiceName = gds_db, because you are now instructing Firebird to listen on gds_db (== port 3050), and not on port 3053. I believe it usually listens on the last one configured in the config file, but I'm not sure that is always the case.
Is your firewall configuration correct for port 3053? Another service may runs on this special port.
You could do the following steps.
Try to run the application on the database server, please change the IP to 127.0.0.1 or localhost.
If step (1) works: check out the firewall
If step (1) doesn't work: maybe try another port, check whether Firebird is running

Populating source IP address in a raw socket to get a valid response

I am doing some basic network programming using c/c++. What I am trying to do is create packets with headers populated with my own values (instead of kernel) , send packet to some server and get a response. I was able to create the tcp/ip header structures and populate fields such as seq_num etc . As an example, I would send a SYN packet to a host at some port, and check if the host responds with a valid SYN_ACK.
I am wondering what needs to be put in for the source_address and source_port field in the ip/tcp header so that I get a valid response. Using local address (127.0.0.1) won't work right, cause the target machine won't be able to send a response.
I have to use raw_sockets only, can't use SOCK_STREAM etc. Using Linux OS.
The source IP address should be the ip address of interface from which you expect the packet to go out to reach the destination. To make things less complicated the source port can be any free port on your machine.
Also you need to take care of one more thing. Once you get the syn-ack back it will be also handled by the tcp stack of your machine and tcp stack will send a reset in response to that syn-ack. If you are on linux you can use iptables to drop the out going reset.
-MS

How to detect mysql server down status quickly

I have an application which connects a remote database server.
If mysql server stops for a reason and stars succesfully after that, my application cannot detect server status quickly. It takes nearly 20 seconds to reconnect to the database server. So my gui freezes. I do not want a gui freeze for 20 seconds
So far I tried
mysql_ping
mysql_real_connect
functions
MYSQL_OPT_RECONNECT
MYSQL_OPT_CONNECT_TIMEOUT
options
My enviroment is not multi-threaded. So
how to do a faster detection?
If you do networking synchronously, be prepared for freezes. For this very reason it makes sense to do data-manipulation in a separate thread.
You could try telnet to the mysql port (usually 3306). If you get a connection refused, mysql isn't listening.
Working.
root#XXXXXX:~# telnet localhost 3306
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
L
5.6.4-m7)#m#_8:W�hP5YBzaXs[MOmysql_native_password
Down.
root#XXXXXX:~# telnet localhost 3306
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
The refused message is almost instant.
As already discussed by others, i won't talk about using multiple threads or processes. Can you connect to your mysql server on tcp? That way in most scenario's you would receive a tcp fin immediately to indicate a closed connection, though at times this might not be the case even. But most robust applications do a proper close.
shell> mysql --protocol=TCP
MYSQL how to specify protocol
If server doesn't accept it, i believe it can be enabled from config settings.
However, this does not address scenarios such as server suddenly gets off the network, or you client's connection is down etc.