/**************************************************************************** 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" #include "socksend.h" #include "mjonot.h" #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.Q.str,"Host: %s [%s]",G.S.rhost,a); \ SetWindowText(hWnd, (LPCSTR) G.Q.str); } #define ERRMSG(a) MessageBox(GetActiveWindow(),a,G.S.rhost, \ MB_ICONSTOP|MB_OK) /* General static variables required for finger queries. */ typedef struct { char str[160]; /* msgstring */ const char *out; /* name+CRLF-pair */ int outlen; char *query; /* result */ int querylen; } tQuery; /* Static variables for socket functions. */ typedef struct { const char *rhost; /* remote f-host */ int port; char con; /* status of conn */ SOCKET s; /* s-descriptor */ char buf[MAXGETHOSTSTRUCT]; /* hostent buffer */ struct sockaddr_in remote_addr; /* address inform */ struct hostent far *remote_host; /* and pointer to */ int error; int timeout; } tSocket; typedef struct { tQuery Q; tSocket S; int run; /* Indicator for active window */ int modal; } tSocketSend; static tSocketSend G; #define CANCEL(a) cancel(hWnd,a) /***************************************************************************/ static LONG cancel(HWND hWnd,const char *a) { MSG("Operation canceled"); PostMessage(hWnd,WM_CLOSE,0,0); kopioi_jono(G.Q.query,G.Q.querylen,a); return NULL; } /***************************************************************************/ LONG FAR PASCAL _export MainSocketWndProc(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; 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 ) return CANCEL("Error - Winsock.dll ver 1.1 not supported."); G.run = 1; if ( G.modal ) SetCapture(hWnd); PostMessage(hWnd,WM_USER,0,0); if ( G.S.timeout ) SetTimer(hWnd,1,G.S.timeout,NULL); } return NULL; case WM_FSOCKET: switch (WSAGETSELECTEVENT(lParam)) { case FD_CONNECT: G.S.con = 1; MSG("Connection"); return NULL; case FD_WRITE: if ( !G.S.con ) return NULL; MSG("Sendind data..."); send(G.S.s, G.Q.out, G.Q.outlen, SO_DONTROUTE); return NULL; case FD_READ: if ( !G.S.con ) return NULL; MSG("Receiving data..."); ret = recv(G.S.s, G.Q.query, G.Q.querylen, 0); if ( ret==SOCKET_ERROR && WSAGetLastError()!=WSAEWOULDBLOCK ) return CANCEL("Socket error"); G.Q.query[ret] = 0; // PostMessage(hWnd,WM_QUERYDONE,0,0); return NULL; case FD_CLOSE: MSG("Connection closed"); G.S.con = 0; PostMessage(hWnd,WM_QUERYDONE,0,0); return NULL; } return NULL; case WM_HOSTRESOLVED: if (WSAGETASYNCERROR(lParam)) return CANCEL("Error - No appropriate server/host."); MSG("Host resolved.") G.S.remote_host = (struct hostent *)G.S.buf; G.S.remote_addr.sin_family = AF_INET; G.S.remote_addr.sin_addr.S_un.S_un_b.s_b1 = G.S.remote_host->h_addr[0]; G.S.remote_addr.sin_addr.S_un.S_un_b.s_b2 = G.S.remote_host->h_addr[1]; G.S.remote_addr.sin_addr.S_un.S_un_b.s_b3 = G.S.remote_host->h_addr[2]; G.S.remote_addr.sin_addr.S_un.S_un_b.s_b4 = G.S.remote_host->h_addr[3]; G.S.remote_addr.sin_port = htons(G.S.port); ret = connect(G.S.s,(struct sockaddr far *)&(G.S.remote_addr), sizeof(struct sockaddr)); if ( ret==SOCKET_ERROR && WSAGetLastError()!=WSAEWOULDBLOCK ) return CANCEL("Connect() failed."); MSG("Trying to connect...") return NULL; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: return CANCEL("User break!"); case WM_USER: if ( G.S.s != 0 ) { ERRMSG("Previous query on process..."); return NULL; } G.S.con=0; memset(G.Q.query, 0, G.Q.querylen); G.S.s = (SOCKET)socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (G.S.s==INVALID_SOCKET) return CANCEL("Socket() failed."); MSG("Created socket.") ret = WSAAsyncSelect(G.S.s, hWnd, WM_FSOCKET, FD_CONNECT|FD_CLOSE|FD_READ|FD_WRITE); if (ret==SOCKET_ERROR) return CANCEL("WSAAsyncSelect() failed."); MSG("WSAAsyncSelect ready.") hret = WSAAsyncGetHostByName(hWnd, WM_HOSTRESOLVED, G.S.rhost, G.S.buf, sizeof(G.S.buf)); if ( !hret ) return CANCEL("WSAAsyncGetHostByName() failed."); MSG("Resolving host...") return NULL; case WM_QUERYDONE: G.S.error = 0; DestroyWindow(hWnd); return NULL; case WM_TIMER: return CANCEL("Timeout"); case WM_CLOSE: DestroyWindow(hWnd); return NULL; case WM_DESTROY: if ( G.S.timeout ) KillTimer(hWnd,1); MSG("Closed socket.") if ( G.S.s ) closesocket( G.S.s ); G.S.s = 0; G.S.con=0; WSACleanup(); ReleaseCapture(); // PostQuitMessage(0); G.run = 0; return NULL; default: break; } return (DefWindowProc(hWnd, message, wParam, lParam)); } /***************************************************************************/ int SocketSendString(HWND hMWnd,int port,const char *host, const char *sendnow, int sendlen, int timeout, int modal, char *receive, int maxreceive) /*-------------------------------------------------------------------------- Returns: 0 in success 1 in error and receive contains error message --------------------------------------------------------------------------*/ { #pragma argsused WNDCLASS wc; HWND hWnd; MSG msg; RECT rc; HINSTANCE hInstance = GetWindowInstance(hMWnd); receive[0] = 0; G.Q.out = sendnow; G.Q.outlen = sendlen; G.Q.query = receive; G.Q.querylen = maxreceive; G.S.rhost = host; G.S.port = port; G.S.error = 1; G.S.timeout = timeout; G.modal = modal; wc.style = NULL; wc.lpfnWndProc = MainSocketWndProc; 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 1; GetWindowRect(hMWnd,&rc); hWnd = CreateWindow("SEWClass","FC example", WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, rc.left,rc.top,rc.right-rc.left,0, hMWnd,NULL,hInstance,NULL); if ( !hWnd ) return 2; ShowWindow(hWnd,SW_SHOW ); UpdateWindow(hWnd); while (GetMessage(&msg,NULL,NULL,NULL) && G.run ) { TranslateMessage(&msg); DispatchMessage(&msg); } UnregisterClass("SEWClass",hInstance); return G.S.error; }