pjs/msgsdk/C/src/nsio.c

840 строки
20 KiB
C

/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the License.
*
* The Original Code is the Netscape Messaging Access SDK Version 3.5 code,
* released on or about June 15, 1998.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998 Netscape
* Communications Corporation. All Rights Reserved.
*
* Contributor(s): ______________________________________.
*/
/*
* Copyright (c) 1997 and 1998 Netscape Communications Corporation
* (http://home.netscape.com/misc/trademarks.html)
*/
/*
* nsio.c
* @author derekt@netscape.com
* @version 1.0
*/
#include "nsmail.h"
#include "nsio.h"
#include "nssocket.h"
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include <stdio.h>
/* Internal functions not to be used directly. */
int IO_checkTimeout( IO_t * in_pIO );
void IO_resetFunctions( IO_t * in_pIO );
int UpdateBuffer( IO_t * in_pIO );
/* Initalize the IO structure. */
int IO_initialize( IO_t * in_pIO,
unsigned int in_readBufferLimit,
unsigned int in_writeBufferLimit )
{
/*
* Parameter validation.
*/
if ( in_pIO == NULL ||
in_pIO->readBuffer != NULL ||
in_pIO->writeBuffer != NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
if ( in_readBufferLimit == 0 )
{
in_pIO->readBufferLimit = DEFAULT_BUFFER_LENGTH;
}
else
{
in_pIO->readBufferLimit = in_readBufferLimit;
}
if ( in_writeBufferLimit == 0 )
{
in_pIO->writeBufferLimit = DEFAULT_BUFFER_LENGTH;
}
else
{
in_pIO->writeBufferLimit = in_writeBufferLimit;
}
/*
* Set the socket descriptor to an invalid value to identify a
* disconnected state.
*/
in_pIO->socket = -1;
/*
* Initialize the read buffer.
*/
in_pIO->readBuffer = (char*)malloc( in_pIO->readBufferLimit * sizeof( char ) );
if ( in_pIO->readBuffer == NULL )
{
return NSMAIL_ERR_OUTOFMEMORY;
}
memset(in_pIO->readBuffer, 0, in_pIO->readBufferLimit * sizeof( char ) );
/*
* Initialize the write buffer.
*/
in_pIO->writeBuffer = (char*)malloc( in_pIO->writeBufferLimit * sizeof( char ) );
if ( in_pIO->writeBuffer == NULL )
{
return NSMAIL_ERR_OUTOFMEMORY;
}
memset(in_pIO->writeBuffer, 0, in_pIO->writeBufferLimit * sizeof( char ) );
/* Set the current size of the write buffer. */
in_pIO->writeBufferSize = 0;
/* Set the current size of the read buffer. */
in_pIO->readBufferSize = 0;
/* Set the IO function pointers. */
IO_resetFunctions( in_pIO );
/* Set the default timeout value. */
return IO_setTimeout( in_pIO, -1 );
}
/* Free the IO structure. */
void IO_free( IO_t * in_pIO )
{
if ( in_pIO == NULL )
{
return;
}
/*
* Reset the data members.
*/
if ( in_pIO->readBuffer != NULL )
{
free( in_pIO->readBuffer );
in_pIO->readBuffer = NULL;
}
if ( in_pIO->writeBuffer != NULL )
{
free( in_pIO->writeBuffer );
in_pIO->writeBuffer = NULL;
}
/*
* Terminate the socket session.
*/
NSSock_Terminate();
}
/* Connect to the specified server with the specified port. */
int IO_connect( IO_t * in_pIO, const char * in_szServer, unsigned short in_nPort )
{
struct sockaddr_in l_hostInetAddr;
LinkedList_t * l_addressList;
LinkedList_t * l_tempList;
int fHostIsIPAddr;
int dotCount = 0;
int i;
/*
* Parameter validation.
*/
if ( in_pIO == NULL || in_szServer == NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
if ( in_pIO->socket > 0 )
{
return NSMAIL_ERR_ALREADYCONNECTED;
}
/*
* Initialize the socket session.
*/
NSSock_Initialize();
/*
* Create a handle to the new socket.
*/
in_pIO->socket = in_pIO->ioFunctions.liof_socket( AF_INET, SOCK_STREAM, 0 );
if ( in_pIO->socket < 0 )
{
return NSMAIL_ERR_IO_SOCKET;
}
/* initialize the address structures */
memset (&l_hostInetAddr, 0, sizeof(l_hostInetAddr));
l_hostInetAddr.sin_family = AF_INET;
l_hostInetAddr.sin_port = htons(in_nPort);
/*
* Determine if a host name or IP address was specified. Assume
* it is, then see if we can find something that means it isn't.
* (The test below is not very careful, it should verify there
* are numbers between the dots, and the numbers are less than 256.)
*/
fHostIsIPAddr = 1;
for (i=0; i<strlen(in_szServer); ++i) {
if (in_szServer[i] == '.') {
++dotCount;
}
else if (!isdigit(in_szServer[i])) {
fHostIsIPAddr = 0;
break;
}
}
if (dotCount != 3) {
fHostIsIPAddr = 0;
}
if ( fHostIsIPAddr )
{
l_hostInetAddr.sin_addr.s_addr = inet_addr( (char *)in_szServer );
if ( in_pIO->ioFunctions.liof_connect(
in_pIO->socket,
(const struct sockaddr *)&l_hostInetAddr,
in_nPort ) != FALSE )
{
return NSMAIL_OK;
}
}
else
{
l_addressList = NSSock_GetHostByName( in_szServer );
while ( l_addressList != NULL )
{
if ( ( l_hostInetAddr.sin_addr.s_addr = inet_addr(l_addressList->pData) ) != 0 )
{
if ( in_pIO->ioFunctions.liof_connect(
in_pIO->socket,
(const struct sockaddr *)&l_hostInetAddr,
in_nPort ) != FALSE )
{
while ( l_addressList != NULL )
{
free( l_addressList->pData );
l_tempList = l_addressList;
l_addressList = l_tempList->next;
free( l_tempList );
}
return NSMAIL_OK;
}
}
free( l_addressList->pData );
l_tempList = l_addressList;
l_addressList = l_tempList->next;
free( l_tempList );
}
}
in_pIO->socket = -1;
return NSMAIL_ERR_IO_CONNECT;
}
/* Disconnect from the server. */
int IO_disconnect( IO_t * in_pIO )
{
/*
* Parameter validation.
*/
if ( in_pIO == NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
if ( in_pIO->socket < 0 )
{
return NSMAIL_ERR_NOTCONNECTED;
}
/*
* Close the socket.
*/
if ( in_pIO->ioFunctions.liof_close( in_pIO->socket ) == FALSE )
{
in_pIO->socket = -1;
return NSMAIL_ERR_IO_CLOSE;
}
in_pIO->socket = -1;
return NSMAIL_OK;
}
/*Send data to the server appending the \r\n and optionally flushing.*/
int IO_send( IO_t * in_pIO, const char * in_data, boolean in_bufferData )
{
int l_nReturn;
l_nReturn = IO_write( in_pIO, in_data, strlen(in_data) );
if ( l_nReturn != NSMAIL_OK )
{
return l_nReturn;
}
l_nReturn = IO_write( in_pIO, eoline, 2 );
if ( l_nReturn != NSMAIL_OK )
{
return l_nReturn;
}
if ( in_bufferData == FALSE )
{
l_nReturn = IO_flush( in_pIO );
if ( l_nReturn != NSMAIL_OK )
{
return l_nReturn;
}
}
return NSMAIL_OK;
}
/* Write operation to the buffered socket. */
int IO_write( IO_t * in_pIO, const char * in_data, unsigned int in_length )
{
int l_nReturn;
/* Parameter validation.*/
if ( in_pIO == NULL || in_data == NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
if ( in_pIO->socket < 0 )
{
return NSMAIL_ERR_NOTCONNECTED;
}
/* Fill the buffer and send the data if it is full. */
if ( in_pIO->writeBufferSize + in_length < in_pIO->writeBufferLimit )
{
memcpy( &(in_pIO->writeBuffer[in_pIO->writeBufferSize]),
in_data,
in_length );
in_pIO->writeBufferSize += in_length;
}
else
{
l_nReturn = IO_flush( in_pIO );
if ( l_nReturn != NSMAIL_OK )
{
return l_nReturn;
}
if ( in_length < in_pIO->writeBufferLimit )
{
memcpy( in_pIO->writeBuffer, in_data, in_length );
in_pIO->writeBufferSize = in_length;
}
else
{
if ( in_pIO->ioFunctions.liof_write( in_pIO->socket,
(char*)in_data,
in_length ) == FALSE )
{
return NSMAIL_ERR_IO_WRITE;
}
}
}
return NSMAIL_OK;
}
int IO_writeByte( IO_t * in_pIO, const char in_byte )
{
int l_nReturn;
/* Parameter validation */
if ( in_pIO == NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
if ( in_pIO->socket < 0 )
{
return NSMAIL_ERR_NOTCONNECTED;
}
/*
* Fill the buffer and send the data if it is full.
*/
if ( in_pIO->writeBufferSize + 1 < in_pIO->writeBufferLimit )
{
in_pIO->writeBuffer[(in_pIO->writeBufferSize)++] = in_byte;
}
else
{
l_nReturn = IO_flush( in_pIO );
if ( l_nReturn != NSMAIL_OK )
{
return l_nReturn;
}
in_pIO->writeBuffer[(in_pIO->writeBufferSize)++] = in_byte;
}
return NSMAIL_OK;
}
int IO_flush( IO_t * in_pIO )
{
/* Parameter validation */
if ( in_pIO == NULL || in_pIO->writeBuffer == NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
if ( in_pIO->socket < 0 )
{
return NSMAIL_ERR_NOTCONNECTED;
}
/* Send the data and verify that it was sent ok. */
if ( in_pIO->writeBufferSize > 0 )
{
if ( in_pIO->ioFunctions.liof_write( in_pIO->socket,
(char*)in_pIO->writeBuffer,
in_pIO->writeBufferSize ) == FALSE )
{
return NSMAIL_ERR_IO_WRITE;
}
memset( in_pIO->writeBuffer, 0, in_pIO->writeBufferLimit );
in_pIO->writeBufferSize = 0;
}
return NSMAIL_OK;
}
/**
* Read in in_size bytes into out_response
* @param in_pIO The IO structure
* @param out_ppResponse The memory to store the data in
* @param in_size The amount of data requested
& @param out_bytesRead The total number of bytes read
*/
int IO_read( IO_t * in_pIO, char * out_response, int in_size, int * out_bytesRead )
{
int l_returnCode;
int l_bytesRead = 0;
int l_bytesToRead = 0;
int l_offset = 0;
/* Parameter validation. */
if ((in_pIO == NULL) || (out_response == NULL) ||
(in_size < 1) || (out_bytesRead == NULL))
{
return NSMAIL_ERR_INVALIDPARAM;
}
/* Make sure the IO buffer is not empty */
if ( in_pIO->readBufferSize == 0 )
{
l_returnCode = UpdateBuffer( in_pIO );
if ( l_returnCode != NSMAIL_OK )
{
return l_returnCode;
}
}
/* Read in_size bytes */
while ( l_bytesRead < in_size )
{
/* Determine amount of data to read in from the IO buffer */
if( (in_pIO->readBufferSize + l_bytesRead) <= in_size)
{
l_bytesToRead = in_pIO->readBufferSize;
}
else
{
l_bytesToRead = in_size - l_bytesRead;
}
memcpy(out_response + l_bytesRead, in_pIO->readBuffer, l_bytesToRead);
in_pIO->readBufferSize -= l_bytesToRead;
l_bytesRead += l_bytesToRead;
l_offset += l_bytesToRead;
/* Make sure the IO buffer is not empty */
if ( in_pIO->readBufferSize == 0 )
{
l_returnCode = UpdateBuffer( in_pIO );
if ( l_returnCode != NSMAIL_OK )
{
return l_returnCode;
}
l_offset = 0;
}
}
/* Move the rest of the buffer to the beginning of the buffer. */
memcpy( in_pIO->readBuffer, (&in_pIO->readBuffer[l_offset]), in_pIO->readBufferSize );
(*out_bytesRead) = l_bytesRead;
return NSMAIL_OK;;
}
/* Reads a line from the socket. */
int IO_readLine( IO_t * in_pIO, char * out_response, int in_maxLength )
{
int l_returnCode;
unsigned int offset = 0;
/* Parameter validation. */
if ( in_pIO == NULL || out_response == NULL || out_response == NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
if ( in_pIO->socket < 0 )
{
return NSMAIL_ERR_NOTCONNECTED;
}
if ( in_pIO->readBufferSize == 0 )
{
l_returnCode = UpdateBuffer( in_pIO );
if ( l_returnCode != NSMAIL_OK )
{
return l_returnCode;
}
}
/* Read byte by byte looking for the newline character. */
while ( in_pIO->readBuffer[offset] != '\n' )
{
offset++;
if ( offset == in_pIO->readBufferSize )
{
if ( offset == in_pIO->readBufferLimit )
{
return NSMAIL_ERR_UNEXPECTED;
}
l_returnCode = UpdateBuffer( in_pIO );
if ( l_returnCode != NSMAIL_OK )
{
return l_returnCode;
}
}
}
if ( offset > in_maxLength )
{
return NSMAIL_ERR_UNEXPECTED;
}
/* Copy the line into the buffer. */
memcpy( out_response, in_pIO->readBuffer, offset + 1 );
in_pIO->readBufferSize -= (offset + 1);
/* Move the rest of the buffer to the beginning of the buffer. */
memcpy( in_pIO->readBuffer,
(&in_pIO->readBuffer[offset+1]),
in_pIO->readBufferSize );
/*
* Look for the carriage return character.
* If it is there, place the null character there,
* else put the null character in the location of the linefeed character.
*/
if ( out_response[offset-1] == '\r' )
{
out_response[offset-1] = '\0';
}
else
{
out_response[offset] = '\0';
}
return NSMAIL_OK;;
}
/* Reads a line from the socket and dynamically allocates the necessary space for the response */
int IO_readDLine( IO_t * in_pIO, char** out_ppResponse )
{
int l_returnCode;
unsigned int offset = 0;
char* l_tempBuffer = NULL;
int l_bufferlength = 0;
/* Parameter validation. */
if ( in_pIO == NULL || (*out_ppResponse) != NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
if ( in_pIO->socket < 0 )
{
return NSMAIL_ERR_NOTCONNECTED;
}
/* Make sure the IO buffer is not empty */
while( in_pIO->readBufferSize == 0 )
{
l_returnCode = UpdateBuffer( in_pIO );
if ( l_returnCode != NSMAIL_OK )
{
return l_returnCode;
}
}
/* Read byte by byte looking for the newline character. */
while(in_pIO->readBuffer[offset] != '\n')
{
offset++;
if(offset >= in_pIO->readBufferSize)
{
if(offset == in_pIO->readBufferLimit)
{
/*Grow the size of the read buffer*/
l_bufferlength = in_pIO->readBufferLimit + DEFAULT_BUFFER_LENGTH;
l_tempBuffer = in_pIO->readBuffer;
in_pIO->readBuffer = (char*)malloc(l_bufferlength*sizeof(char));
if(in_pIO->readBuffer == NULL)
{
return NSMAIL_ERR_OUTOFMEMORY;
}
memset(in_pIO->readBuffer, 0, l_bufferlength*sizeof(char));
in_pIO->readBufferLimit = l_bufferlength;
memcpy( in_pIO->readBuffer,
l_tempBuffer,
in_pIO->readBufferSize );
free(l_tempBuffer);
l_tempBuffer = NULL;
}
while(offset >= in_pIO->readBufferSize)
{
/* Put more data in the buffer. */
l_returnCode = UpdateBuffer( in_pIO );
if ( l_returnCode != NSMAIL_OK )
{
return l_returnCode;
}
}
}
}
(*out_ppResponse) = (char*)malloc((offset + 2)*sizeof(char));
if((*out_ppResponse) == NULL)
{
return NSMAIL_ERR_OUTOFMEMORY;
}
memset((*out_ppResponse), 0, (offset + 2)*sizeof(char));
memcpy((*out_ppResponse), in_pIO->readBuffer, offset + 1);
in_pIO->readBufferSize -= (offset + 1);
/* Move the rest of the buffer to the beginning of the buffer. */
memcpy( in_pIO->readBuffer,
(&in_pIO->readBuffer[offset + 1]),
in_pIO->readBufferSize );
memset((&in_pIO->readBuffer[in_pIO->readBufferSize]), 0, in_pIO->readBufferLimit - in_pIO->readBufferSize);
return NSMAIL_OK;
}
int IO_freeDLine( char ** out_ppResponse )
{
if ( out_ppResponse == NULL || (*out_ppResponse) == NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
free( (*out_ppResponse) );
(*out_ppResponse) = NULL;
return NSMAIL_OK;
}
/* Updates the read buffer. */
int UpdateBuffer( IO_t * in_pIO )
{
int l_nByteCount;
int l_nSelectResponse;
/* Determine if there is any data to be read in. */
l_nSelectResponse = IO_checkTimeout( in_pIO );
if ( l_nSelectResponse == 0 )
{
return NSMAIL_ERR_TIMEOUT;
}
/* Determine if there was an error. */
if ( l_nSelectResponse < 0 )
{
return NSMAIL_ERR_IO_SELECT;
}
/* Read in as much data as possible up to the max. size from the socket. */
l_nByteCount = in_pIO->ioFunctions.liof_read(
in_pIO->socket,
in_pIO->readBuffer + in_pIO->readBufferSize,
in_pIO->readBufferLimit - in_pIO->readBufferSize );
if ( l_nByteCount <= 0 )
{
return NSMAIL_ERR_IO_READ;
}
/* Set the new size of the read buffer. */
in_pIO->readBufferSize += l_nByteCount;
return NSMAIL_OK;
}
/* Set the timeout value. */
int IO_setTimeout( IO_t * in_pIO, double in_timeout )
{
if ( in_pIO == NULL )
{
return NSMAIL_ERR_INVALIDPARAM;
}
/* represents infinite blocking, not timeout */
if ( in_timeout == -1 )
{
in_pIO->timeout.tv_sec = (long)in_timeout;
return NSMAIL_OK;
}
if (in_timeout < 0.0) in_timeout = 0.0;
if (in_timeout > 1.0e8) in_timeout = 1.0e8;
in_pIO->timeout.tv_sec = (long) in_timeout;
in_pIO->timeout.tv_usec = (long) (1.0e6 * (in_timeout-(double)(long)in_timeout));
if (in_pIO->timeout.tv_usec >= 1000000)
{
in_pIO->timeout.tv_sec++;
in_pIO->timeout.tv_usec = 0;
}
return NSMAIL_OK;
}
/* Check for a timeout using select() */
int IO_checkTimeout( IO_t * in_pIO )
{
fd_set * l_fdSet;
int l_nSelectResponse;
int l_nSock = in_pIO->socket + 1;
/*
* Create the fd_set structure to be used in select().
*/
l_fdSet = (fd_set *)malloc( sizeof(fd_set) );
FD_ZERO( l_fdSet );
FD_SET( in_pIO->socket, l_fdSet );
/*
* Determine if the timeout value is infinite or not.
*/
if ( in_pIO->timeout.tv_sec == -1 )
{
l_nSelectResponse = in_pIO->ioFunctions.liof_select( l_nSock, l_fdSet, NULL, NULL, NULL );
}
else
{
l_nSelectResponse = in_pIO->ioFunctions.liof_select( l_nSock, l_fdSet, NULL, NULL, &(in_pIO->timeout) );
}
/*
* Free the fd_set structure.
*/
free( l_fdSet );
/*
* Return the result.
*/
return l_nSelectResponse;
}
/* Reset the IO functions. */
void IO_resetFunctions( IO_t * in_pIO )
{
in_pIO->ioFunctions.liof_read = NSSock_Read;
in_pIO->ioFunctions.liof_write = NSSock_Write;
in_pIO->ioFunctions.liof_socket = NSSock_Socket;
in_pIO->ioFunctions.liof_select = NSSock_Select;
in_pIO->ioFunctions.liof_connect = NSSock_Connect;
in_pIO->ioFunctions.liof_close = NSSock_Close;
}
/* Get a structure to the IO functions. */
void IO_getFunctions( IO_t * in_pIO, nsmail_io_fns_t * in_pIOFunctions )
{
in_pIOFunctions->liof_read = in_pIO->ioFunctions.liof_read;
in_pIOFunctions->liof_write = in_pIO->ioFunctions.liof_write;
in_pIOFunctions->liof_socket = in_pIO->ioFunctions.liof_socket;
in_pIOFunctions->liof_select = in_pIO->ioFunctions.liof_select;
in_pIOFunctions->liof_connect = in_pIO->ioFunctions.liof_connect;
in_pIOFunctions->liof_close = in_pIO->ioFunctions.liof_close;
}
/* Set the IO functions. */
void IO_setFunctions( IO_t * in_pIO, nsmail_io_fns_t * in_pIOFunctions )
{
in_pIO->ioFunctions.liof_read = in_pIOFunctions->liof_read;
in_pIO->ioFunctions.liof_write = in_pIOFunctions->liof_write;
in_pIO->ioFunctions.liof_socket = in_pIOFunctions->liof_socket;
in_pIO->ioFunctions.liof_select = in_pIOFunctions->liof_select;
in_pIO->ioFunctions.liof_connect = in_pIOFunctions->liof_connect;
in_pIO->ioFunctions.liof_close = in_pIOFunctions->liof_close;
}