My ++ program connects to my FTP server and does some stuff which takes about 10 minutes. I want that when the connection is lost, the program waits until the connection is back then resumes. Here's the code I made (incomplete, please read comments):
#include <WinINet.h> //and other headers
HINTERNET hIntSession;
HINTERNET hFtpSession;
using namespace std;
void ResetConnection() {
if (hIntSession != NULL) InternetCloseHandle(hIntSession); //Do I need to add this line?
do {
if ((hIntSession = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0)) == NULL) continue;
hFtpSession = InternetConnect(hIntSession, "x.example.com", 21, "user", "pass", INTERNET_SERVICE_FTP, 0, 0);
if (hFtpSession == NULL) {
InternetCloseHandle(hIntSession); continue;
}
} while (FALSE);
}
int main() {
ResetConnection();
/*
FTP stuff
if(is not connected) ResetConnection();
FTP stuff
if(is not connected) ResetConnection();
and so on ...
*/
InternetCloseHandle(hConnect);
}
Also, I don't want to use extra memory, so maybe I should add more of "InternetCloseHandle()" function.
Please do not ask me to install a third party library.
Related
I am creating a client connection using Windows XP as a server, and clients (8 clients) are Windows NT.
However, only 2 clients can connect to the server.
I also tried it using Windows Server 2003 as a server, and Windows XP for the clients. With this configuration, all 8 clients can connect to the server.
Is there a limitation on the connection when using Windows XP as a server?
My error code from GetLastError() is 71 (ERROR_REQ_NOT_ACCEP, "No more connections can be made to this remote computer at this time because there are already as many connections as the computer can accept.")
Below is my code:
BOOL CClientPipeInstance::Write(LPCTSTR szData){
ASSERT(szData);
ASSERT(AfxIsValidString(szData));
DWORD dwDataLen,
dwError;
CSleeper ss;
CSecurityToken sa;
if (m_csPipename.IsEmpty())
return FALSE;
try
{
if (m_hPipe == HANDLE(NULL))
{
if (WaitNamedPipe(m_csPipename, PIPE_WAIT_TIME))
{
while (TRUE)
{
if ((m_hPipe = CreateFile(m_csPipename, GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
{
output("Create Pipe File OK");
m_isPipeOn = true;
return WriteFile(m_hPipe, szData, _tcslen(szData), &dwDataLen, NULL);
}
else if (GetLastError() == ERROR_PIPE_BUSY)
{
ss.Sleep(50);
continue;
}
else
{
warning("Create Pipe File is NOT OK");
return FALSE;
}
}
}
warning("PIPE Wait Time Out with ErrorNum %d", GetLastError() );
return FALSE;
}
else if (WriteFile(m_hPipe, szData, _tcslen(szData), &dwDataLen, NULL) == 0)
{
dwError = GetLastError();
warning("Error Broken Pipe with ErrorNum %d", dwError);
if (dwError == ERROR_BROKEN_PIPE)
{
// Our pipe went away
CloseHandle(m_hPipe);
m_hPipe = HANDLE(NULL);
m_isPipeOn = false;
return FALSE;
}
}
}
catch(...)
{
warning("Caught unknown exception in CClientPipeInstance::Send");
TRACE("Caught unknown exception in CClientPipeInstance::Send\n");
return FALSE;
}
return TRUE;
}
m_csPipename is already created with the servername format (\\\servername\pipe\pipename).
My question are as follows:
WaitNamedPipe() returns 0 for clients 3 to 8, even if the pipename is already created.
Is there a limitation on Windows XP that only allows 2 clients?
If there is a limitation, how to configure it to allow more than 2 clients?
I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this.
Thanks in advance.
i Have the following code:
void QtGuiApplication::getBtnClick() {
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
// Specify an HTTP server.
if (hSession) {
hConnect = WinHttpConnect(hSession, L"127.0.0.1",
INTERNET_DEFAULT_HTTP_PORT, 0);
}
else {
qDebug("Error has WinHttpOpen");
QString errorStr = QString::number(GetLastError());
qDebug(qPrintable(errorStr));
}
// Create an HTTP request handle.
if (hConnect) {
hRequest = WinHttpOpenRequest(hConnect, L"GET", NULL,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
}
else {
qDebug("Error has WinHttpConnect");
QString errorStr = QString::number(GetLastError());
qDebug(qPrintable(errorStr));
}
// Send a request.
if (hRequest) {
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
}
else {
qDebug("Error has WinHttpOpenRequest");
QString errorStr = QString::number(GetLastError());
qDebug(qPrintable(errorStr));
}
// End the request.
if (bResults) {
bResults = WinHttpReceiveResponse(hRequest, NULL);
}
else {
qDebug("Error has WinHttpSendRequest");
QString errorStr = QString::number(GetLastError());
qDebug(qPrintable(errorStr));
}
// Keep checking for data until there is nothing left.
if (bResults)
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
printf("Error %u in WinHttpQueryDataAvailable.\n", GetLastError());
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer)
{
printf("Out of memory\n");
dwSize = 0;
}
else
{
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
printf("Error %u in WinHttpReadData.\n", GetLastError());
else
qDebug(pszOutBuffer);
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
}
} while (dwSize > 0);
// Report any errors.
if (!bResults) {
qDebug("Error has occurred");
QString str = QString::number(GetLastError());
qDebug(qPrintable(str));
}
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
}
I try to access the local server through winhttp.
The browser can normally access 127.0.0.1.
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
error var
GetLastError returns 6 after call to WinHttpSendRequest
The code of the service running with springboot is as follows
#Controller
public class MyController {
#ResponseBody
#RequestMapping("")
public String home() {
return "Home";
}
}
Springboot run information: Tomcat started on port(s): 80 (http) with context path ''
Using winhttp API to access services, Get springboot error information
I've tried a lot of ways, and it's still useless.
For example, modify the springboot port and winhttp API request port to 8089.
From WinHttpConnect
INTERNET_DEFAULT_HTTP_PORT
Uses the default port for HTTP servers (port 80).
INTERNET_DEFAULT_HTTPS_PORT
Uses the default port for HTTPS servers (port 443). Selecting this
port does not automatically establish a secure connection. You must
still specify the use of secure transaction semantics by using the
WINHTTP_FLAG_SECURE flag with WinHttpOpenRequest.
The :80 part is the TCP port. You can consider these ports as communications endpoints on a particular IP address (in the case of localhost - 127.0.0.1). The IANA is responsible for maintaining the official assignments of standard port numbers for specific services. Port 80 happens to be the standard port for HTTP.
Refer: What's the whole point of “localhost”, hosts and ports at all?
So you need to change INTERNET_DEFAULT_HTTPS_PORT to INTERNET_DEFAULT_HTTP_PORT.
Given the following code that should connect to a sftp server and print the name of the first file in that server. It looks like it returns the error 12002 which means that the request timed out. I've tried to run it with 2 different servers. Is there something fundamentally wrong in my code?
#include "stdafx.h"
#include <Windows.h>
#include <Wininet.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "wininet.lib")
int main()
{
HINTERNET hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInternet == NULL)
{
_tprintf(_T("An error has occured while trying to open the internet connection\n"));
return 1;
}
HINTERNET hFTP = InternetConnect(
hInternet,
L"test.rebex.net", // this is a sftp server publicly available
22,
L"demo",
L"password",
INTERNET_SERVICE_FTP,
INTERNET_FLAG_PASSIVE,
0
);
if (hFTP == NULL)
{
cout << GetLastError() << endl;
_tprintf(_T("Couldn't connect to the ftp server\n"));
return 1;
}
_tprintf(_T("%d\n"), hFTP);
WIN32_FIND_DATA fd;
FtpFindFirstFile(hFTP, L".", &fd, INTERNET_FLAG_RELOAD, NULL);
_tprintf(_T("%s"), fd.cFileName);
InternetCloseHandle(hFTP);
InternetCloseHandle(hInternet);
return 0;
}
SFTP (FTP over SSH) is very different than FTPS (FTP over SSL), which is probably what you want instead.
But either way, WinInet simply does not support SFTP or FTPS (the INTERNET_FLAG_SECURE flag is only supported for HTTPS).
You will have to use another FTP library that supports SFTP/FTPS.
I am trying to retrieve the source code of a web page using WinHTTP. Reading from this page: http://msdn.microsoft.com/en-us/library/windows/desktop/aa384110(v=vs.85).aspx
I was able to come up with this code. The HTTP status code is 200 which means the request was completed correctly. I end up getting the source code for the login page instead of my intended web page behind it.
Should I send a httprequest to the login page and then to the file path?
Here is the code:
#include <windows.h>
#include <winhttp.h>
#include <string>
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
#pragma comment(lib, "winhttp.lib")
DWORD ChooseAuthScheme(DWORD dwSupportedSchemes)
{
// It is the server's responsibility only to accept
// authentication schemes that provide a sufficient
// level of security to protect the servers resources.
//
// The client is also obligated only to use an authentication
// scheme that adequately protects its username and password.
//
// Thus, this sample code does not use Basic authentication
// becaus Basic authentication exposes the client's username
// and password to anyone monitoring the connection.
if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE)
return WINHTTP_AUTH_SCHEME_NEGOTIATE;
else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NTLM)
return WINHTTP_AUTH_SCHEME_NTLM;
else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_PASSPORT)
return WINHTTP_AUTH_SCHEME_PASSPORT;
else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_DIGEST)
return WINHTTP_AUTH_SCHEME_DIGEST;
else
return 0;
}
struct SWinHttpSampleGet
{
LPCWSTR szServer;
LPCWSTR szPath;
BOOL fUseSSL;
LPCWSTR szServerUsername;
LPCWSTR szServerPassword;
LPCWSTR szProxyUsername;
LPCWSTR szProxyPassword;
};
void WinHttpAuthSample(IN SWinHttpSampleGet *pGetRequest)
{
string contents;
DWORD dwStatusCode = 0;
DWORD dwSupportedSchemes;
DWORD dwFirstScheme;
DWORD dwSelectedScheme;
DWORD dwTarget;
DWORD dwLastStatus = 0;
DWORD dwSize = sizeof(DWORD);
BOOL bResults = FALSE;
BOOL bDone = FALSE;
DWORD dwProxyAuthScheme = 0;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
INTERNET_PORT nPort = (pGetRequest->fUseSSL) ?
INTERNET_DEFAULT_HTTPS_PORT :
INTERNET_DEFAULT_HTTP_PORT;
// Specify an HTTP server.
if (hSession)
hConnect = WinHttpConnect(hSession,
pGetRequest->szServer,
nPort, 0);
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest(hConnect,
L"GET",
pGetRequest->szPath,
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
(pGetRequest->fUseSSL) ?
WINHTTP_FLAG_SECURE : 0);
// Continue to send a request until status code
// is not 401 or 407.
if (hRequest == NULL)
bDone = TRUE;
while (!bDone)
{
// If a proxy authentication challenge was responded to, reset
// those credentials before each SendRequest, because the proxy
// may require re-authentication after responding to a 401 or
// to a redirect. If you don't, you can get into a
// 407-401-407-401- loop.
if (dwProxyAuthScheme != 0)
bResults = WinHttpSetCredentials(hRequest,
WINHTTP_AUTH_TARGET_PROXY,
dwProxyAuthScheme,
pGetRequest->szProxyUsername,
pGetRequest->szProxyPassword,
NULL);
// Send a request.
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
WINHTTP_NO_REQUEST_DATA,
0,
0,
0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
// Resend the request in case of
// ERROR_WINHTTP_RESEND_REQUEST error.
if (!bResults && GetLastError() == ERROR_WINHTTP_RESEND_REQUEST)
continue;
// Check the status code.
if (bResults)
bResults = WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_STATUS_CODE |
WINHTTP_QUERY_FLAG_NUMBER,
NULL,
&dwStatusCode,
&dwSize,
NULL);
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
if (bResults)
{
switch (dwStatusCode)
{
case 200:
// The resource was successfully retrieved.
// You can use WinHttpReadData to read the
// contents of the server's response.
printf("The resource was successfully retrieved.\n");
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
printf("Error %u in WinHttpQueryDataAvailable.\n",
GetLastError());
break;
}
// No more available data.
if (!dwSize)
break;
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer)
{
printf("Out of memory\n");
break;
}
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
{
printf("Error %u in WinHttpReadData.\n", GetLastError());
}
else
{
printf("%s", pszOutBuffer);
contents += pszOutBuffer;
}
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
// This condition should never be reached since WinHttpQueryDataAvailable
// reported that there are bits to read.
if (!dwDownloaded)
break;
} while (dwSize > 0);
bDone = true;
break;
case 401:
// The server requires authentication.
printf(" The server requires authentication. Sending credentials...\n");
// Obtain the supported and preferred schemes.
bResults = WinHttpQueryAuthSchemes(hRequest,
&dwSupportedSchemes,
&dwFirstScheme,
&dwTarget);
// Set the credentials before resending the request.
if (bResults)
{
dwSelectedScheme = ChooseAuthScheme(dwSupportedSchemes);
if (dwSelectedScheme == 0)
bDone = TRUE;
else
bResults = WinHttpSetCredentials(hRequest,
dwTarget,
dwSelectedScheme,
pGetRequest->szServerUsername,
pGetRequest->szServerPassword,
NULL);
}
// If the same credentials are requested twice, abort the
// request. For simplicity, this sample does not check
// for a repeated sequence of status codes.
if (dwLastStatus == 401)
bDone = TRUE;
break;
case 407:
// The proxy requires authentication.
printf("The proxy requires authentication. Sending credentials...\n");
// Obtain the supported and preferred schemes.
bResults = WinHttpQueryAuthSchemes(hRequest,
&dwSupportedSchemes,
&dwFirstScheme,
&dwTarget);
// Set the credentials before resending the request.
if (bResults)
dwProxyAuthScheme = ChooseAuthScheme(dwSupportedSchemes);
// If the same credentials are requested twice, abort the
// request. For simplicity, this sample does not check
// for a repeated sequence of status codes.
if (dwLastStatus == 407)
bDone = TRUE;
break;
default:
// The status code does not indicate success.
printf("Error. Status code %d returned.\n", dwStatusCode);
bDone = TRUE;
}
}
// Keep track of the last status code.
dwLastStatus = dwStatusCode;
// If there are any errors, break out of the loop.
if (!bResults)
bDone = TRUE;
}
// Report any errors.
if (!bResults)
{
DWORD dwLastError = GetLastError();
printf("Error %d has occurred.\n", dwLastError);
}
ofstream fout("Output.txt");
fout << contents;
fout.close();
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
}
int main()
{
wstring Server = L"moodle.redlands.edu";
wstring Path = L"/course/view.php?id=2213/";
wstring User = L"test";
wstring Pass = L"password";
wstring User_Proxy = L"test";
wstring Pass_Proxy = L"password";
SWinHttpSampleGet Lawl{
Server.c_str(),
Path.c_str(),
1,
User.c_str(),
Pass.c_str(),
User_Proxy.c_str(), Pass_Proxy.c_str()
};
WinHttpAuthSample(&Lawl);
system("PAUSE");
return 0;
}
How can I get contents of a file online with C++?
There are a number of ways you can do this.
WinInet
First off Windows has a built-in API allowing you to make HTTP requests, which is reasonably simple to use. I use this simple wrapper class to download files using it:
/**
* Simple wrapper around the WinInet library.
*/
class Inet
{
public:
explicit Inet() : m_hInet(NULL), m_hConnection(NULL)
{
m_hInet = ::InternetOpen(
"My User Agent",
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
/*INTERNET_FLAG_ASYNC*/0);
}
~Inet()
{
Close();
if (m_hInet)
{
::InternetCloseHandle(m_hInet);
m_hInet = NULL;
}
}
/**
* Attempt to open a URL for reading.
* #return false if we don't have a valid internet connection, the url is null, or we fail to open the url, true otherwise.
*/
bool Open(LPCTSTR url)
{
if (m_hInet == NULL)
{
return false;
}
if (url == NULL)
{
return false;
}
m_hConnection = ::InternetOpenUrl(
m_hInet,
url,
NULL /*headers*/,
0 /*headers length*/,
INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI,
reinterpret_cast<DWORD_PTR>(this));
return m_hConnection != NULL;
}
/**
* Read from a connection opened with Open.
* #return true if we read data.
*/
bool ReadFile(LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD dwRead)
{
ASSERT(m_hConnection != NULL);
return ::InternetReadFile(m_hConnection, lpBuffer, dwNumberOfBytesToRead, dwRead) != 0;
}
/**
* Close any open connection.
*/
void Close()
{
if (m_hConnection != NULL)
{
::InternetCloseHandle(m_hConnection);
m_hConnection = NULL;
}
}
private:
HINTERNET m_hInet;
HINTERNET m_hConnection;
};
Usage of this is very simple:
Inet inet;
if (inet.Open(url))
{
BYTE buffer[UPDATE_BUFFER_SIZE];
DWORD dwRead;
while (inet.ReadFile(&buffer[0], UPDATE_BUFFER_SIZE, &dwRead))
{
// TODO: Do Something With buffer here
if (dwRead == 0)
{
break;
}
}
}
LibCurl
If you'd rather avoid Windows-specific APIs then you could do a lot worse than use the libcurl library to get files using a variety of protocols, including HTTP. There is a good sample showing how to retrieve a URL directly into memory (avoiding downloading to disk): getinmemory sample.
Use the following functions.
WinHttpConnect
WinHttpOpenRequest
WinHttpSendRequest
WinHttpReceiveResponse
WinHttpQueryDataAvailable
WinHttpReadData