/**************************************************************************** Example.c Finger client for windows. A simple example of socket programming using direct WSI commands. Possible character set problems are ignored. It should be noted, that this program can't handle multiple segments when commands send() and recv() are used. In particularly, the result from the finger server (maximum QUERYLEN bytes) is expected to be read within one recv() command. This simplification is acceptable, because following program is intended to be an example of socket programming, not example of segmented input/output. When compiling this module into an executable one, the following files are needed: example.c - this file, main definitions and source code example.def - module definitions (defaults will do) example.rc - resources winsock.lib - information for linker winsock.h - information for compiler This progran runs under Microsoft Windows 3.1 (TM). Executable file requires also functional network and -winsock.dll -pair in order to work properly. ALL RIGHTS RESERVED (c) Ossi Nykänen 1994 ****************************************************************************/ #include #include #include #include #include "winsock.h" #define IDE_QUERY 101 #define NAMELEN 80 #define QUERYLEN 512 #define WM_FSOCKET (WM_USER+1) #define WM_HOSTRESOLVED (WM_USER+2) #define WM_QUERYDONE (WM_USER+3) #define VER 0x0101 /* winsock.dll ver 1.1 */ #define MSG(a) { sprintf(G_str,"FC example [%s]",a); \ SetWindowText(hWnd, (LPCSTR) G_str); } #define ERRMSG(a) MessageBox(GetActiveWindow(),a,"FC Error Message", \ MB_ICONSTOP|MB_OK); #define CANCEL { MSG("Operation canceled") closesocket(G_s); \ G_s=0; return NULL; } /* General static variables required for finger queries. */ static char G_str[160]; /* msgstring */ static char G_name[NAMELEN]; /* query of ... */ static char G_out[NAMELEN+3]; /* name+CRLF-pair */ static char G_query[QUERYLEN]; /* result */ /* Static variables for socket functions. */ static char G_rhost[]={"tarzan.jyu.fi"}; /* remote f-host */ static char G_con=0; /* status of conn */ static SOCKET G_s=0; /* s-descriptor */ static char G_buf[MAXGETHOSTSTRUCT]; /* hostent buffer */ static struct sockaddr_in G_remote_addr; /* address inform */ static struct hostent far *G_remote_host; /* and pointer to */ /***************************************************************************/ int CreateModalDialog(HWND hWnd, char *name, DLGPROC func) /*--------------------------------------------------------------------------- Purpose: Creates a modal dialog. Returns: Status of creation. ---------------------------------------------------------------------------*/ { int ret; FARPROC lpProcFunc; HINSTANCE hInstance; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ hInstance = GetWindowInstance(hWnd); lpProcFunc = MakeProcInstance((FARPROC)func, hInstance); ret = DialogBox(hInstance, name, hWnd, (DLGPROC)lpProcFunc); if (ret==-1) MessageBox(hWnd,name,"Unable to create modal dialog",MB_ICONSTOP|MB_OK); FreeProcInstance(lpProcFunc); return ret; } /***************************************************************************/ BOOL CALLBACK _export FQModalWndProc(HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam) /*-------------------------------------------------------------------------- Purpose: Asks the name for finger guery. Returns: Status of action(s). --------------------------------------------------------------------------*/ { #pragma argsused int ret; switch (message) { case WM_INITDIALOG: SetActiveWindow(GetDlgItem(hWnd,IDE_QUERY)); return TRUE; case WM_CLOSE: EndDialog(hWnd,1); return TRUE; case WM_COMMAND: switch (wParam) { case IDOK: ret = GetWindowText(GetDlgItem(hWnd, IDE_QUERY), (LPSTR) G_name, NAMELEN); if (!ret) return TRUE; EndDialog(hWnd,0); return TRUE; case IDCANCEL: EndDialog(hWnd,1); return TRUE; default: break; } default: break; } return FALSE; } /***************************************************************************/ LONG FAR PASCAL _export MainWndProc(HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam) /*-------------------------------------------------------------------------- Purpose: Main window procedure. Handles socket and main window events. Returns: Status of action(s) --------------------------------------------------------------------------*/ { #pragma argsused int ret,len; HANDLE hret; switch (message) { case WM_CREATE: { WORD wVersionRequested; WSADATA wsaData; int err; /* We require winsock.dll version 1.1. */ wVersionRequested = VER; err = WSAStartup( wVersionRequested, &wsaData ); if ( err!=0 ) return err; if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { ERRMSG("Error - Winsock.dll ver 1.1 not supported.") PostMessage(hWnd,WM_CLOSE,0,0); return NULL; } } return NULL; case WM_FSOCKET: switch (WSAGETSELECTEVENT(lParam)) { case FD_CONNECT: G_con = 1; MSG("Connection") return NULL; case FD_WRITE: if (!G_con) return NULL; MSG("Sendind data...") sprintf(G_out,"%s\r\n",G_name); len = strlen(G_out); send(G_s, (char far *)G_out, len, SO_DONTROUTE); return NULL; case FD_READ: if (!G_con) return NULL; MSG("Receiving data...") ret = recv(G_s, (char far *)G_query, QUERYLEN, 0); if ( ret==SOCKET_ERROR && WSAGetLastError()!=WSAEWOULDBLOCK ) CANCEL G_query[ret] = 0; PostMessage(hWnd,WM_QUERYDONE,0,0); return NULL; case FD_CLOSE: MSG("Connection closed") G_con = 0; closesocket(G_s); return NULL; } return NULL; case WM_HOSTRESOLVED: if (WSAGETASYNCERROR(lParam)) { ERRMSG("Error - No appropriate server/host.") CANCEL } MSG("Host resolved.") G_remote_host = (struct hostent *)G_buf; G_remote_addr.sin_family = AF_INET; G_remote_addr.sin_addr.S_un.S_un_b.s_b1 = G_remote_host->h_addr[0]; G_remote_addr.sin_addr.S_un.S_un_b.s_b2 = G_remote_host->h_addr[1]; G_remote_addr.sin_addr.S_un.S_un_b.s_b3 = G_remote_host->h_addr[2]; G_remote_addr.sin_addr.S_un.S_un_b.s_b4 = G_remote_host->h_addr[3]; G_remote_addr.sin_port = htons(IPPORT_FINGER); ret = connect(G_s,(struct sockaddr far *) &(G_remote_addr), sizeof(struct sockaddr)); if ( ret==SOCKET_ERROR && WSAGetLastError()!=WSAEWOULDBLOCK ) { ERRMSG("Connect() failed.") CANCEL } MSG("Trying to connect...") return NULL; case WM_RBUTTONDOWN: if (!G_s) return NULL; MSG("Closed socket.") closesocket(G_s); G_s = 0; return NULL; case WM_LBUTTONDOWN: if (G_s!=0) { ERRMSG("Previous query on process...") return NULL; } G_con=0; memset(G_query, 0, sizeof(G_query)); ret = CreateModalDialog(hWnd,"DIALOG_1",FQModalWndProc); if (ret) return NULL; G_s = (SOCKET)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (G_s==INVALID_SOCKET) { ERRMSG("Socket() failed.") return NULL; } MSG("Created socket.") ret = WSAAsyncSelect(G_s, hWnd, WM_FSOCKET, FD_CONNECT|FD_CLOSE|FD_READ|FD_WRITE); if (ret==SOCKET_ERROR) { ERRMSG("WSAAsyncSelect() failed.") CANCEL } MSG("WSAAsyncSelect ready.") hret = WSAAsyncGetHostByName(hWnd, WM_HOSTRESOLVED, G_rhost, G_buf, sizeof(G_buf)); if ( !hret ) { ERRMSG("WSAAsyncGetHostByName() failed.") CANCEL } MSG("Resolving host...") return NULL; case WM_QUERYDONE: G_s = 0; MessageBox(hWnd, G_query, "Finger query results", MB_ICONINFORMATION|MB_OK); return NULL; case WM_CLOSE: DestroyWindow(hWnd); return NULL; case WM_DESTROY: if (G_s) closesocket(G_s); WSACleanup(); PostQuitMessage(0); return NULL; default: break; } return (DefWindowProc(hWnd, message, wParam, lParam)); } /***************************************************************************/ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) /*-------------------------------------------------------------------------- Purpose: WinMain. Returns: 0 --------------------------------------------------------------------------*/ { #pragma argsused WNDCLASS wc; HWND hWnd; MSG msg; if (!hPrevInstance) { wc.style = NULL; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "SEWClass"; if (!RegisterClass(&wc)) return (FALSE); } hWnd = CreateWindow("SEWClass","FC example",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,hInstance,NULL); if (!hWnd) return (FALSE); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while (GetMessage(&msg,NULL,NULL,NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); } UnregisterClass("SEWClass",hInstance); return msg.wParam; }