300 lines
7.9 KiB
C
300 lines
7.9 KiB
C
|
/*
|
||
|
* Copyright (c) Microsoft Corporation
|
||
|
*
|
||
|
* Module Name :
|
||
|
* main.c
|
||
|
*
|
||
|
* This is the main file containing the client code.
|
||
|
*
|
||
|
*
|
||
|
* Sadagopan Rajaram -- Oct 14, 1999
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
// Can kill this program on a normal NT console using the
|
||
|
// Alt - X Key combination. Just a shortcut, that is all.
|
||
|
// Serves no useful purpose.
|
||
|
|
||
|
#include "tcclnt.h"
|
||
|
#include "tcsrvc.h"
|
||
|
|
||
|
WSABUF ReceiveBuffer;
|
||
|
CHAR RecvBuf[MAX_BUFFER_SIZE];
|
||
|
IO_STATUS_BLOCK IoStatus;
|
||
|
HANDLE InputHandle;
|
||
|
DWORD bytesRecvd;
|
||
|
WSAOVERLAPPED junk;
|
||
|
SOCKET cli_sock;
|
||
|
DWORD flags;
|
||
|
|
||
|
#if _MSC_FULL_VER >= 13008827
|
||
|
#pragma warning(push)
|
||
|
#pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
|
||
|
#endif
|
||
|
|
||
|
DWORD
|
||
|
inputUpdate(
|
||
|
PVOID dummy
|
||
|
)
|
||
|
{
|
||
|
// Runs in a single thread getting all the inputs
|
||
|
// from the keyboard.
|
||
|
|
||
|
ULONG result;
|
||
|
// gets a multibyte string for every character
|
||
|
// pressed on the keyboard.
|
||
|
CHAR r[MB_CUR_MAX + 1];
|
||
|
|
||
|
while(1){
|
||
|
r[0] = _T('\0');
|
||
|
inchar(r);
|
||
|
// BUGBUG - Performance issues in sending a single character
|
||
|
// at a time across the n/w
|
||
|
if(strlen(r)){
|
||
|
// may send a single byte or two bytes.
|
||
|
send(cli_sock,r,strlen(r),0);
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
#if _MSC_FULL_VER >= 13008827
|
||
|
#pragma warning(pop)
|
||
|
#endif
|
||
|
|
||
|
VOID sendUpdate(
|
||
|
IN DWORD dwError,
|
||
|
IN DWORD cbTransferred,
|
||
|
IN LPWSAOVERLAPPED lpOverLapped,
|
||
|
IN DWORD dwFlags
|
||
|
)
|
||
|
{
|
||
|
int error,i;
|
||
|
// Receives a packet and sends it through the stream parser
|
||
|
// BUGBUG - For effeciency it can be made inline.
|
||
|
// I am not sure of the performance increase, but it should
|
||
|
// be substantial as we will be sending a lot of data.
|
||
|
|
||
|
if(dwError != 0){
|
||
|
exit(1);
|
||
|
}
|
||
|
for(i=0;i < (int)cbTransferred;i++){
|
||
|
PrintChar(ReceiveBuffer.buf[i]);
|
||
|
}
|
||
|
// Repost the receive on the socket.
|
||
|
|
||
|
error = WSARecv(cli_sock,
|
||
|
&ReceiveBuffer,
|
||
|
1,
|
||
|
&bytesRecvd,
|
||
|
&flags,
|
||
|
&junk,
|
||
|
sendUpdate
|
||
|
);
|
||
|
if((error == SOCKET_ERROR)
|
||
|
&&(WSAGetLastError()!=WSA_IO_PENDING)){
|
||
|
// Implies something wrong with the socket.
|
||
|
exit(1);
|
||
|
}
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
int __cdecl
|
||
|
main(
|
||
|
IN int argc,
|
||
|
char *argv[]
|
||
|
)
|
||
|
/*++
|
||
|
Opens a single port, binds to the tcserver and passes information back and forth.
|
||
|
--*/
|
||
|
{
|
||
|
struct sockaddr_in srv_addr,cli_addr;
|
||
|
LPHOSTENT host_info;
|
||
|
CLIENT_INFO SendInfo;
|
||
|
int status;
|
||
|
WSADATA data;
|
||
|
#ifdef UNICODE
|
||
|
// BUGBUG - Trying to write a code that works for
|
||
|
// both Unicode and ASCII. Gets multi byte sequences
|
||
|
// Confusion when the tcclnt and tcclnt are in different
|
||
|
// modes.
|
||
|
ANSI_STRING Src;
|
||
|
UNICODE_STRING Dest;
|
||
|
#endif
|
||
|
NTSTATUS Status;
|
||
|
HANDLE Thread;
|
||
|
DWORD ThreadId;
|
||
|
COORD coord;
|
||
|
SMALL_RECT rect;
|
||
|
int RetVal;
|
||
|
struct hostent *ht;
|
||
|
ULONG r;
|
||
|
TCHAR Buffer[80];
|
||
|
|
||
|
|
||
|
|
||
|
if((argc<2) || (argc >4)){
|
||
|
// Error in running the program
|
||
|
printf("Usage - tcclnt COMPORTNAME [ipaddress]\n");
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
ThreadId = GetEnvironmentVariable(_T("TERM"),Buffer , 80);
|
||
|
// We need to know if we have a vt100 screen or an ANSI screen.
|
||
|
AttributeFunction = ProcessTextAttributes;
|
||
|
if(ThreadId >0){
|
||
|
// Terminal type exists in the environment.
|
||
|
// Use it
|
||
|
if((_tcsncmp(Buffer, _T("VT100"), 5) == 0)||
|
||
|
_tcsncmp(Buffer, _T("vt100"),5) ==0 )
|
||
|
AttributeFunction = vt100Attributes;
|
||
|
}
|
||
|
|
||
|
hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
|
coord.X = MAX_TERMINAL_WIDTH;
|
||
|
coord.Y = MAX_TERMINAL_HEIGHT;
|
||
|
rect.Left = rect.Top = 0;
|
||
|
rect.Right = MAX_TERMINAL_WIDTH -1;
|
||
|
rect.Bottom = MAX_TERMINAL_HEIGHT -1;
|
||
|
|
||
|
if(hConsoleOutput == NULL){
|
||
|
printf("Could not get current console handle %d\n", GetLastError());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
RetVal = SetConsoleScreenBufferSize(hConsoleOutput,
|
||
|
coord
|
||
|
);
|
||
|
|
||
|
RetVal = SetConsoleWindowInfo(hConsoleOutput,
|
||
|
TRUE,
|
||
|
&rect
|
||
|
);
|
||
|
if (RetVal == FALSE) {
|
||
|
printf("Could not set window size %d\n", GetLastError());
|
||
|
return 1;
|
||
|
}
|
||
|
RetVal = SetConsoleMode(hConsoleOutput,ENABLE_PROCESSED_OUTPUT);
|
||
|
if(RetVal == FALSE){
|
||
|
printf("Could not console mode %d\n", GetLastError());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* Set up client socket */
|
||
|
InputHandle = GetStdHandle(STD_INPUT_HANDLE);
|
||
|
if(InputHandle == NULL) return 1;
|
||
|
SetConsoleMode(InputHandle, 0);
|
||
|
status=WSAStartup(514,&data);
|
||
|
|
||
|
if(status){
|
||
|
printf("Cannot start up %d\n",status);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
cli_sock=WSASocket(PF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
|
||
|
|
||
|
if (cli_sock==INVALID_SOCKET){
|
||
|
printf("Windows Sockets error %d: Couldn't create socket.",
|
||
|
WSAGetLastError());
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
cli_addr.sin_family=AF_INET;
|
||
|
cli_addr.sin_addr.s_addr=INADDR_ANY;
|
||
|
cli_addr.sin_port=0; /* no specific port req'd */
|
||
|
|
||
|
/* Bind client socket to any local interface and port */
|
||
|
|
||
|
if (bind(cli_sock,(LPSOCKADDR)&cli_addr,sizeof(cli_addr))==SOCKET_ERROR){
|
||
|
printf("Windows Sockets error %d: Couldn't bind socket.",
|
||
|
WSAGetLastError());
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
srv_addr.sin_family = AF_INET;
|
||
|
if(argc == 3){
|
||
|
srv_addr.sin_addr.s_addr = inet_addr(argv[2]);
|
||
|
if (srv_addr.sin_addr.s_addr == INADDR_NONE) {
|
||
|
ht = gethostbyname(argv[2]);
|
||
|
if(!ht || !ht->h_addr){ // cannot resolve the name
|
||
|
printf("Cannot resolve %s", argv[2]);
|
||
|
exit(1);
|
||
|
}
|
||
|
memcpy((&(srv_addr.sin_addr.s_addr)),ht->h_addr, ht->h_length);
|
||
|
}
|
||
|
}
|
||
|
else{
|
||
|
srv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||
|
}
|
||
|
srv_addr.sin_port=htons(SERVICE_PORT);
|
||
|
|
||
|
/* Connect to FTP server at address SERVER */
|
||
|
|
||
|
if (connect(cli_sock,(LPSOCKADDR)&srv_addr,sizeof(srv_addr))==SOCKET_ERROR){
|
||
|
printf("Windows Sockets error %d: Couldn't connect socket.\n",
|
||
|
WSAGetLastError());
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
SendInfo.len = sizeof(CLIENT_INFO);
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
Src.Buffer = argv[1];
|
||
|
Src.Length = (USHORT)strlen(argv[1]);
|
||
|
Dest.Buffer = SendInfo.device;
|
||
|
Dest.MaximumLength = MAX_BUFFER_SIZE;
|
||
|
Status = RtlAnsiStringToUnicodeString(&Dest, &Src, FALSE);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
printf("RtlAnsiStringToUnicodeString failed, ec = 0x%08x\n",Status);
|
||
|
exit(1);
|
||
|
}
|
||
|
send(cli_sock, (PCHAR) &SendInfo, sizeof(CLIENT_INFO), 0);
|
||
|
#else
|
||
|
// We are sending to an ANSI String
|
||
|
strcpy(SendInfo.device, argv[1]);
|
||
|
send(cli_sock, (PCHAR) &SendInfo, sizeof(CLIENT_INFO), 0);
|
||
|
#endif
|
||
|
ReceiveBuffer.len = MAX_BUFFER_SIZE;
|
||
|
ReceiveBuffer.buf = RecvBuf;
|
||
|
status=WSARecv(cli_sock,
|
||
|
&ReceiveBuffer,
|
||
|
1,
|
||
|
&bytesRecvd,
|
||
|
&flags,
|
||
|
&junk,
|
||
|
sendUpdate
|
||
|
);
|
||
|
if((status == SOCKET_ERROR)
|
||
|
&&(WSAGetLastError() != WSA_IO_PENDING)){
|
||
|
printf("Error in recv %d\n",WSAGetLastError());
|
||
|
exit(1);
|
||
|
}
|
||
|
// Create a thread that gets input from the console
|
||
|
// to send to the bridge.
|
||
|
Thread = CreateThread(NULL,
|
||
|
0,
|
||
|
inputUpdate,
|
||
|
NULL,
|
||
|
0,
|
||
|
&ThreadId
|
||
|
);
|
||
|
if (Thread== NULL) {
|
||
|
exit(1);
|
||
|
}
|
||
|
CloseHandle(Thread);
|
||
|
|
||
|
while(1){
|
||
|
// Put this thread in an alertable
|
||
|
// state so that the receive calls can
|
||
|
// asynchronously terminate within the
|
||
|
// context of this thread.
|
||
|
status=SleepEx(INFINITE,TRUE);
|
||
|
}
|
||
|
// We never return here.
|
||
|
closesocket(cli_sock);
|
||
|
return 0;
|
||
|
}
|
||
|
|