Mozilla/mozilla/modules/ipc/src/ipcTransportUnix.cpp
darin%netscape.com 2e50b6f4f7 eliminate primary name from "client hello" (not needed, and added
problematic dependency on libpref).


git-svn-id: svn://10.0.0.236/trunk@133838 18797224-902f-48f8-a5cc-f745e15eee43
2002-11-14 19:37:01 +00:00

413 lines
11 KiB
C++

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 Mozilla IPC.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "prenv.h"
#include "nsIFile.h"
#include "nsIServiceManager.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "ipcSocketProviderUnix.h"
#include "nsISocketTransportService.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "netCore.h"
#include "nsCOMPtr.h"
#include "ipcConfig.h"
#include "ipcLog.h"
#include "ipcTransportUnix.h"
#include "ipcTransport.h"
#include "ipcm.h"
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
//-----------------------------------------------------------------------------
// ipcTransport (XP_UNIX specific methods)
//-----------------------------------------------------------------------------
nsresult
ipcTransport::InitUnix()
{
nsresult rv = GetSocketPath(mSocketPath);
if (NS_FAILED(rv)) return rv;
ipcSocketProviderUnix::SetSocketPath(mSocketPath);
return NS_OK;
}
nsresult
ipcTransport::Shutdown()
{
LOG(("ipcTransport::Shutdown\n"));
mHaveConnection = PR_FALSE;
if (mReadRequest) {
mReadRequest->Cancel(NS_BINDING_ABORTED);
mReadRequest = nsnull;
}
if (mWriteRequest) {
mWriteRequest->Cancel(NS_BINDING_ABORTED);
mWriteRequest = nsnull;
mWriteSuspended = PR_FALSE;
}
mTransport = nsnull;
return NS_OK;
}
nsresult
ipcTransport::SendMsg_Internal(ipcMessage *msg)
{
LOG(("ipcTransport::SendMsg_Internal [dataLen=%u]\n", msg->DataLen()));
mSendQ.EnqueueMsg(msg);
if (!mWriteRequest) {
if (!mTransport)
return NS_ERROR_FAILURE;
nsresult rv = mTransport->AsyncWrite(&mSendQ, nsnull, 0, PRUint32(-1), 0,
getter_AddRefs(mWriteRequest));
if (NS_FAILED(rv)) return rv;
}
if (mWriteSuspended) {
mWriteRequest->Resume();
mWriteSuspended = PR_FALSE;
}
return NS_OK;
}
nsresult
ipcTransport::Connect()
{
nsresult rv;
LOG(("ipcTransport::Connect\n"));
if (++mConnectionAttemptCount > 20) {
LOG((" giving up after 20 unsuccessful connection attempts\n"));
return NS_ERROR_ABORT;
}
rv = CreateTransport();
if (NS_FAILED(rv)) return rv;
rv = mTransport->AsyncRead(&mReceiver, nsnull, 0, PRUint32(-1), 0,
getter_AddRefs(mReadRequest));
return rv;
}
void
ipcTransport::OnStartRequest(nsIRequest *req)
{
nsresult status;
req->GetStatus(&status);
if (NS_SUCCEEDED(status) && !mHaveConnection && !mSentHello) {
//
// send CLIENT_HELLO; expect CLIENT_ID in response.
//
SendMsg_Internal(new ipcmMessageClientHello());
mSentHello = PR_TRUE;
}
}
void
ipcTransport::OnStopRequest(nsIRequest *req, nsresult status)
{
LOG(("ipcTransport::OnStopRequest [status=%x]\n", status));
if (mHaveConnection) {
mHaveConnection = PR_FALSE;
if (mObserver)
mObserver->OnConnectionLost();
}
if (status == NS_BINDING_ABORTED)
return;
if (NS_FAILED(status) && NS_FAILED(OnConnectFailure()))
return;
if (req == mReadRequest)
mReadRequest = nsnull;
else if (req == mWriteRequest) {
mWriteRequest = nsnull;
mWriteSuspended = PR_FALSE;
}
}
nsresult
ipcTransport::CreateTransport()
{
nsresult rv;
nsCOMPtr<nsISocketTransportService> sts(
do_GetService(kSocketTransportServiceCID, &rv));
if (NS_FAILED(rv)) return rv;
rv = sts->CreateTransportOfType(IPC_SOCKET_TYPE,
"127.0.0.1",
IPC_PORT,
nsnull,
1024,
1024*16,
getter_AddRefs(mTransport));
return rv;
}
nsresult
ipcTransport::GetSocketPath(nsACString &socketPath)
{
nsCOMPtr<nsIFile> file;
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file));
if (!file)
return NS_ERROR_FAILURE;
const char *logName = PR_GetEnv("LOGNAME");
if (!(logName && *logName)) {
logName = PR_GetEnv("USER");
if (!(logName && *logName)) {
LOG(("could not determine username from environment\n"));
return NS_ERROR_FAILURE;
}
}
nsCAutoString leaf;
leaf = NS_LITERAL_CSTRING(".mozilla-ipc-")
+ nsDependentCString(logName);
file->AppendNative(leaf);
file->AppendNative(NS_LITERAL_CSTRING("ipcd"));
file->GetNativePath(socketPath);
return NS_OK;
}
//-----------------------------------------------------------------------------
// ipcSendQueue
//-----------------------------------------------------------------------------
NS_IMETHODIMP_(nsrefcnt)
ipcSendQueue::AddRef()
{
return mTransport->AddRef();
}
NS_IMETHODIMP_(nsrefcnt)
ipcSendQueue::Release()
{
return mTransport->Release();
}
NS_IMPL_QUERY_INTERFACE2(ipcSendQueue, nsIStreamProvider, nsIRequestObserver)
NS_IMETHODIMP
ipcSendQueue::OnStartRequest(nsIRequest *request,
nsISupports *context)
{
LOG(("ipcSendQueue::OnStartRequest\n"));
if (mTransport)
mTransport->OnStartRequest(request);
return NS_OK;
}
NS_IMETHODIMP
ipcSendQueue::OnStopRequest(nsIRequest *request,
nsISupports *context,
nsresult status)
{
LOG(("ipcSendQueue::OnStopRequest [status=%x]\n", status));
if (mTransport)
mTransport->OnStopRequest(request, status);
return NS_OK;
}
struct ipcWriteState
{
ipcMessage *msg;
PRBool complete;
};
static NS_METHOD ipcWriteMessage(nsIOutputStream *stream,
void *closure,
char *segment,
PRUint32 offset,
PRUint32 count,
PRUint32 *countWritten)
{
ipcWriteState *state = (ipcWriteState *) closure;
if (state->msg->WriteTo(segment, count,
countWritten, &state->complete) != PR_SUCCESS)
return NS_ERROR_UNEXPECTED;
return NS_OK;
}
NS_IMETHODIMP
ipcSendQueue::OnDataWritable(nsIRequest *request,
nsISupports *context,
nsIOutputStream *stream,
PRUint32 offset,
PRUint32 count)
{
PRUint32 n;
nsresult rv;
ipcWriteState state;
PRBool wroteSomething = PR_FALSE;
LOG(("ipcSendQueue::OnDataWritable\n"));
while (!mQueue.IsEmpty()) {
state.msg = mQueue.First();
state.complete = PR_FALSE;
rv = stream->WriteSegments(ipcWriteMessage, &state, count, &n);
if (NS_FAILED(rv))
break;
if (state.complete) {
LOG((" wrote message %u bytes\n", mQueue.First()->MsgLen()));
mQueue.DeleteFirst();
}
wroteSomething = PR_TRUE;
}
if (wroteSomething)
return NS_OK;
LOG((" suspending write request\n"));
mTransport->SetWriteSuspended(PR_TRUE);
return NS_BASE_STREAM_WOULD_BLOCK;
}
//----------------------------------------------------------------------------
// ipcReceiver
//----------------------------------------------------------------------------
NS_IMETHODIMP_(nsrefcnt)
ipcReceiver::AddRef()
{
return mTransport->AddRef();
}
NS_IMETHODIMP_(nsrefcnt)
ipcReceiver::Release()
{
return mTransport->Release();
}
NS_IMPL_QUERY_INTERFACE2(ipcReceiver, nsIStreamListener, nsIRequestObserver)
NS_IMETHODIMP
ipcReceiver::OnStartRequest(nsIRequest *request,
nsISupports *context)
{
LOG(("ipcReceiver::OnStartRequest\n"));
if (mTransport)
mTransport->OnStartRequest(request);
return NS_OK;
}
NS_IMETHODIMP
ipcReceiver::OnStopRequest(nsIRequest *request,
nsISupports *context,
nsresult status)
{
LOG(("ipcReceiver::OnStopRequest [status=%x]\n", status));
if (mTransport)
mTransport->OnStopRequest(request, status);
return NS_OK;
}
static NS_METHOD ipcReadMessage(nsIInputStream *stream,
void *closure,
const char *segment,
PRUint32 offset,
PRUint32 count,
PRUint32 *countRead)
{
ipcReceiver *receiver = (ipcReceiver *) closure;
return receiver->ReadSegment(segment, count, countRead);
}
NS_IMETHODIMP
ipcReceiver::OnDataAvailable(nsIRequest *request,
nsISupports *context,
nsIInputStream *stream,
PRUint32 offset,
PRUint32 count)
{
LOG(("ipcReceiver::OnDataAvailable [count=%u]\n", count));
PRUint32 countRead;
return stream->ReadSegments(ipcReadMessage, this, count, &countRead);
}
nsresult
ipcReceiver::ReadSegment(const char *ptr, PRUint32 count, PRUint32 *countRead)
{
*countRead = 0;
while (count) {
PRUint32 nread;
PRBool complete;
mMsg.ReadFrom(ptr, count, &nread, &complete);
if (complete) {
mTransport->OnMessageAvailable(&mMsg);
mMsg.Reset();
}
count -= nread;
ptr += nread;
*countRead += nread;
}
return NS_OK;
}