/* -*- 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 mozilla.org code. * * The Initial Developer of the Original Code is Sun Microsystems, Inc. * Portions created by Sun are * Copyright (C) 1999 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): * Serge Pikalev * */ #include #include #include "llTransport.h" #include "private/pprio.h" // ========== llTransport def ========== char * llTransport::ParseParam( char *in_str, char *param_name ) { // move point to "=," string char *value = strstr( in_str, param_name ) + strlen(param_name); if( (value == NULL) || (*value != '=') ) { return NULL; } value++; // move to "," string // extract value char *valueend = strpbrk( value, ",;" ); if( valueend == NULL ) for( valueend = value; *valueend != 0; valueend++ ); int valuesize = valueend - value; char *retvalue = (char*)PR_Malloc( valuesize + 1 ); memcpy( retvalue, value, valuesize ); retvalue[valuesize] = 0; return retvalue; } // ========== llConnection default destructor ========== llConnection::~llConnection() { } // ========== llSocketConnection ========== llSocketConnection::~llSocketConnection() { PR_Close(socket); } PRInt32 llSocketConnection::Read( void *buf, PRInt32 amount ) { return PR_Recv( socket, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT ); } PRInt32 llSocketConnection::Write( void *buf, PRInt32 amount ) { return PR_Send( socket, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT ); } // ========== llTCPTransport ========== static PRStatus fill_addr_by_name( char *hostname, PRUint16 port, PRNetAddr *addr ) { PRStatus status; PRIntn result; PRHostEnt hostentry; char buf[PR_NETDB_BUF_SIZE]; status = PR_GetHostByName( hostname, buf, PR_NETDB_BUF_SIZE, &hostentry ); if( status == PR_FAILURE ) { return PR_FAILURE; } result = PR_EnumerateHostEnt( 0, &hostentry, port, addr ); if( result == 0 ) { return PR_FAILURE; } return PR_SUCCESS; } static PRFileDesc *create_socket( PRUint16 family ) { switch( family ) { case AF_INET: return PR_NewTCPSocket(); case AF_UNIX: return (PRFileDesc *)PR_Socket( AF_UNIX, SOCK_STREAM, 0 ); } return NULL; } PRStatus llTCPTransport::Open( char *name, llSideType type ) { PRStatus status; PRSocketOptionData sopt; this->type = type; char *host = ParseParam( name, "host" ); char *portStr = ParseParam( name, "port" ); PRUint16 port = atoi( portStr ); if( type==llServer ) // prepare to accept { fd = create_socket( AF_INET ); if ( fd == NULL ) { status = PR_FAILURE; } else { sopt.option = PR_SockOpt_Reuseaddr; sopt.value.reuse_addr = PR_TRUE; PR_SetSocketOption( fd, &sopt ); addr.inet.family = AF_INET; addr.inet.port = PR_htons(port); addr.inet.ip = PR_htonl(INADDR_ANY); status = PR_Bind( fd, &addr ); if( status == PR_SUCCESS ) PR_Listen( fd, 5 ); } PR_Free( host ); PR_Free( portStr ); return status; } if( type == llClient ) // prepare to connect { status = fill_addr_by_name( host, port, &addr ); // free allocated mem PR_Free( host ); PR_Free( portStr ); return status; } return PR_FAILURE; } PRStatus llTCPTransport::Close( void ) { if( type == llServer ) return PR_Close( fd ); return PR_SUCCESS; // client is always successful } llConnection * llTCPTransport::ProvideConnection( void ) { PRSocketOptionData sopt; PRFileDesc *socket; if( type == llServer ) { // fd is constant socket = PR_Accept( fd, &addr, PR_INTERVAL_NO_TIMEOUT ); if ( socket == NULL ) { return NULL; } } else if( type == llClient ) { // addr is constant socket = create_socket( addr.raw.family ); if ( socket == NULL ) { return NULL; } PRStatus status = PR_Connect( socket, &addr, PR_INTERVAL_NO_TIMEOUT ); if ( status == PR_FAILURE ) { return NULL; } } // set option to blocking read/write ops sopt.option = PR_SockOpt_Nonblocking; sopt.value.non_blocking = PR_FALSE; PR_SetSocketOption( socket, &sopt ); llSocketConnection *cnt = new llSocketConnection(); cnt->socket = socket; return cnt; } // ========== llPipeTransport ========== PRStatus llPipeTransport::Open( char *name, llSideType type ) { PRStatus status; PRSocketOptionData sopt; this->type = type; const char prefix[] = "/tmp/OSL_PIPE_"; char *path = ParseParam( name, "name" ); addr.local.family = AF_UNIX; strcpy( addr.local.path, prefix ); strcpy( addr.local.path+sizeof(prefix)-1, path ); PR_Free( path ); if( type == llServer ) // prepare to accept { fd = create_socket( AF_UNIX ); if( fd == NULL ) return PR_FAILURE; sopt.option = PR_SockOpt_Reuseaddr; sopt.value.reuse_addr = PR_TRUE; PR_SetSocketOption( fd, &sopt ); status = PR_Bind( fd, &addr ); if ( status == PR_FAILURE ) { return PR_FAILURE; } PR_Listen( fd, 5 ); return PR_SUCCESS; } if ( type == llClient ) { return PR_SUCCESS; } return PR_FAILURE; } PRStatus llPipeTransport::Close( void ) { if( type == llServer ) { PRNetAddr addr; PR_GetSockName( fd, &addr ); PR_Delete( addr.local.path ); return PR_Close( fd ); } return PR_SUCCESS; // client is always successful }