зеркало из https://github.com/mozilla/gecko-dev.git
649 строки
16 KiB
C
649 строки
16 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* The contents of this file are subject to the Mozilla Public
|
|
* License Version 1.1 (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/MPL/
|
|
*
|
|
* 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 security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* terms of the GNU General Public License Version 2 or later (the
|
|
* "GPL"), in which case the provisions of the GPL are applicable
|
|
* instead of those above. If you wish to allow use of your
|
|
* version of this file only under the terms of the GPL and not to
|
|
* allow others to use your version of this file under the MPL,
|
|
* indicate your decision by deleting the provisions above and
|
|
* replace them with the notice and other provisions required by
|
|
* the GPL. If you do not delete the provisions above, a recipient
|
|
* may use your version of this file under either the MPL or the
|
|
* GPL.
|
|
*/
|
|
#if defined(XP_UNIX) || defined(XP_BEOS) || defined(XP_OS2)
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#else
|
|
#ifdef XP_MAC
|
|
#include "macsocket.h"
|
|
#else /* Windows */
|
|
#include <windows.h>
|
|
#include <winsock.h>
|
|
#endif
|
|
#endif
|
|
#include "cmtcmn.h"
|
|
#include "cmtutils.h"
|
|
#include "newproto.h"
|
|
#include <string.h>
|
|
|
|
/* Local defines */
|
|
#if 0
|
|
#define PSM_WAIT_BEFORE_SLEEP (CM_TicksPerSecond() * 60)
|
|
#define PSM_SPINTIME PSM_WAIT_BEFORE_SLEEP
|
|
#define PSM_KEEP_CONNECTION_ALIVE (PSM_WAIT_BEFORE_SLEEP * 900)
|
|
#endif
|
|
|
|
/* If you want to dump the messages sent between the plug-in and the PSM
|
|
* server, then remove the comment for the appropriate define.
|
|
*/
|
|
#if 0
|
|
#define PRINT_SEND_MESSAGES
|
|
#define PRINT_RECEIVE_MESSAGES
|
|
#endif
|
|
|
|
#ifdef PRINT_SEND_MESSAGES
|
|
#ifndef DEBUG_MESSAGES
|
|
#define DEBUG_MESSAGES
|
|
#endif /*DEBUG_MESSAGES*/
|
|
#endif /*PRINT_SEND_MESSAGES*/
|
|
|
|
#ifdef PRINT_RECEIVE_MESSAGES
|
|
#ifndef DEBUG_MESSAGES
|
|
#define DEBUG_MESSAGES
|
|
#endif /*DEBUG_MESSAGES*/
|
|
#endif /*PRINT_RECEIVE_MESSAGES*/
|
|
|
|
#ifdef DEBUG_MESSAGES
|
|
#define LOG(x) do { FILE *f; f=fopen("cmnav.log","a+"); if (f) { \
|
|
fprintf(f, x); fclose(f); } } while(0);
|
|
#define LOG_S(x) do { FILE *f; f=fopen("cmnav.log","a+"); if (f) { \
|
|
fprintf(f, "%s", x); fclose(f); } } while(0);
|
|
#define ASSERT(x) if (!(x)) { LOG("ASSERT:"); LOG(#x); LOG("\n"); exit(-1); }
|
|
#else
|
|
#define LOG(x)
|
|
#define LOG_S(x)
|
|
#define ASSERT(x)
|
|
#endif
|
|
|
|
CMUint32
|
|
cmt_Strlen(char *str)
|
|
{
|
|
CMUint32 len = strlen(str);
|
|
return sizeof(CMInt32) + (((len + 3)/4)*4);
|
|
}
|
|
|
|
CMUint32
|
|
cmt_Bloblen(CMTItem *blob)
|
|
{
|
|
return sizeof(CMInt32) + (((blob->len +3)/4)*4);
|
|
}
|
|
|
|
char *
|
|
cmt_PackString(char *buf, char *str)
|
|
{
|
|
CMUint32 len = strlen(str);
|
|
CMUint32 networkLen = htonl(len);
|
|
CMUint32 padlen = ((len + 3)/4)*4;
|
|
|
|
memcpy(buf, &networkLen, sizeof(CMUint32));
|
|
memcpy(buf + sizeof(CMUint32), str, len);
|
|
memset(buf + sizeof(CMUint32) + len, 0, padlen - len);
|
|
|
|
return buf+sizeof(CMUint32)+padlen;
|
|
}
|
|
|
|
char *
|
|
cmt_PackBlob(char *buf, CMTItem *blob)
|
|
{
|
|
CMUint32 len = blob->len;
|
|
CMUint32 networkLen = htonl(len);
|
|
CMUint32 padlen = (((blob->len + 3)/4)*4);
|
|
|
|
*((CMUint32*)buf) = networkLen;
|
|
memcpy(buf + sizeof(CMUint32), blob->data, len);
|
|
memset(buf + sizeof(CMUint32) + len, 0, padlen - len);
|
|
|
|
return buf + sizeof(CMUint32) + padlen;
|
|
}
|
|
|
|
char *
|
|
cmt_UnpackString(char *buf, char **str)
|
|
{
|
|
char *p = NULL;
|
|
CMUint32 len, padlen;
|
|
|
|
/* Get the string length */
|
|
len = ntohl(*(CMUint32*)buf);
|
|
|
|
/* Get the padded length */
|
|
padlen = ((len + 3)/4)*4;
|
|
|
|
/* Allocate the string and copy the data */
|
|
p = (char *) malloc(len + 1);
|
|
if (!p) {
|
|
goto loser;
|
|
}
|
|
/* Copy the data and NULL terminate */
|
|
memcpy(p, buf+sizeof(CMUint32), len);
|
|
p[len] = 0;
|
|
|
|
*str = p;
|
|
return buf+sizeof(CMUint32)+padlen;
|
|
loser:
|
|
*str = NULL;
|
|
if (p) {
|
|
free(p);
|
|
}
|
|
return buf+sizeof(CMUint32)+padlen;
|
|
}
|
|
|
|
char *
|
|
cmt_UnpackBlob(char *buf, CMTItem **blob)
|
|
{
|
|
CMTItem *p = NULL;
|
|
CMUint32 len, padlen;
|
|
|
|
/* Get the blob length */
|
|
len = ntohl(*(CMUint32*)buf);
|
|
|
|
/* Get the padded length */
|
|
padlen = ((len + 3)/4)*4;
|
|
|
|
/* Allocate the CMTItem for the blob */
|
|
p = (CMTItem*)malloc(sizeof(CMTItem));
|
|
if (!p) {
|
|
goto loser;
|
|
}
|
|
p->len = len;
|
|
p->data = (unsigned char *) malloc(len);
|
|
if (!p->data) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Copy that data across */
|
|
memcpy(p->data, buf+sizeof(CMUint32), len);
|
|
*blob = p;
|
|
|
|
return buf+sizeof(CMUint32)+padlen;
|
|
|
|
loser:
|
|
*blob = NULL;
|
|
CMT_FreeMessage(p);
|
|
|
|
return buf+sizeof(CMUint32)+padlen;
|
|
}
|
|
|
|
#ifdef DEBUG_MESSAGES
|
|
void prettyPrintMessage(CMTItem *msg)
|
|
{
|
|
int numLines = ((msg->len+7)/8);
|
|
char curBuffer[9], *cursor, string[2], hexVal[8];
|
|
char hexArray[25];
|
|
int i, j, numToCopy;
|
|
|
|
/*Try printing out 8 bytes at a time. */
|
|
LOG("\n**********************************************************\n");
|
|
LOG("About to pretty Print Message\n\n");
|
|
curBuffer[9] = '\0';
|
|
hexArray[24] = '\0';
|
|
hexVal[2] = '\0';
|
|
string[1] = '\0';
|
|
LOG("Header Info\n");
|
|
LOG("Message Type: ");
|
|
sprintf(hexArray, "%lx\n", msg->type);
|
|
LOG(hexArray);
|
|
LOG("Message Length: ");
|
|
sprintf (hexArray, "%ld\n\n", msg->len);
|
|
LOG(hexArray);
|
|
LOG("Body of Message\n");
|
|
for (i=0, cursor=msg->data; i<numLines; i++, cursor+=8) {
|
|
/* First copy over the buffer to our local array */
|
|
numToCopy = ((msg->len - (unsigned int)((unsigned long)cursor-(unsigned long)msg->data)) < 8) ?
|
|
msg->len - (unsigned int)((unsigned long)cursor-(unsigned long)msg->data) : 8;
|
|
memcpy(curBuffer, cursor, 8);
|
|
for (j=0;j<numToCopy;j++) {
|
|
string[0] = curBuffer[j];
|
|
if (isprint(curBuffer[j])) {
|
|
string[0] = curBuffer[j];
|
|
} else {
|
|
string[0] = ' ';
|
|
}
|
|
LOG(string);
|
|
}
|
|
string[0] = ' ';
|
|
for (;j<8;j++) {
|
|
LOG(string);
|
|
}
|
|
LOG("\t");
|
|
for (j=0; j<numToCopy; j++) {
|
|
sprintf (hexVal,"%.2x", 0x0ff & (unsigned short)curBuffer[j]);
|
|
LOG(hexVal);
|
|
LOG(" ");
|
|
}
|
|
LOG("\n");
|
|
}
|
|
LOG("Done Pretty Printing Message\n");
|
|
LOG("**********************************************************\n\n");
|
|
}
|
|
#endif
|
|
|
|
CMTStatus CMT_ReadMessageDispatchEvents(PCMT_CONTROL control, CMTItem* message)
|
|
{
|
|
CMTStatus status;
|
|
CMBool done = CM_FALSE;
|
|
CMUint32 msgCategory;
|
|
|
|
/* We have to deal with other types of data on the socket and */
|
|
/* handle them accordingly */
|
|
while (!done) {
|
|
status = CMT_ReceiveMessage(control, message);
|
|
if (status != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
msgCategory = (message->type & SSM_CATEGORY_MASK);
|
|
switch (msgCategory) {
|
|
case SSM_REPLY_OK_MESSAGE:
|
|
done = CM_TRUE;
|
|
break;
|
|
case SSM_REPLY_ERR_MESSAGE:
|
|
done = CM_TRUE;
|
|
break;
|
|
case SSM_EVENT_MESSAGE:
|
|
CMT_DispatchEvent(control, message);
|
|
break;
|
|
/* XXX FIX THIS!!! For the moment I'm ignoring all other types */
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return CMTSuccess;
|
|
loser:
|
|
return CMTFailure;
|
|
}
|
|
|
|
CMTStatus CMT_SendMessage(PCMT_CONTROL control, CMTItem* message)
|
|
{
|
|
CMTStatus status;
|
|
#ifdef PRINT_SEND_MESSAGES
|
|
LOG("About to print message sent to PSM\n");
|
|
prettyPrintMessage(message);
|
|
#endif
|
|
|
|
/* Acquire lock on the control connection */
|
|
CMT_LOCK(control->mutex);
|
|
|
|
/* Try to send pending random data */
|
|
if (message->type != (SSM_REQUEST_MESSAGE | SSM_HELLO_MESSAGE))
|
|
{
|
|
/* If we've already said hello, then flush random data
|
|
just before sending the request. */
|
|
status = CMT_FlushPendingRandomData(control);
|
|
if (status != CMTSuccess)
|
|
goto loser;
|
|
}
|
|
|
|
status = CMT_TransmitMessage(control, message);
|
|
if (status != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (CMT_ReadMessageDispatchEvents(control, message) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
/* Release the control connection lock */
|
|
CMT_UNLOCK(control->mutex);
|
|
return CMTSuccess;
|
|
loser:
|
|
/* Release the control connection lock */
|
|
CMT_UNLOCK(control->mutex);
|
|
return CMTFailure;
|
|
}
|
|
|
|
CMTStatus CMT_TransmitMessage(PCMT_CONTROL control, CMTItem * message)
|
|
{
|
|
CMTMessageHeader header;
|
|
CMUint32 sent, rv;
|
|
|
|
/* Set up the message header */
|
|
header.type = htonl(message->type);
|
|
header.len = htonl(message->len);
|
|
|
|
/* Send the message header */
|
|
sent = CMT_WriteThisMany(control, control->sock,
|
|
(void *)&header, sizeof(CMTMessageHeader));
|
|
if (sent != sizeof(CMTMessageHeader)) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Send the message body */
|
|
sent = CMT_WriteThisMany(control, control->sock, (void *)message->data,
|
|
message->len);
|
|
if (sent != message->len) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Free the buffer */
|
|
free(message->data);
|
|
message->data = NULL;
|
|
return CMTSuccess;
|
|
|
|
loser:
|
|
return CMTFailure;
|
|
}
|
|
|
|
CMTStatus CMT_ReceiveMessage(PCMT_CONTROL control, CMTItem * response)
|
|
{
|
|
CMTMessageHeader header;
|
|
CMUint32 numread, rv;
|
|
|
|
/* Get the message header */
|
|
numread = CMT_ReadThisMany(control, control->sock,
|
|
(void *)&header, sizeof(CMTMessageHeader));
|
|
if (numread != sizeof(CMTMessageHeader)) {
|
|
goto loser;
|
|
}
|
|
|
|
response->type = ntohl(header.type);
|
|
response->len = ntohl(header.len);
|
|
response->data = (unsigned char *) malloc(response->len);
|
|
if (response->data == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
numread = CMT_ReadThisMany(control, control->sock,
|
|
(void *)(response->data), response->len);
|
|
if (numread != response->len) {
|
|
goto loser;
|
|
}
|
|
|
|
#ifdef PRINT_RECEIVE_MESSAGES
|
|
LOG("About to print message received from PSM.\n");
|
|
prettyPrintMessage(response);
|
|
#endif /*PRINT_RECEIVE_MESSAGES*/
|
|
return CMTSuccess;
|
|
loser:
|
|
if (response->data) {
|
|
free(response->data);
|
|
}
|
|
return CMTFailure;
|
|
}
|
|
|
|
CMUint32 CMT_ReadThisMany(PCMT_CONTROL control, CMTSocket sock,
|
|
void * buffer, CMUint32 thisMany)
|
|
{
|
|
CMUint32 total = 0;
|
|
|
|
while (total < thisMany) {
|
|
int got;
|
|
got = control->sockFuncs.recv(sock, (void*)((char*)buffer + total),
|
|
thisMany-total);
|
|
if (got < 0 ) {
|
|
break;
|
|
}
|
|
total += got;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
CMUint32 CMT_WriteThisMany(PCMT_CONTROL control, CMTSocket sock,
|
|
void * buffer, CMUint32 thisMany)
|
|
{
|
|
CMUint32 total = 0;
|
|
|
|
while (total < thisMany) {
|
|
CMInt32 got;
|
|
got = control->sockFuncs.send(sock, (void*)((char*)buffer+total),
|
|
thisMany-total);
|
|
if (got < 0) {
|
|
break;
|
|
}
|
|
total += got;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
CMTItem* CMT_ConstructMessage(CMUint32 type, CMUint32 length)
|
|
{
|
|
CMTItem * p;
|
|
|
|
p = (CMTItem*)malloc(sizeof(CMTItem));
|
|
if (!p) {
|
|
goto loser;
|
|
}
|
|
|
|
p->type = type;
|
|
p->len = length;
|
|
p->data = (unsigned char *) malloc(length);
|
|
if (!p->data) {
|
|
goto loser;
|
|
}
|
|
return p;
|
|
|
|
loser:
|
|
CMT_FreeMessage(p);
|
|
return NULL;
|
|
}
|
|
|
|
void CMT_FreeMessage(CMTItem * p)
|
|
{
|
|
if (p != NULL) {
|
|
if (p->data != NULL) {
|
|
free(p->data);
|
|
}
|
|
free(p);
|
|
}
|
|
}
|
|
|
|
CMTStatus CMT_AddDataConnection(PCMT_CONTROL control, CMTSocket sock,
|
|
CMUint32 connectionID)
|
|
{
|
|
PCMT_DATA ptr;
|
|
|
|
/* This is the first connection */
|
|
if (control->cmtDataConnections == NULL) {
|
|
control->cmtDataConnections = ptr =
|
|
(PCMT_DATA)calloc(sizeof(CMT_DATA), 1);
|
|
if (!ptr) {
|
|
goto loser;
|
|
}
|
|
} else {
|
|
/* Position at the last entry */
|
|
for (ptr = control->cmtDataConnections; (ptr != NULL && ptr->next
|
|
!= NULL); ptr = ptr->next);
|
|
ptr->next = (PCMT_DATA)calloc(sizeof(CMT_DATA), 1);
|
|
if (!ptr->next) {
|
|
goto loser;
|
|
}
|
|
/* Fix up the pointers */
|
|
ptr->next->previous = ptr;
|
|
ptr = ptr->next;
|
|
}
|
|
|
|
/* Fill in the data */
|
|
ptr->sock = sock;
|
|
ptr->connectionID = connectionID;
|
|
|
|
return CMTSuccess;
|
|
loser:
|
|
return CMTFailure;
|
|
}
|
|
|
|
int
|
|
CMT_DestroyDataConnection(PCMT_CONTROL control, CMTSocket sock)
|
|
{
|
|
PCMT_DATA ptr, pptr = NULL;
|
|
int rv=CMTSuccess;
|
|
|
|
if (!control) return rv;
|
|
|
|
control->sockFuncs.close(sock);
|
|
for (ptr = control->cmtDataConnections; ptr != NULL;
|
|
pptr = ptr, ptr = ptr->next) {
|
|
if (ptr->sock == sock) {
|
|
if (pptr == NULL) {
|
|
/* node is at head */
|
|
control->cmtDataConnections = ptr->next;
|
|
if (ptr->priv != NULL)
|
|
ptr->priv->dest(ptr->priv);
|
|
free(ptr);
|
|
return rv;
|
|
}
|
|
/* node is elsewhere */
|
|
pptr->next = ptr->next;
|
|
if (ptr->priv != NULL)
|
|
ptr->priv->dest(ptr->priv);
|
|
free(ptr);
|
|
return rv;
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
CMTStatus CMT_CloseDataConnection(PCMT_CONTROL control, CMUint32 connectionID)
|
|
{
|
|
/* PCMT_DATA ptr, pptr = NULL; */
|
|
CMTSocket sock;
|
|
/* int rv;*/
|
|
|
|
/* Get the socket for this connection */
|
|
if (CMT_GetDataSocket(control, connectionID, &sock) == CMTFailure) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Free data connection associated with this socket */
|
|
if (CMT_DestroyDataConnection(control, sock) == CMTFailure) {
|
|
goto loser;
|
|
}
|
|
|
|
return CMTSuccess;
|
|
loser:
|
|
return CMTFailure;
|
|
}
|
|
|
|
CMTStatus CMT_GetDataConnectionID(PCMT_CONTROL control, CMTSocket sock, CMUint32 * connectionID)
|
|
{
|
|
PCMT_DATA ptr;
|
|
|
|
for (ptr = control->cmtDataConnections; ptr != NULL; ptr = ptr->next) {
|
|
if (ptr->sock == sock) {
|
|
*connectionID = ptr->connectionID;
|
|
return CMTSuccess;
|
|
}
|
|
}
|
|
|
|
return CMTFailure;
|
|
}
|
|
|
|
CMTStatus CMT_GetDataSocket(PCMT_CONTROL control, CMUint32 connectionID, CMTSocket * sock)
|
|
{
|
|
PCMT_DATA ptr;
|
|
|
|
for (ptr = control->cmtDataConnections; ptr != NULL; ptr = ptr->next) {
|
|
if (ptr->connectionID == connectionID) {
|
|
*sock = ptr->sock;
|
|
return CMTSuccess;
|
|
}
|
|
}
|
|
|
|
return CMTFailure;
|
|
}
|
|
|
|
|
|
CMTStatus CMT_SetPrivate(PCMT_CONTROL control, CMUint32 connectionID,
|
|
CMTPrivate *cmtpriv)
|
|
{
|
|
PCMT_DATA ptr;
|
|
|
|
for (ptr = control->cmtDataConnections; ptr != NULL; ptr = ptr->next) {
|
|
if (ptr->connectionID == connectionID) {
|
|
ptr->priv = cmtpriv;
|
|
return CMTSuccess;
|
|
}
|
|
}
|
|
return CMTFailure;
|
|
}
|
|
|
|
CMTPrivate *CMT_GetPrivate(PCMT_CONTROL control, CMUint32 connectionID)
|
|
{
|
|
PCMT_DATA ptr;
|
|
|
|
for (ptr = control->cmtDataConnections; ptr != NULL; ptr = ptr->next) {
|
|
if (ptr->connectionID == connectionID) {
|
|
return ptr->priv;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void CMT_FreeItem(CMTItem *p)
|
|
{
|
|
CMT_FreeMessage(p);
|
|
}
|
|
|
|
CMTItem CMT_CopyPtrToItem(void* p)
|
|
{
|
|
CMTItem value = {0, NULL, 0};
|
|
|
|
if (!p) {
|
|
return value;
|
|
}
|
|
|
|
value.len = sizeof(p);
|
|
value.data = (unsigned char *) malloc(value.len);
|
|
memcpy(value.data, &p, value.len);
|
|
|
|
return value;
|
|
}
|
|
|
|
void * CMT_CopyItemToPtr(CMTItem value)
|
|
{
|
|
void * p = NULL;
|
|
|
|
if (value.len == sizeof(void*)) {
|
|
memcpy(&p, value.data, value.len);
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
CMTStatus CMT_ReferenceControlConnection(PCMT_CONTROL control)
|
|
{ CMT_LOCK(control->mutex);
|
|
control->refCount++;
|
|
CMT_UNLOCK(control->mutex);
|
|
return CMTSuccess;
|
|
}
|
|
|
|
void
|
|
CMT_LockConnection(PCMT_CONTROL control)
|
|
{
|
|
CMT_LOCK(control->mutex);
|
|
}
|
|
|
|
void
|
|
CMT_UnlockConnection(PCMT_CONTROL control)
|
|
{
|
|
CMT_UNLOCK(control->mutex);
|
|
}
|