Пытаюсь сделать туннель. Но вот возникли проблемы. Пакеты фрагментируются и к тому же пакеты rdp могут идти друг за другом, вот тут то и возникли проблемы. Если размер одного пакета я знаю, это WORD по смещению 2, и используя размер читаю его без проблем, а вот если начну проверять следующий то могу заблокировать сокет. Но похоже ещё не только в этом проблема. Может кто то подобное делал? Может есть у кого описание протокола? Код (Text): #include "Tunneling.h" #define DEFAULT_BUFLEN 0x8000 DWORD recv_data(char *recvbuf,SOCKET hsock1,SOCKET hsock2){ int count=0; int iResult; int recvbuflen=0x8000; int iSendResult=0; memset(recvbuf,0,DEFAULT_BUFLEN); DWORD size=0; iResult = recv(hsock1, &recvbuf[count], 4, 0); if ((iResult==-1) || (iResult==0)) return 0; count+=iResult; do{ size+=(((*(WORD*)&recvbuf[size+2]&0xFF00)>>8)|((*(WORD*)&recvbuf[size+2]&0x00FF)<<8)); while(count<size){ if ((count>0x2400)&&(count<0x2700)){ _asm nop; } iResult = recv(hsock1, &recvbuf[count], recvbuflen, 0); if ((iResult==SOCKET_ERROR) || (iResult==0)) return 0; count+=iResult; } }while (count!=size); if (size==46){ _asm nop } iSendResult = send(hsock2, recvbuf, size, 0); return count; } struct Tsock{ SOCKET s1,s2; }; DWORD __stdcall ThreadTunnel(LPVOID param){ Tsock *s=(Tsock*)param; char *mem=new char[DEFAULT_BUFLEN]; int a=1; while(a>0){ a=recv_data(mem,s->s1,s->s2); printf("s: %d\n",a); if (a==0){ _asm nop } } delete []mem; ExitThread(0); return 0; } DWORD recv_send(SOCKET ClientSocket,SOCKET ServerSocket){ // Receive until the peer shuts down the connection int iSendResult=0; int count=0; HANDLE t[2]; Tsock s1,s2; s1.s1=ClientSocket; s1.s2=ServerSocket; t[0]=CreateThread(0,0,ThreadTunnel,&s1,0,0); s2.s2=ClientSocket; s2.s1=ServerSocket; t[1]=CreateThread(0,0,ThreadTunnel,&s2,0,0); WaitForMultipleObjects(2,t,TRUE,-1); return 1; } DWORD server_tunnel(){ //---------------------- // Initialize Winsock. WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != NO_ERROR) { printf("WSAStartup failed with error: %ld\n", iResult); return 1; } //---------------------- // Create a SOCKET for listening for // incoming connection requests. SOCKET ListenSocket; ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { printf("socket failed with error: %ld\n", WSAGetLastError()); WSACleanup(); return 1; } //---------------------- // The sockaddr_in structure specifies the address family, // IP address, and port for the socket that is being bound. sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr("127.0.0.1"); service.sin_port = htons(4444); if (bind(ListenSocket, (SOCKADDR *) & service, sizeof (service)) == SOCKET_ERROR) { printf("bind failed with error: %ld\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return 1; } //---------------------- // Listen for incoming connection requests. // on the created socket if (listen(ListenSocket, 1) == SOCKET_ERROR) { printf("listen failed with error: %ld\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return 1; } //---------------------- // Create a SOCKET for accepting incoming requests. SOCKET AcceptSocket; printf("Waiting for client to connect...\n"); //---------------------- // Accept the connection. while(1){ AcceptSocket = accept(ListenSocket, NULL, NULL); //DWORD opt=10000; //setsockopt(AcceptSocket,SOL_SOCKET,SO_SNDTIMEO,(char*)&opt,4); //setsockopt(AcceptSocket,SOL_SOCKET,SO_RCVTIMEO,(char*)&opt,4); if (AcceptSocket == INVALID_SOCKET) { printf("accept failed with error: %ld\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return 1; } else{ printf("Client connected.\n"); SOCKET hserv_rdp=connect_tunnel(); if (hserv_rdp!=INVALID_SOCKET){ //тут туннель !!! recv_send(AcceptSocket,hserv_rdp); //recv_send(AcceptSocket,hserv_rdp); } iResult = closesocket(hserv_rdp); if (iResult == SOCKET_ERROR) { printf("closesocket function failed with error: %ld\n", WSAGetLastError()); WSACleanup(); return 1; } } } // No longer need server socket closesocket(ListenSocket); WSACleanup(); return 0; } SOCKET connect_tunnel(){ //---------------------- // Initialize Winsock WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != NO_ERROR) { printf("WSAStartup function failed with error: %d\n", iResult); return 0; } //---------------------- // Create a SOCKET for connecting to server SOCKET ConnectSocket; ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //DWORD opt=10000; //setsockopt(ConnectSocket,SOL_SOCKET,SO_SNDTIMEO,(char*)&opt,4); // setsockopt(ConnectSocket,SOL_SOCKET,SO_RCVTIMEO,(char*)&opt,4); if (ConnectSocket == INVALID_SOCKET) { printf("socket function failed with error: %ld\n", WSAGetLastError()); WSACleanup(); return 0; } //---------------------- // The sockaddr_in structure specifies the address family, // IP address, and port of the server to be connected to. sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("192.168.75.128"); clientService.sin_port = htons(3389); //---------------------- // Connect to server. iResult = connect(ConnectSocket, (SOCKADDR *) & clientService, sizeof (clientService)); if (iResult == SOCKET_ERROR) { printf("connect function failed with error: %ld\n", WSAGetLastError()); iResult = closesocket(ConnectSocket); if (iResult == SOCKET_ERROR) printf("closesocket function failed with error: %ld\n", WSAGetLastError()); //WSACleanup(); return 0; } printf("Connected to server.\n"); return ConnectSocket; } int main(int n,char ** arg){ server_tunnel(); //connect_tunnel(); return 0; }
Нашёл исходники, есть всё необходимое http://www.rdesktop.org/ http://ignum.dl.sourceforge.net/project/rdesktop/rdesktop/1.2.0/rdesktop-1.2.0.tar.gz
функцию send нужно тоже контролировать, а то не всегда отправляла данные в сокет. Код (Text): bool tunnel(SOCKET hsock1,SOCKET hsock2){ int iResult; int count=0; char *data=new char[DEFAULT_BUFLEN]; fd_set read_s; timeval time_out; time_out.tv_sec = 0; time_out.tv_usec = 0; FD_ZERO (&read_s); FD_SET (hsock1, &read_s); bool flag=true; while (SOCKET_ERROR == (iResult = select (0, &read_s, NULL, NULL, &time_out) ) ); do{ iResult = recv(hsock1, &data[count], SIZE_RECV, 0); if (iResult>0){ count+=iResult; if (count>DEFAULT_BUFLEN) flag=false; }else{ if (iResult==0){ flag=false; } } }while((iResult>0)&&(flag)); if (count>0) printf("count: %d\n",count); int i=0; bool f=true; while((count>0) && f){ if (count>=SIZE_SEND) iResult=send(hsock2,&data[i],SIZE_SEND,0); else iResult=send(hsock2,&data[i],count,0); if (iResult>0){ i+=iResult; count-=iResult; } if (iResult==0) f=false; FD_ZERO (&read_s); FD_SET (hsock2, &read_s); while (SOCKET_ERROR == (iResult = select (0, NULL,&read_s, NULL, &time_out) ) ); if (iResult==0) f=false; } delete [] data; return flag; }
Runcorn Да вы правы цикл тут вообще лишний! Я пока эксперементировал намудрил немного. Удивительно что это не приводило к зависанию. надо просто так использовать. FD_ZERO (&read_s); FD_SET (hsock1, &read_s); iResult = select (0, &read_s, NULL, NULL, &time_out); FD_ZERO (&read_s); FD_SET (hsock2, &read_s); iResult = select (0, NULL,&read_s, NULL, &time_out); таймаут тут обязателен т.к. сокеты неблокируемые, хоть и равен нулю