Link to home
Start Free TrialLog in
Avatar of Maverick_Cool
Maverick_CoolFlag for India

asked on

Access violation reading location while using CSocket across threads....

I am modify a VC++ web server code(small),
It throws access violation in sockcore.cpp while starting a new threading, Myapp is non  mfc, but i have headers file to access CString and CSocket.

Is there a solution.
I am posting my code.
#include "stdafx.h"
#include <atlstr.h>
 
//process.h
#include <afxsock.h>
 
 
 
CString Path;
UINT NewThread (LPVOID p);
CString MIME(CString GetEX);
 
int Connections;
bool doRun = true;
CSocket Listener;
 
void webserver()
{
char TPath[50];
		//cout << "Enter the path to your index file" << endl;
		//cout << "Ex: C:\\html\\MicahServer" << endl;
		//cin >> TPath;
		//Path.Format("%s", &TPath);
Path = "c:\\webserver\\root";
		AfxSocketInit();
		//CSocket Listener;
		
		int Code = Listener.Create(80); //Create socket
		if( Code == 0 ) 
		{
//			cout << "Error creating Socket." << endl; //Get this usually if something is already listening on Port 80.
			
		}
 
		Listener.Listen();
		//cout << "Listening..." << endl;
		
		while(1)
		{
 
			CSocket pConn;
			Listener.Accept(pConn); //Accept on pConn.
			Connections++;
			AfxBeginThread(NewThread, (LPVOID) pConn.Detach()); //Start new thread.
				
		}
 
}
 
 
UINT NewThread (LPVOID p)
 
{
	CSocket TheConn;
	TheConn.Attach((SOCKET)p);
 
	
	CSocketFile file(&TheConn);
	CArchive arIn(&file, CArchive::load);
	CArchive arOut(&file, CArchive::store);
	CString Request;
	CString RFile;
 
	int First = 0;
	do {
		arIn.ReadString(Request); //Read incomming data line by line.
		//cout << (LPCTSTR)Request << endl;
		if (First == 0 ){
			RFile = Request.Mid(4, Request.Find(L" ", 4) - 4);
			First = 1;
		}
	} while (Request != "");
 
 
	CString Temp;
	CString Type;
	CString GetEX;
	CString HisIP;
	CString Varis;
	unsigned int Port;
	
	TheConn.GetPeerName(HisIP, Port); //Get Clients IP and Port.
 
//	cout << endl << "Connected to " << (LPCSTR)HisIP <<", on port " << Port << endl;
 
	
	GetEX = RFile.Mid(RFile.Find(L".", 1) + 1);
 
	if( GetEX.Find(L"?",1)!=-1){ // Remove any variables the Client tried to send in the request
		Varis = GetEX.Mid(GetEX.Find(L"?",1) +1);
		GetEX = GetEX.Mid(0, GetEX.Find(L"?"));
		RFile = RFile.Mid(0, RFile.Find(L"?"));
 
	}
 
	Type.Format(MIME(GetEX)); // Get the MIME Type
 
	
	if( RFile == "/" ) { //If only recived a / look for index file.
		CFile Filer;
		CString TFile;
		CFileException peError;
		RFile.Format(L"\\index.html");
		TFile.Format(L"%s%s",Path, RFile); 
 
		if (!Filer.Open(TFile, CFile::shareDenyNone, &peError)){
			RFile.Format(L"\\index.php");
			TFile.Format(L"%s%s",Path, RFile); 
			
			if (!Filer.Open(TFile, CFile::shareDenyNone, &peError)){
				RFile.Format(L"\\index.htm");
				TFile.Format(L"%s%s",Path, RFile); 
				
				if (!Filer.Open(TFile, CFile::shareDenyNone, &peError)){
					RFile.Format(L"\\index.htm");
					TFile.Format(L"%s%s",Path, RFile); 
				}
			}
		}
	}
	
	
	Temp.Format(L"%s", (LPCSTR)(LPCTSTR)RFile);
	RFile.Format(L"%s%s", Path, Temp);
 
//	cout << (LPCSTR)RFile << " " << (LPCSTR)Type << endl;
	
	CString AllData;
 
	int FLen;
	char *FileData[8193];
	CFile File;
	CFileException pError;
 
	if (File.Open(RFile, CFile::shareDenyNone, &pError))
	{
		FLen = File.GetLength();
		AllData.Format(L"HTTP/1.1 200 OK\nContent-Type: %s\nServer: TCS MicahServer 4.0a\nContent-Length: %d\nConnection: close\n\n", Type, FLen); //Header
		TheConn.Send(AllData, AllData.GetLength(), 0);
 
		UINT nRead;
		while ((nRead = File.Read(FileData, 8192)))// File.Read returns the number of bytes successfully read.
			TheConn.Send(FileData, nRead, 0); // Send data
	}
	else
	{
		AllData.Format(L"HTTP/1.1 404 Object Not Found\nServer: TCS MicahServer 4.0a\nConnection: close\n\n");
		
		int AllSize;
		AllSize =  AllData.GetLength();	
		
		TheConn.Send(AllData, AllSize, 0); //Send data
	}
 
	return 0;
}
 
CString MIME(CString GetEX)
{
	GetEX.MakeLower();
	if ( GetEX == "gif" ){
		return "image/gif";
	}
	if ( GetEX == "jpg" ){
		return "image/jpeg";
	}
	if ( GetEX == "zip" ){
		return "aplication/zip";
	}
	if ( GetEX == "exe" ){
		return "aplication/exe";
	}
	if ( GetEX == "asp" ){
		return "text/asp";
	}
	if ( GetEX == "bmp" ){
		return "image/bmp";
	}
	if ( GetEX == "mov" ){
		return "video/quicktime";
	}
	if ( GetEX == "mp3" ){
		return "video/mpeg";
	}
	if ( GetEX == "mpeg" ){
		return "video/mpeg";
	}
	if ( GetEX == "txt" ){
		return "text/plain";
	}
	if ( GetEX == "cab" ){
		return "application/octet-stream";
	}
	else {
		return "text/html";
	}
 
}

Open in new window

Avatar of LordOfPorts
LordOfPorts
Flag of United States of America image

On line 55 above try:


CSocket TheConn;
if(p) {
    SOCKET * _p = (SOCKET)p;
    TheConn.Attach(*_p);
}
else {
    AfxMessageBox(_T("p is NULL"));
}

Open in new window

Avatar of Maverick_Cool

ASKER

Error    2    error C2440: 'initializing' : cannot convert from 'SOCKET' to 'SOCKET *'  

Sorry, try:
CSocket TheConn;
if(p) {
    SOCKET * _p = (SOCKET*)p;
    TheConn.Attach(*_p);
}
else {
    AfxMessageBox(_T("p is NULL"));
}

Open in new window

...also on line 44 I believe you need to call it as in the code snippet below. I don't have access to a compiler at the moment so please let me know if it fails and I'll take a look at it tomorrow.
AfxBeginThread(NewThread, (LPVOID)&pConn.Detach());

Open in new window

Unhandled exception at 0x00403d40 in xxxxxxxx.exe: 0xC0000005: Access violation reading location 0x00000d84.
changing line 44:
Error    1    error C2102: '&' requires l-value    

Ok, sorry for the inconvenience, I will follow up tomorrow.

The problem is the second parameter of the thread function is a void pointer, whereas the Detach function returns a SOCKET structure, if you like try also this also line 44:


SOCKET _s = pConn.Detach();
AfxBeginThread(NewThread, (LPVOID)&_s); 

Open in new window

well when is was separate console application it was working properly,
some thing to do with wnd class registration and hooking
ASKER CERTIFIED SOLUTION
Avatar of LordOfPorts
LordOfPorts
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>>> char *FileData[8193];

That is an array of char pointers. You were using it in CFile::Read which expects an array of chars (and not an array of pointers). Your code will work nevertheless as you pass the same array to CAsyncSocket::Send which also expects a char buffer. Since a pointer array was bigger in size than a char array the wrong type doesn't harm but all in all it is a rather bad code with poor initializing and risky casts and you will have bad luck if you don't make some fundamental overwork.

>>>>             while(1)
>>>>             {
>>>> 
>>>>                   CSocket pConn;
>>>>                   Listener.Accept(pConn); //Accept on pConn.
>>>>                   Connections++;
>>>>                   AfxBeginThread(NewThread, (LPVOID) pConn.Detach()); //Start new thread.
>>>>                         
>>>>             }

In that loop you create a new CSocket and call Accept. Then, you start a new thread passing the new socket handle. But after that call (and before the new thread could be alive) the loop cycle ends and the CSocket pConn runs out of scope. That means that the destructor was called and the pConn was disconnected. That makes the passed socket handle invalid as well.

You need to define the CSocket before the loop and you MUST have some way how to break the infinite loop somehow (e. g. by accepting a client which invokes a stop request).
 
i couldn't make it work...the problem was use of mfc lib filesin non mfc app. CSocket works poorly with threads when its not able find app handler
>>> CSocket works poorly with threads when its not able find app

You can pass a pointer to your app to the thread, e. g. by using a structure like

  struct ThreadData
  {
      SOCKET sock;
      MyApp * ptrApp;
  };

in myapp.cpp

BOOL MyApp::createThreads()
{
     for (int i = 0; i < MAX_THREADS; ++i)
     {
          ThreadData * pt = new ThreadData;
          pt->sock = getSocketForThread(i);
          pt->sock = this;   // here set the application pointer

          HANDLE h = _beginthread(threadFunc, 0, pt);   // create thread and pass ThreadData
         
          // save thread resources
          myThreads.push_back(pair<ThreadData*, HANDLE>(pt, h));          
     }
}