Developing for the Internet with Winsock


Updated Oct 4, 1997

Winsock Class Bugs

  1. Problem: A CStreamSocket object created using the CStreamSocket::Accept function of another CStreamSocket object would not receive Winsock events.

    Solution: The private CStreamSocket constructor that Accept called to create the new socket object was not registering the new socket with the event dispatch mechanism. The solution is to add the code to register the new socket to the private constructor. The correct code for the function is:

    CStreamSocket::CStreamSocket(SOCKET s, CStreamCallback * pCallback,
    	int iToken)
    	: m_s(s), m_iLastError(WSANOERROR), m_pCallback(pCallback),
    	m_iToken(iToken), m_iState(CONNECTED),
    	// 4/18/96: Added initialization of queue pointers.
    	m_pbdHead(NULL), m_pbdTail(NULL) 
    	// 11/17/95: Added the following two lines to register the newly
    	// created socket with the event dispatch mechanism. Previously,
    	// events were enabled on the socket but were simply discarded
    	// by the event dispatch mechansim because the new socket was not
    	// registered with it.
    	SetCallback(pCallback, iToken);
    	Register((WPARAM) m_s, WPARAM_TYPE_SOCKET);
    	WSAAsyncSelect(m_s, WSCGetEventWindow(), WM_WSAASYNCSELECT,
        	FD_READ | FD_WRITE | FD_CLOSE);

  2. Problem: The CStreamSocket::CStreamSocket private constructor shown previously does not correctly initialize the data queue head and tail pointers to NULL when the new object is created.

    Solution: Add the initializaters shown in the code above.

  3. Problem: The CStreamSocket::GetSockName function mistakenly called getpeername rather than getsockname. A simple cut and paste error on my part.

    Solution: Replace the call to getpeername with getsockname.

Mail Client Bugs

  1. Problem: Mail Client can't send mail.

    Solution: The problem is a Win32 vs Win16 difference that didn't get caught in the MAILEDIT.CPP file.

    In Win16, the first parameter to GetTempFileName is the driver on which to store the file. Specifying "0" indicates the current drive. In Win32, GetTempFileName requires you to specify a temporary path as its first parameter (as a string). Specifying "0" causes the GetTempFileName to fail under Win32.

    In the OnMailSend function, find the location where the temp file name is created and replace it with the following code which conditionally compiles for Win32 and Win16:

    	// Get a temp file name from Windows.
    	pdata->pszTempFile = new char[MAX_PATH_LENGTH];
    #ifdef WIN32
    	char TempPath[MAX_PATH_LENGTH];
    	GetTempPath(sizeof(TempPath), TempPath);
    	GetTempFileName(TempPath, "MAIL", 0, pdata->pszTempFile);
    	GetTempFileName(0, "MAIL", 0, pdata->pszTempFile);

    See the altered OnMailSend function in MAILEDIT.CPP.

    [Don't ask me how this got through. I swear I tested sending messages under both Windows NT and Windows 95, and I have no idea why the code even worked. The only way I can explain it is that I must have tested the Win16 version under Windows NT and Windows 95 and though I was testing the Win32 version.]

  2. Problem: Under Windows 95, the Date field of a message generated with Mail Client is blank.

    Solution: The GetCurrentRFC822Date routine in the RFC822.CPP file generates the date for the date field. In the past, the routine relied on the standard library functions tzset, time, and localtime to get the time. For some reason, under Windows 95, trying to read the _tzname[] array, which is supposed to hold the name of the current time zone, produces strange results. It simply sets the entire string that is being formatted in the wsprintf function call to a null string. The workaround for this is to use the Win32 functions GetLocalTime and GetTimeZoneInformation to determine the date. Since these functions are not available under Win16, the original code should be used for the Win16 version of the program.

    Update Oct 4, 1997: The new code for Win32 environments, discussed above, does not correctly set the time zone portion of the date when daylight savings time is in effect. New code has been uploaded that corrects this error.

    See the altered GetCurrentRFC822Date function in RFC822.CPP.

  3. Problem: Mail transmission would hang although the rest of the application would continue to operate.

    Solution: The problem was with the CSMTP::StreamCallback function. In some cases, the call to ReadReplyData in the function would return two response lines from the server: the first a continuation response and the second a standard response. The code in the routine would discard the continuation response, as it should have, but would fail to pass the second line on to the CSMTP state machine. The state machine would hang waiting for the response which was sitting in the response buffer but was being ignored. Changing "if (LineComplete()) {" to "while (LineComplete()) {" eliminates the problem.

    See the altered CSMTP::StreamCallback function in CSMTP.CPP.

  4. Problem: Mail Client skips over the first body part of a multipart message when it goes to display the message.

    Solution: The problem occurs when the first boundary marker occurs as the first line of the body of the multipart message. The multipart parser looks for the boundary string "CRLF--boundary string" rather than just "--boundary string". Since the boundary starts on the first line, there is no leading "CRLF" to match and the parser misses the first body part. The problem can be fixed by decrementing m_lCurrent by two before searching for the first boundary. If the first boundary marker occurs on the first line of the body, then the leading "CRLF" of the search string matches the blank line separting the headers from the body part.

    See the altered CMIMEBodyPart::ParseMultipart in CMIME.CPP.

News Client Bugs

  1. Problem: 32-bit News Client crashes while retrieving news headers.

    Solution: The problem is the same GetTempFileName porting bug between Win16 and Win32 reported for Mail Client, above. The offending code is in the CNNTP.CPP module, function CNNTP::OpenFile. Change the call to GetTempFileName to:

    #ifdef WIN32
                char szTempPath[256];
                GetTempPath(sizeof(szTempPath), szTempPath);
                GetTempFileName(szTempPath, "NWZ", 0, m_szFileName);
                GetTempFileName(0, "NWZ", 0, m_szFileName);

Project Hiccups

  1. Compiler: Visual C++ 2.x

    OS: Windows '95

    Problem: Trying to build the project results in the following error when the resource file is compiled:

    Command line is too long (tool does not support response files).
    Error: Could not generate command line for the Win32 Resource Compiler tool.

    Solution: Go to the Project | Settings menu and select the Resources tab in the dialog box. The "Additional Include Directories" edit control contains two directory entries: ".." and "..\..\common". Delete the ".." directory. It is unneeded and its removal allows the resource compiler to be invoked from the IDE.

  2. Compiler: Visual C++ 2.x

    Problem: Doubling clicking on the MAILCLI.RC file to try to edit it causes:

    fatal error C1024: cannot open include file 'errno.c'

    Solution: The resource editor is trying to compile the file and is not finding the "errno.c" file. Add the directory the file is in (source/common) to the compiler directory path. Select the Tools|Options menu choice in the IDE. Select the Directories tab in the dialog and add the "..\..\common" directory to the search paths.