//
// Function: RemoveSocketObjByHandle
//
// Description:
//    Remove the socket object structure from the list of objects that
//    matches the socket handle.
//
void RemoveSocketObjByHandle(SOCKET s)
{
    SOCKET_OBJ *obj;

    obj = FindSocketObj(s);
    if (obj)
    {
        RemoveSocketObj(obj);
    }
    return;
}
bool MightyTCPCompletionPortServer::CloseLink(const string & strLinkNo)
{
	PCompletionPortIOObject controlHandle=NULL;
	controlHandle=SearchSocketObj(strLinkNo);
	if (controlHandle!=NULL)
	{
		RemoveSocketObj(controlHandle);

		return true;
	}

	return false;
}
BOOL HandleIOProcessTCPServer::HandleIO(PSOCKET_OBJ pSocket)
{
	// 获取具体发生的网络事件
	WSANETWORKEVENTS event;
	::WSAEnumNetworkEvents(pSocket->s, pSocket->event, &event);
	do
	{
		if(event.lNetworkEvents & FD_READ)			// 套节字可读
		{
			if(event.iErrorCode[FD_READ_BIT] == 0)
			{
				char tcpPackage[4096]={0};
				int nRecv = ::recv(pSocket->s,tcpPackage,4096,0);
				/*if(nRecv > 0)				
				{
					szText[nRecv] = '\0';
					printf("接收到数据:%s \n", szText);
				}*/
				((MightyTCPEventSelectServer *)(m_userInstance.InstanceUserData_))->m_pNotifyCallBack->OnRecvData(tcpPackage,nRecv,pSocket->identityIDKey);
			}
			else
				break;
		}
		else if(event.lNetworkEvents & FD_CLOSE)	// 套节字关闭
		{
			break;
		}
		else if(event.lNetworkEvents & FD_WRITE)	// 套节字可写
		{
			if(event.iErrorCode[FD_WRITE_BIT] == 0)
			{	
			}
			else
				break;
		}
		return TRUE;
	}
	while(FALSE);

	// 套节字关闭,或者有错误发生,程序都会转到这里来执行
	RemoveSocketObj(pSocket);
	return FALSE;
}
void MightyTCPCompletionPortServer::HandleIO(DWORD dwKey, PCompletionPort_BufObj pBuffer, DWORD dwTrans, int nError)
{
	PCompletionPortIOObject pContext = (PCompletionPortIOObject)dwKey;

	//首先减少套节字上的未决I/O计数
	if(pContext != NULL)
	{
		if(pBuffer->nOperation == OP_READ)
			pContext->nOutstandingRecv --;
		else if(pBuffer->nOperation == OP_WRITE)
			pContext->nOutstandingSend --;



		// 检查套节字是否已经被我们关闭
		if(pContext->nCondition) 
		{

			if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
			{		
				RemoveSocketObj(pContext);
			}
			// 释放已关闭套节字的未决I/O
			ReleaseBuffer(pBuffer);	
			return;
		}
	}
	else
	{
		RemovePendingAccept(pBuffer);
	}

	//检查套节字上发生的错误,如果有的话,通知用户,然后关闭套节字
	if(nError != NO_ERROR)
	{
		if(pBuffer->nOperation != OP_ACCEPT)
		{
			//if(nError==ERROR_NETNAME_DELETED)
			RemoveSocketObj(pContext);
			if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
			{		
				//ReleaseContext(pContext);
			}

		}
		else // 在监听套节字上发生错误,也就是监听套节字处理的客户出错了
		{
			// 客户端出错,释放I/O缓冲区
			if(pBuffer->sAccept!= INVALID_SOCKET)
			{
				::closesocket(pBuffer->sAccept);
				pBuffer->sAccept= INVALID_SOCKET;
			}		
		}

		ReleaseBuffer(pBuffer);
		return;
	}


	// 开始处理
	if(pBuffer->nOperation == OP_ACCEPT)
	{
		if(dwTrans == 0)
		{
			if(pBuffer->sAccept!= INVALID_SOCKET)
			{
				::closesocket(pBuffer->sAccept);
				pBuffer->sAccept= INVALID_SOCKET;
			}
		}
		else
		{
			// 为新接受的连接申请客户上下文对象
			PCompletionPortIOObject pClient =GetSocketObj(pBuffer->sAccept);
			if(pClient != NULL)
			{
				if(InsertSocketObj(pClient)==0)
				{	
					// 取得客户地址
					int nLocalLen, nRmoteLen;
					LPSOCKADDR pLocalAddr, pRemoteAddr;
					m_lpfnGetAcceptExSockaddrs(
						pBuffer->buff,
						pBuffer->nLen - ((sizeof(sockaddr_in) + 16) * 2),
						sizeof(sockaddr_in) + 16,
						sizeof(sockaddr_in) + 16,
						(SOCKADDR **)&pLocalAddr,
						&nLocalLen,
						(SOCKADDR **)&pRemoteAddr,
						&nRmoteLen);
					memcpy(&pClient->addrLocal, pLocalAddr, nLocalLen);
					memcpy(&pClient->addrRemote, pRemoteAddr, nRmoteLen);

					// 关联新连接到完成端口对象
					::CreateIoCompletionPort((HANDLE)pClient->s, m_hCompletionPort, (DWORD)pClient, 0);

					// 通知用户
					pBuffer->nLen = dwTrans;
					

					m_pNotifyCallBack->OnRecvData(pBuffer->buff,dwTrans,pClient->identityIDKey);

					// 向新连接投递几个Read请求,这些空间在套节字关闭或出错时释放
					for(int i=0; i<5; i++)
					{
						PCompletionPort_BufObj p = AllocateBuffer(pClient,2048);
						if(p != NULL)
						{
							if(!PostRecv(p))
							{
								RemoveSocketObj(pClient);
								break;
							}
						}
					}
				}
				else	// 连接数量已满,关闭连接
				{
					RemoveSocketObj(pClient);
					
				}
			}
			else
			{
				// 资源不足,关闭与客户的连接即可
				::closesocket(pBuffer->sAccept);
				pBuffer->sAccept= INVALID_SOCKET;
			}
		}

		// Accept请求完成,释放I/O缓冲区
		ReleaseBuffer(pBuffer);	

		// 通知监听线程继续再投递一个Accept请求
		::InterlockedIncrement(&m_nRepostCount);
		::SetEvent(m_hRepostEvent);
	}
	else if(pBuffer->nOperation == OP_READ)
	{
		if(dwTrans == 0)	// 对方关闭套节字
		{
			// 先通知用户
			pBuffer->nLen = 0;
			RemoveSocketObj(pContext);
			// 释放客户上下文和缓冲区对象
			if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
			{		
				//ReleaseContext(pContext);
			}
			//ReleaseBuffer(pBuffer);	
		}
		else
		{
			pBuffer->nLen = dwTrans;
			// 按照I/O投递的顺序读取接收到的数据
			PCompletionPort_BufObj pNextIO = GetNextReadBuffer(pContext, pBuffer);
			while(pNextIO != NULL)
			{
				

				m_pNotifyCallBack->OnRecvData(pNextIO->buff,dwTrans,pContext->identityIDKey);
				// 增加要读的序列号的值
				::InterlockedIncrement((LONG*)&pContext->nCurrentReadSequence);
				// 释放这个已完成的I/O
				ReleaseBuffer(pNextIO);
				pNextIO= GetNextReadBuffer(pContext, NULL);
			}

			// 继续投递一个新的接收请求
			pBuffer = AllocateBuffer(pContext,4096);
			if(pBuffer == NULL || !PostRecv(pBuffer))
			{
				//closeAConnection(pContext);
			}
		}
	}
	else if(pBuffer->nOperation == OP_WRITE)
	{

		if(dwTrans == 0)	// 对方关闭套节字
		{
			// 先通知用户
			pBuffer->nLen = 0;
			RemoveSocketObj(pContext);
			// 再关闭连接
			//CloseAConnection(pContext);

			// 释放客户上下文和缓冲区对象
			if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
			{		
				//ReleaseContext(pContext);
			}
			//ReleaseBuffer(pBuffer);	
		}
		else
		{
			// 写操作完成,通知用户
			pBuffer->nLen = dwTrans;
			//OnWriteCompleted(pContext, pBuffer);
			// 释放SendText函数申请的缓冲区
			ReleaseBuffer(pBuffer);
		}
	}
}
//
// Function: HandleIo
//
// Description:
//    This function handles the IO on a socket. First, the events signaled
//    on the socket are enuemrated, then the appropriate handler routine
//    for the event is called.
//
int  HandleIo(THREAD_OBJ *thread, SOCKET_OBJ *sock)
{
    WSANETWORKEVENTS nevents;
    int              rc;

    // Enumerate the events
    rc = WSAEnumNetworkEvents(
            sock->s,
            sock->event,
           &nevents
            );
    if (rc == SOCKET_ERROR)
    {
        fprintf(stderr, "HandleIo: WSAEnumNetworkEvents failed: %d\n", WSAGetLastError());
        return SOCKET_ERROR;
    }

    if (nevents.lNetworkEvents & FD_READ)
    {
        // Check for read error
        if (nevents.iErrorCode[FD_READ_BIT] == 0)
        {
            rc = ReceivePendingData(sock);
            if (rc == -1)
            {
                RemoveSocketObj(thread, sock);
                FreeSocketObj(sock);
                return SOCKET_ERROR;
            }
            rc = SendPendingData(sock);
            if (rc == -1)
            {
                RemoveSocketObj(thread, sock);
                FreeSocketObj(sock);
                return SOCKET_ERROR;
            }
        }
        else
        {
            fprintf(stderr, "HandleIo: FD_READ error %d\n", 
                    nevents.iErrorCode[FD_READ_BIT]);
            RemoveSocketObj(thread, sock);
            FreeSocketObj(sock);
            return SOCKET_ERROR;
        }
    }
    if (nevents.lNetworkEvents & FD_WRITE)
    {
        // Check for write error
        if (nevents.iErrorCode[FD_WRITE_BIT] == 0)
        {
            rc = SendPendingData(sock);
            if (rc == -1)
            {
                RemoveSocketObj(thread, sock);
                FreeSocketObj(sock);
                return SOCKET_ERROR;
            }
        }
        else
        {
            fprintf(stderr, "HandleIo: FD_WRITE error %d\n",
                    nevents.iErrorCode[FD_WRITE_BIT]);
            return SOCKET_ERROR;
        }
    }
    if (nevents.lNetworkEvents & FD_CLOSE)
    {
        // Check for close error
        if (nevents.iErrorCode[FD_CLOSE_BIT] == 0)
        {
            // Socket has been indicated as closing so make sure all the data
            // has been read
            while (1)
            {
                rc = ReceivePendingData(sock);
                if (rc == -1)
                {
                    RemoveSocketObj(thread, sock);
                    FreeSocketObj(sock);
                    return SOCKET_ERROR;
                }
                else if (rc != 0)
                {
                    continue;
                }
                else
                {
                    break;
                }
            }
            // See if there is any data pending, if so try to send it
            rc = SendPendingData(sock);
            if (rc == -1)
            {
                RemoveSocketObj(thread, sock);
                FreeSocketObj(sock);
                return SOCKET_ERROR;
            }
        }
        else
        {
            fprintf(stderr, "HandleIo: FD_CLOSE error %d\n",
                    nevents.iErrorCode[FD_CLOSE_BIT]);
            RemoveSocketObj(thread, sock);
            FreeSocketObj(sock);
            return SOCKET_ERROR;
        }
    }
    return NO_ERROR;
}
// 
// Function: WindowProc
//
// Description:
//    This is the window procedure which handles the window messages for
//    our hidden window. It handles all the WM_SOCKET messages and performs
//    the correct actions for each message type (FD_READ, FD_WRITE, etc.).
//
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SOCKET_OBJ  *sockobj=NULL,
                *newsock=NULL;
    int          rc;

    if (uMsg == WM_SOCKET)
    {
        // Check for an error on the socket
        if (WSAGETSELECTERROR(lParam))
        {
            // An error occured on the socket, close it down
            fprintf(stderr, "Socket failed with error %d\n", WSAGETSELECTERROR(lParam));
            closesocket(wParam);
            RemoveSocketObjByHandle(wParam);
        }
        else
        {
            // Find the socket object for this event
            sockobj = FindSocketObj(wParam);
            if (sockobj == NULL)
                return 0;

            switch (WSAGETSELECTEVENT(lParam))
            {
                case FD_ACCEPT:

                    // Get a new object for the client socket
                    newsock = GetSocketObj(INVALID_SOCKET);

                    newsock->s = accept(
                            wParam, 
                            (SOCKADDR *)&newsock->addr, 
                           &newsock->addrlen
                            );
                    if (newsock->s == INVALID_SOCKET)
                    {
                        fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
                        break;
                    }

                    InterlockedIncrement(&gCurrentConnections);

                    // Create a socket information structure to associate with the
                    // socket for processing I/O.
                    InsertSocketObj(newsock);

                    /*
                    printf("Accepted connection from: ");
                    PrintAddress((SOCKADDR *)&newsock->addr, newsock->addrlen);
                    printf("\n");
                    */

                    rc = WSAAsyncSelect(
                            newsock->s, 
                            hwnd, 
                            WM_SOCKET, 
                            FD_READ | FD_WRITE | FD_CLOSE
                            );
                    if (rc == SOCKET_ERROR)
                    {
                        fprintf(stderr, "WSAAsyncSelect failed: %d\n", WSAGetLastError());
                        return -1;
                    }

                    break;
                case FD_READ:
                    rc = ReceivePendingData(sockobj);
                    if (rc == -1)
                    {
                        RemoveSocketObj(sockobj);
                        break;
                    }
                    else if (rc != WSAEWOULDBLOCK)
                    {
                        PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
                    }
                    //
                    // Don't break fall through and attempt to send data
                    //
                case FD_WRITE:
                    //
                    // Send routine automatically tries to send all queued buffers.
                    //
                    rc = SendPendingData(sockobj);
                    if (rc == -1)
                    {
                        RemoveSocketObj(sockobj);
                    }
                    break;
                case FD_CLOSE:
                    sockobj->closing = TRUE;
                    //
                    // Post an FD_READ message to force another receive
                    //    This is to ensure we recv() until 0 is returned.
                    //
                    PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
                    break;
                default:
                    printf("Unknown message received: %d\n", WSAGETSELECTEVENT(lParam));
                    break;
            }
        }
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}