void CSocket::WaitForConnetion()
{
CSocket* pSocket = NULL;
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = m_hSocket;
timeval timeout;
ZeroMemory(&timeout, sizeof(timeout));
timeout.tv_sec = 10;
while(!g_bQuit)
{
int iSelect = select(NULL, &readfds, NULL, NULL, &timeout);
if (iSelect == SOCKET_ERROR)
{
// error
break;
}
else
{
if (iSelect == 0)
{
// timeout
}
else
{
assert(iSelect == 1);
SOCKET new_sock = accept(m_hSocket, NULL, NULL);
if (new_sock != INVALID_SOCKET)
{
pSocket = new CSocketEx(new_sock);
// create a new thread to process the connection request with pSocket
}
}
continue;
}
}
Hi,all
CSocket is a socket wrapper.
Using blocking socket in my programm,calling accept function will be blocked when i want to exit thoroughly, so i have to terminate the thread calling accept.I want to use select function as above.But select often goes with non-blocking socket, are there any problems or concerns using blocking socket under such environment above?
With EJP's help.I modified the code below.Is there any error? And as you said if i use the way by closing socket handle,i must pass the socket handle to the other thread then close it,is it safty to operator one sokcet in different threads?
void CSocket::WaitForConnetion()
{
CSocket* pSocket = NULL;
timeval timeout;
ZeroMemory(&timeout, sizeof(timeout));
timeout.tv_sec = 10;
while(!g_bQuit)
{
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = m_hSocket;
int iSelect = select(NULL, &readfds, NULL, NULL, &timeout);
if (iSelect == SOCKET_ERROR)
{
// error
break;
}
else
{
if (iSelect == 0)
{
// timeout
}
else
{
assert(iSelect == 1);
SOCKET new_sock = accept(m_hSocket, NULL, NULL);
if (new_sock != INVALID_SOCKET)
{
pSocket = new CSocketEx(new_sock);
// create a new thread to process the connection request with pSocket
}
}
continue;
}
}
Related
I'm trying to start a process in the interactive session of the currently logged-on user using Win32 API. The start-up is taking place from a remote SSH session, so this should be similar to starting a process in an interactive session from a service. The remote SSH session is logged-in with the same user that I'm trying to start-up a process in the interactive session for.
I have the following setup:
A Windows Server 2019 GCE VM
OpenSSH server is enabled on the server machine
A user administrator that has the following privileges:
Act as the operating system administrator
Impersonate a client after authentication
I use the following piece of C# code to start-up the process, in this case it's notepad.exe. The code is opening the token of explorer.exe process which should run in the user session. The token is then duplicated and used to create the process.
var pHandle = OpenProcess(
0x001F0FFF,
false,
explorerPID);
if (pHandle == IntPtr.Zero) { // handle win32 error }
if (!OpenProcessToken(pHandle,
TOKEN_ALL_ACCESS,
out IntPtr tHandle)) {
// handle win32 error
}
var lpT = new SECURITY_ATTRIBUTES();
if (!DuplicateTokenEx(
tHandle,
TOKEN_ALL_ACCESS,
ref lpT,
SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
TOKEN_TYPE.TokenPrimary,
out IntPtr newtHandle)) {
// handle win32 error
}
var startInfo = new STARTUPINFO();
var lpProcAttr = new SECURITY_ATTRIBUTES();
var lpThreadAttr = new SECURITY_ATTRIBUTES();
startInfo.lpDesktop = "winsta0\\default";
startInfo.cb = Marshal.SizeOf(startInfo);
if (!CreateProcessAsUser(newtHandle,
"c:\\Windows\\notepad.exe",
null,
ref lpProcAttr,
ref lpThreadAttr,
false,
0x00000020,
IntPtr.Zero,
null,
ref startInfo,
out _)) {
// handle win32 error
}
I am deploying the binary on the server and then via SSH I'm executing it. The problem is I'm getting (5) Access is denied on the CreateProcessAsUser function. Does anyone have any clue of what I'm missing here or if it's even possible to achieve this?
for call CreateProcessAsUser in general case you need SE_ASSIGNPRIMARYTOKEN_NAME privilege. also you can search for some process in some session (like explorer) and use it token. or you can enumerate terminal sessions and get token from session. for this you need TCB privilege. both this possible got you you initially have Debug privileges. code can be next:
#define BEGIN_PRIVILEGES(name, n) static const union { TOKEN_PRIVILEGES name;\
struct { ULONG PrivilegeCount; LUID_AND_ATTRIBUTES Privileges[n];} label(_) = { n, {
#define LAA(se) {{se}, SE_PRIVILEGE_ENABLED }
#define LAA_D(se) {{se} }
#define END_PRIVILEGES }};};
const SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof (sqos), SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE
};
const OBJECT_ATTRIBUTES oa_sqos = { sizeof(oa_sqos), 0, 0, 0, 0, const_cast<SECURITY_QUALITY_OF_SERVICE*>(&sqos) };
const TOKEN_PRIVILEGES tp_Debug = { 1, { { { SE_DEBUG_PRIVILEGE }, SE_PRIVILEGE_ENABLED } } };
BEGIN_PRIVILEGES(tp_TCB, 3)
LAA(SE_TCB_PRIVILEGE),
LAA(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE),
LAA(SE_INCREASE_QUOTA_PRIVILEGE),
END_PRIVILEGES
NTSTATUS GetToken(PVOID buf, const TOKEN_PRIVILEGES* RequiredSet)
{
NTSTATUS status;
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
HANDLE hProcess, hToken, hNewToken;
CLIENT_ID ClientId = { pspi->UniqueProcessId };
if (ClientId.UniqueProcess)
{
if (0 <= NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION,
const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), &ClientId))
{
status = NtOpenProcessToken(hProcess, TOKEN_DUPLICATE, &hToken);
NtClose(hProcess);
if (0 <= status)
{
status = NtDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE,
const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), FALSE, TokenImpersonation, &hNewToken);
NtClose(hToken);
if (0 <= status)
{
status = NtAdjustPrivilegesToken(hNewToken, FALSE, const_cast<PTOKEN_PRIVILEGES>(RequiredSet), 0, 0, 0);
if (STATUS_SUCCESS == status)
{
status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &hNewToken, sizeof(hNewToken));
}
NtClose(hNewToken);
if (STATUS_SUCCESS == status)
{
return STATUS_SUCCESS;
}
}
}
}
}
} while (NextEntryOffset = pspi->NextEntryOffset);
return STATUS_UNSUCCESSFUL;
}
NTSTATUS AdjustPrivileges(_In_ const TOKEN_PRIVILEGES* ptp)
{
NTSTATUS status;
HANDLE hToken, hNewToken;
if (0 <= (status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE, &hToken)))
{
status = NtDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE,
const_cast<OBJECT_ATTRIBUTES*>(&oa_sqos), FALSE, TokenImpersonation, &hNewToken);
NtClose(hToken);
if (0 <= status)
{
if (STATUS_SUCCESS == (status = NtAdjustPrivilegesToken(hNewToken, FALSE,
const_cast<PTOKEN_PRIVILEGES>(ptp), 0, 0, 0)))
{
status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &hNewToken, sizeof(hNewToken));
}
NtClose(hNewToken);
}
}
return status;
}
NTSTATUS ImpersonateToken(_In_ const TOKEN_PRIVILEGES* RequiredSet)
{
NTSTATUS status = AdjustPrivileges(&tp_Debug);
ULONG cb = 0x40000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PBYTE buf = new BYTE[cb += PAGE_SIZE])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
status = GetToken(buf, RequiredSet);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
status = STATUS_UNSUCCESSFUL;
}
}
delete [] buf;
}
} while(status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
void StartNotepadInSession(ULONG dwSessionId)
{
HANDLE hToken;
WCHAR sz[MAX_PATH];
if (SearchPathW(0, L"notepad.exe", 0, _countof(sz), sz, 0))
{
if (WTSQueryUserToken(dwSessionId, &hToken))
{
PVOID lpEnvironment;
if (CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE))
{
PROCESS_INFORMATION pi;
STARTUPINFOW si = { sizeof(si) };
if (CreateProcessAsUserW(hToken, sz, 0, 0, 0, 0,
CREATE_UNICODE_ENVIRONMENT, lpEnvironment, 0, &si, &pi))
{
NtClose(pi.hThread);
NtClose(pi.hProcess);
}
DestroyEnvironmentBlock(lpEnvironment);
}
NtClose(hToken);
}
}
}
void exec()
{
if (0 <= ImpersonateToken(&tp_TCB))
{
ULONG MySessionId, SessionId;
ProcessIdToSessionId(GetCurrentProcessId(), &MySessionId);
PWTS_SESSION_INFOW pSessionInfo;
ULONG Count;
if (WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &Count))
{
DbgPrint("Sessions = %x\r\n", Count);
if (Count)
{
pSessionInfo += Count;
do
{
--pSessionInfo;
DbgPrint("SESSION_INFO<%x>: %x %S\r\n", pSessionInfo->SessionId, pSessionInfo->State, pSessionInfo->pWinStationName);
if (SessionId = pSessionInfo->SessionId)
{
switch (pSessionInfo->State)
{
case WTSDisconnected:
case WTSActive:
if (MySessionId != SessionId)
{
StartNotepadInSession(SessionId);
}
break;
}
}
} while (--Count);
}
WTSFreeMemory(pSessionInfo);
}
RevertToSelf();
}
}
I am using VS 2013 Professional in an MFC project
I have been using my software to receive data from the com port for some time, but recently needed to add transmission capability
The Init code is:
BOOL PASCAL FAR SetupConnect(pCONNECTION pCon, pCOMCONFIG pCfg)
{
DCB dcb;
pSERBUF pSB = pCon->BufStruct;
// pSERBUF *ppSB = (pSERBUF*)pCon->BufStruct;
// pSB = *ppSB;
dcb.DCBlength = sizeof(DCB);
CheckComs(); // Gets available COM ports
pCon->Port = pNames[0].PortNames[3] - 0x30;
if (pCon->BufStruct == NULL) // This is a personal Communications structure
{ // Init
pCon->hSB = GlobalAlloc(GHND, sizeof(SERBUF));
if (pCon->hSB == NULL)
{
// return INVALID_HANDLE_VALUE;
return 0;
}
pSB = (pSERBUF)GlobalLock(pCon->hSB);
pSB->idComDev = INVALID_HANDLE_VALUE;
pCon->BufStruct = pSB;
}
else return (0);
if (pSB->idComDev == INVALID_HANDLE_VALUE)
{
pSB->idComDev = CreateFile(pNames[0].PortNames, GENERIC_READ | GENERIC_WRITE,
0, //exclusive access
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
}
// Current configuration
GetCommState(pSB->idComDev, &dcb);
// Setup baudrate, parity, etc.
dcb.BaudRate = pCfg->dwBaudRate;
dcb.ByteSize = pCfg->bDataBits;
dcb.Parity = pCfg->bParity;
dcb.StopBits = pCfg->bStopBits;
// Setup Flow Control
dcb.fOutxDsrFlow = pCfg->handshake_DTR;
dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR high while port open
dcb.fOutxCtsFlow = pCfg->handshake_RTS;
dcb.fRtsControl = RTS_CONTROL_DISABLE; // Toggle RTS with EscapeCommFunction
// XON/XOFF Not Used
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
//return TRUE if everything looks cool
return (SetCommState(pSB->idComDev, &dcb));
}
And:
CSerCom::CSerCom()
{
pCon = &Con;
pCfg = &Cfg;
m_SerHwnd = this;
pCfg->dwBaudRate = 115200;
pCfg->bDataBits = 8;
pCfg->bParity = NOPARITY;
pCfg->bStopBits = TWOSTOPBITS;
// here
SetupConnect(pCon, pCfg);
pSERBUF pSB = pCon->BufStruct; // pSB is set in SetUpConnect
if (pSB->idComDev == INVALID_HANDLE_VALUE)
{
// device open failure
// hardware not there or someone else controls it!
GlobalUnlock(pCon->hSB);
GlobalFree(pCon->hSB);
pCon->BufStruct = NULL;
// TODO stop this from going any further
HandleFailure();
}
else // Only continue if Port is available
{
// Clear Buffer
SetupComm(pSB->idComDev, 4096, 4096);
PurgeComm(pSB->idComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
// create the overlapped events
memset(&(pSB->osRead), 0, sizeof(OVERLAPPED));
memset(&(pSB->osWrite), 0, sizeof(OVERLAPPED));
pSB->osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pSB->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if ((pSB->osRead.hEvent == NULL) || (pSB->osWrite.hEvent == NULL))
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
// allocate & lock the mem
// (used to contain data points to & from the MODBUS
// as well as the receive buffer for incoming serial data)
pSB->hRcv = GlobalAlloc(GHND, MAX_RX_LEN);
if (pSB->hRcv == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
pSB->pRcv = (char *)GlobalLock(pSB->hRcv);
pSB->hTx = (char *)GlobalAlloc(GHND, MAX_TX_LEN);
if (pSB->hTx == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
pSB->pTx = (char *)GlobalLock(pSB->hTx);
// remember the setup params
pSB->TimeOut = 3; //CalculateTimeOut(pCfg->dwBaudRate);
// pSB->TimerId = TimerId;
// initialize the status counters
// pSB->ValidCt = 0;
// pSB->InvalidCt = 0;
pSB->RxInIdx = 0;
// pSB->RTS_Delay[0] = pCfg->RTS_Delay[0];
// pSB->RTS_Delay[1] = pCfg->RTS_Delay[1];
pSB->RTS_Delay[0] = 100;
pSB->RTS_Delay[1] = 100;
// setup the Comm Timeouts
CommTimeOuts.ReadIntervalTimeout = 0xffffffff;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 1000;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts(pSB->idComDev, &CommTimeOuts);
// if everything looks good to here
// create the Receive Thread & return the CONNECT handle
pSB->hIOThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)SerProc,
(LPVOID)pCon,
0,
&dwThreadID);
if (pSB->hIOThread == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
hIOT = pSB->hIOThread;
}
}
So with that set up, I enter a thread loop in which I have the following
// wait indefinitely for somthing to happen
WaitCommEvent(pSB->idComDev, &dwEvtMask, NULL);
// Catch Rx event
if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
{
Edit1_txt.Format(_T("Rx'd"));
E1->SetWindowText(Edit1_txt);
CMFCView->UpdateWindow();
// only try to read number of bytes in queue
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
dwLength = ComStat.cbInQue;
// Read data bytes into connection Rcv Buffer at current RxInIdx
if (dwLength > 0)
{
fReadStat = ReadFile(pSB->idComDev,
&(pSB->pRcv[pSB->RxInIdx]),
dwLength,
&bytesread,
&(pSB->osRead));
if (!fReadStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
// We have to wait for read to complete.
while (!GetOverlappedResult(pSB->idComDev,
&(pSB->osRead), &bytesread, FALSE))
{
dwErrorFlags = GetLastError();
if (dwErrorFlags != ERROR_IO_INCOMPLETE)
// an error occurred, try to recover
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
}
else
{
// some other error occurred
dwLength = 0;
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
} // End of Read Error
} // End of Read Char
if (ComStat.cbInQue < 500)
{
// update the receive index
pSB->RxInIdx += dwLength;
wSleepime = GetTickCount(); // hkk 7/16/99 for console app
ParseAPI(pSB);
}
else
ComStat.cbInQue = 0;
}
// At some point in the program pSB->TxOutIdx is set to some positive value
if (pSB->TxOutIdx > 0)
{
dwLength = pSB->TxOutIdx;
fWriteStat = WriteFile(pSB->idComDev,
&(pSB->pTx[pSB->TxOutIdx]),
dwLength,
&byteswritten,
&(pSB->osWrite));
if (!fWriteStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
while (!GetOverlappedResult(pSB->idComDev,
&(pSB->osWrite), &byteswritten, FALSE))
{
dwErrorFlags = GetLastError();
if (dwErrorFlags != ERROR_IO_INCOMPLETE)
// an error occurred, try to recover
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
}
pSB->TxOutIdx -= byteswritten;
}
}
}
This detects the Tx buffer full, (pSB->TxOutIdx > 0)
and transmits the data
The transmit fails with an IO pending error, but after execution of GetOverlappedResult, bytes written show the length desired.
However, no data comes out the port. I have checked, and the port found and used is correct.
Wassup?
I want to develop an encrypt-virtual-disk based on the FileDisk-17 opensource project.
Here is my solution:
In IPR_MJ_READ, when the ZwReadFile returns, I use function 'DecryptData' to decrypt the data read by ZwReadFile.
In IPR_MJ_WRITE, before call ZwWriteFile, I use function 'EncryptData' to encrypt the data which will be written to the disk.
I put EncryptData & DecryptData functions in a single C source file.
The question is; when I loaded my driver, I get the ERROR_PROC_NOT_FOUND(127) error code
every time, even there are only one line in the EncryptData or DecryptData function.
Who can tell me what caused this and how to fix it?
filedisk.c
switch (io_stack->MajorFunction)
{
case IRP_MJ_READ:
system_buffer = (PUCHAR) MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
if (system_buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
buffer = (PUCHAR) ExAllocatePool(PagedPool, io_stack->Parameters.Read.Length);
if (buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
ZwReadFile(
device_extension->file_handle,
NULL,
NULL,
NULL,
&irp->IoStatus,
buffer,
io_stack->Parameters.Read.Length,
&io_stack->Parameters.Read.ByteOffset,
NULL
);
*if(bEncrypt)
{
cipher = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, irp->IoStatus.Information, 'TAG');
if(cipher)
{
**DecryptData**(buffer, cipher, irp->IoStatus.Information);
RtlCopyMemory(system_buffer, cipher, irp->IoStatus.Information);
ExFreePool(cipher);
}
else
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
}*
else
{
RtlCopyMemory(system_buffer, buffer, io_stack->Parameters.Read.Length);
ExFreePool(buffer);
}
crypto.c
VOID EncryptData(PUCHAR src, PUCHAR dst, ULONG length)
{
BF_LONG data[2];
BF_KEY key;
BF_set_key(&key, pCryptoInformation->CryptoKey, sizeof(pCryptoInformation->CryptoKey));
}
VOID DecryptData(PUCHAR src, PUCHAR dst, ULONG length)
{
BF_LONG data[2];
BF_KEY key;
BF_set_key(&key, pCryptoInformation->CryptoKey, sizeof(pCryptoInformation->CryptoKey));
}
i have implemented my ClientSocket class from CAsyncSocket:
class ClientSocket : public CAsyncSocket
{
// this socket sends data back to "backSocket" which points to this only for
// testing but it can send data to other sockets like that too.
ClientSocket * backSocket;
// store some data in backupData untill connection is established.
StringBuilder * backupData;
public:
virtual void OnClose(int);
virtual void OnReceive(int);
ClientSocket(void);
bool ConnectToBACK();
virtual ~ClientSocket(void);
};
ClientSocket::ClientSocket(void)
{
// DONOT run to back !!! recursive calls otherwise.
backSocket = NULL;
backupData = NULL;
}
bool ClientSocket::ConnectToBACK()
{
if(this->backSocket != NULL)
return true;
// just for debugging :)
this->backSocket = this;
return true;
}
ClientSocket::~ClientSocket(void)
{
this->Close();
if(this->backSocket)
{
this->backSocket->Close();
delete this->backSocket;
this->backSocket = NULL;
}
}
void ClientSocket::OnClose(int nErrorCode)
{
if(this->backSocket != NULL)
{
this->backSocket->Close();
}
CAsyncSocket::OnClose(nErrorCode);
}
void ClientSocket::OnReceive(int nErrorCode)
{
if(nErrorCode == 0)
{
char *buffer = new char[2049];
int bufLen = sizeof(buffer)/sizeof(buffer[0]);
int received = this->Receive(buffer, bufLen-1, 0);
if(received == SOCKET_ERROR)
{
return ;
}
if(this->ConnectToback())
{
if(backupData)
{
int backupLen;
char *backup = backupData->ToString(&backupLen);
this->backSocket->Send(backup, backupLen);
delete backupData;
delete [] backup;
backupData = NULL;
}
this->backSocket->Send(buffer, received);
delete buffer;
}
else
{
if(backupData == NULL)
{
backupData = new StringBuilder();
}
backupData->Insert(buffer, received);
}
}
CAsyncSocket::OnReceive(nErrorCode);
}
I have not associated any GUI to this as i thought that it would be good for no overheads.
I donot require it. I have also done AfxSocketIback() in main and from a thread started another ListeningSocket .
netstat -a shows proper binding at the port of ListeningSocket and status as Listening
// ListeningSocket inherits public CAsyncSocket
void ListeningSocket::OnAccept(int nErrorCode)
{
#ifdef DEBUG
std::cout << "\nOnAccepting Proxy Server :)";
#endif
if(nErrorCode == 0)
{
ClientSocket *FromCliet = new ClientSocket();
FromCliet->value = 100;
if(this->Accept(*FromCliet, NULL, NULL))
{
// Connection just has ClientSocket * client
Connection * connection = new Connection(FromCliet);
// a list<Connection *> is stored in ListeningSocket
this->clients.push_front(connection);
}
else
{
std::cerr << "\nFailed to accept connection from Client";
}
}
CAsyncSocket::OnAccept(nErrorCode);
}
When putting brakepoints in ListenSocket::OnAccept, it never comes here.
EDIT:
static DWORD WINAPI StartListening(LPVOID param)
{
ListeningSocket *app = (ListeningSocket *)param;
if(false == app->Create(7897, SOCK_STREAM, 31, "127.0.0.1"))
{
std::cerr << "\nCould not create\bind to port";
delete app;
return -1;
}
if(false == app->Listen())
{
std::cerr << "\nCould not listen";
app->Close();
delete app;
return -1;
}
return 0;
}
int ListeningSocket::Start()
{
if(NULL == CreateThread(NULL,0, StartListening, (LPVOID)this,0, NULL))
{
return -1;
}
return 0;
}
I have NOT made it like MFC Wizard solution. I have simple project and main().
My ListeningSocket Class is Singletone Class:
class ListeningSocket : public CAsyncSocket
{
private:
static ListeningSocket * ListeningSocket;
std::list<Connection *> clients;
ListeningSocket(void);
public:
// overrides
virtual void OnAccept(int);
virtual void OnClose(int);
static ListeningSocket * GetListeningSocket();
virtual ~ListeningSocket(void);
virtual void Close();
int Start(void);
};
CAsyncSocket class internally uses Windows messages for firing events. You need to create CAsyncSocket-derived class in a thread with message loop. In this case events will be called. Pseudo-code:
// This function runs in the context of worker thread
void MyClass::ThreadFunction()
{
mySocket.Create(...); // creating CAsyncSocket-derived class
// Run message loop.
BOOL bRes = FALSE;
MSG msg;
while((bRes = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRes == -1)
{
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
To stop this thread, use PostQuitMessage function.
Edit.
I didn't post all multi-threading details, assuming that you are familiar with them. Generally, CreateThread requires global function as parameter (or class static function). To call regular class method, use "this" as CreateThread parameter, which is passed as void* to global thread function. Cast it back to the class pointer and call regular class method.
I've also run into this same issue - with someone's re-implementation of CAsyncSocket called CAsyncSocketEx -- built to be a function replacement for CAsyncSocket.
Just this week, I thought I'd see if I could use this code again, and I ran into this very same problem. Since the async-window was not created inside a thread that has a message loop, the events were not firing from WSAAsyncSelect()...
see this: http://support.microsoft.com/kb/90975
The program runs fine for a few minutes and then ReadFile starts failing with error code ERROR_WORKING_SET_QUOTA.
I'm using ReadFile with overlapped I/O like so:
while (continueReading)
{
BOOL bSuccess = ReadFile(deviceHandle, pReadBuf, length,
&bytesRead, readOverlappedPtr);
waitVal = WaitForMultipleObjects(
(sizeof(eventsToWaitFor)/sizeof(eventsToWaitFor[0])),
eventsToWaitFor, FALSE, INFINITE);
if (waitVal == WAIT_OBJECT_0) {
// do stuff
} else if (waitVal == WAIT_OBJECT_0 + 1) {
// do stuff
} else if (waitVal == WAIT_OBJECT_0 + 2) {
// complete the read
bSuccess = GetOverlappedResult(deviceHandle, &readOverlapped,
&bytesRead, FALSE);
if (!bSuccess) {
errorCode = GetLastError();
printf("ReadFile error=%d\n", errorCode);
}
}
}
Why am I getting this error?
The problem is that ReadFile is getting called more times than GetOverlappedResult. Causing the process to run out of resources for dealing with all the outstanding reads.
Additionally, we should check the result of ReadFile and ensure the result is ERROR_IO_PENDING, if it isn't and ReadFile returned FALSE then there is another problem.
Ensure that GetOverlappedResult is called once for each successful call to ReadFile. Like so:
BOOL bPerformRead = TRUE;
while (continueReading)
{
BOOL bSuccess = TRUE;
// only perform the read if the last one has finished
if (bPerformRead) {
bSuccess = ReadFile(deviceHandle, pReadBuf, length,
&bytesRead, readOverlappedPtr);
if (!bSuccess) {
errorCode = GetLastError();
if (errorCode != ERROR_IO_PENDING) {
printf("ReadFile error=%d\n", errorCode);
return;
}
} else {
// read completed right away
continue;
}
// we can't perform another read until this one finishes
bPerformRead = FALSE;
}
waitVal = WaitForMultipleObjects(
(sizeof(eventsToWaitFor)/sizeof(eventsToWaitFor[0])),
eventsToWaitFor, FALSE, INFINITE);
if (waitVal == WAIT_OBJECT_0) {
// do stuff
} else if (waitVal == WAIT_OBJECT_0 + 1) {
// do stuff
} else if (waitVal == WAIT_OBJECT_0 + 2) {
// complete the read
bSuccess = GetOverlappedResult(deviceHandle, &readOverlapped,
&bytesRead, FALSE);
// the read is finished, we can read again
bPerformRead = TRUE;
if (!bSuccess) {
errorCode = GetLastError();
printf("GetOverlappedResult from ReadFile error=%d\n", errorCode);
}
}
}