uds.c 7.96 KB
/**    
    @file     uds.c
    @date     2009-03-19
    @author   오재경 freefrug@falinux.com
    @brief    uds 를 사용한 통신을 담당한다.

    @modify   2009-12-11 (오재경)
                  uds_open_client() 함수에 대한 편의성을 가미했다.
                  uds_open_client() 함수 호출시 인자의 파일이름은 uds_write() 함수에서
                  목적지가 NULL 일 경우 목적지로 대치된다.
    @todo    
    @bug     
    @remark   
    
    @warning 
*/
//
//  저작권    에프에이리눅스(주)
//            외부공개 금지
//
//----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/un.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <pollmng.h>
#include <uds.h>


char desc_uds[] = "falinux uds ver 0.2.0";

/// uds 개별 구조체
typedef struct {
	
	char  port[256];
	int   im_server;
	
} uds_priv_t;

static poll_obj_t  *tmp_uds_poll = NULL;  // poll 관리객체없이 전송함수를 위해


//------------------------------------------------------------------------------
/** @brief    uds 소켓을 서버형태로 open 한다.
    @param    fname  문자열 파일이름
    @return   poll_obj_t 형태의 포인터
*///----------------------------------------------------------------------------
poll_obj_t  *uds_open_server( char *fname )
{
	struct sockaddr_un addr_svr;
	poll_obj_t *obj;
	uds_priv_t *uds;
	int  option;
	int  sockfd;
	
	sockfd = socket( AF_UNIX, SOCK_DGRAM, 0 );
	if ( sockfd < 0 )
	{
		perror( "uds open error:" );
		return NULL;	
	}

	// 이미 소켓용 화일에 링크되어 있다면 제거한다.
	unlink ( fname );

	// TIME-WAIT 상태에 있는 소켓에 할당되어 있는 IP 주소와 포트를 바로 사용할 수 있도록
	// SO_REUSEADDR 의 옵션 값을 TRUE 로
	option = 1;                                                         
	setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
	
	// 소켓을 시스템에 연결한다.
	bzero( &addr_svr, sizeof(struct sockaddr_un) );
	addr_svr.sun_family = AF_UNIX;
	strcpy( addr_svr.sun_path, fname );
	
	if( bind( sockfd, (struct sockaddr *)&addr_svr, sizeof(struct sockaddr_un) ) < 0 )
	{
		perror("uds bind error :"); 
	    close( sockfd );
	    return NULL;
	}

	// uds 만의 정보를 설정한다.
	uds = (uds_priv_t *)malloc( sizeof(uds_priv_t) );
	uds->im_server = 1;
	strcpy( uds->port, fname );

	obj = poll_add( sockfd );
	obj->type = STYP_UDS;
	obj->priv = (void *)uds;
	
	tmp_uds_poll = obj;
	
	return obj;
}
//------------------------------------------------------------------------------
/** @brief    uds 소켓을 클라이언트 형태로 open 한다.
    @param    fname  문자열 파일이름, 확장을 위해 존재하며 NULL 을 사용하여도 된다.
    @return   poll_obj_t 형태의 포인터
*///----------------------------------------------------------------------------
poll_obj_t  *uds_open_client( char *fname )
{
	poll_obj_t *obj;
	uds_priv_t *uds;
	int sockfd;
	
	sockfd = socket( AF_UNIX, SOCK_DGRAM, 0 );
	if ( sockfd < 0 )
	{
		perror( "uds open error:" );
		return NULL;	
	}

	// uds 만의 정보를 설정한다.
	uds = (uds_priv_t *)malloc( sizeof(uds_priv_t) );
	uds->im_server = 0;
	if (fname)
	{
		strcpy( uds->port, fname );
	}

	obj = poll_add( sockfd );
	obj->type = STYP_UDS;
	obj->priv = (void *)uds;
	
	tmp_uds_poll = obj;
	
	return obj;
}
//------------------------------------------------------------------------------
/** @brief    uds 소켓을 close 한다.
    @param    obj  폴객체 포인터
*///----------------------------------------------------------------------------
void uds_close( poll_obj_t *obj )
{
	close( obj->fd );
	
	if ( obj->priv )
	{
		free( obj->priv );
	}
	
	poll_delete( obj );
	
	if ( tmp_uds_poll == obj ) tmp_uds_poll = NULL;
}
//------------------------------------------------------------------------------
/** @brief    uds 폴객체를 파일이름으로 찾는다.
    @param    fname 문자열 파일이름
    @return   obj  폴객체 포인터
*///----------------------------------------------------------------------------
poll_obj_t  *uds_get_byport( char *fname )
{
	poll_obj_t *obj;
	uds_priv_t *uds;
	int  idx, count;
	
	count = poll_count();
	
	for(idx=0; idx<count; idx++)
	{
		obj = poll_get_obj( idx );
		uds = (uds_priv_t *)obj->priv;  
		if ( uds )
		{
			if ( 0 == strcmp( uds->port, fname ) )
			{
				return obj;
			}
		}
	}
	
	return NULL;
}
//------------------------------------------------------------------------------
/** @brief    uds 소켓을 통해 데이타를 전송한다.
    @param    obj  폴객체 포인터
    @param    to   상대방 파일이름 문자열포인터
    @param    buf  전송버퍼
    @param    len  버퍼의 길이
    @return   전송한 데이타 개수
*///----------------------------------------------------------------------------
int  uds_write( poll_obj_t *obj, char *to, char *buf, int len )
{
	uds_priv_t *uds;
	struct sockaddr_un uds_addr;
	char *dst;
	int   wrcnt;
	
	uds = (uds_priv_t *)obj->priv; 
	
	// 클라이언트로 열려있거나 목적지가 존재하지 않으면 저장된 포트로 전송한다.
	dst = to;
	if ( ( 0 == uds->im_server ) && ( NULL == dst ) )
	{
		dst = uds->port;
	}

	// 상대편 주소를 설정한다.
	bzero( &uds_addr, sizeof(struct sockaddr_un) );	
	uds_addr.sun_family = AF_UNIX;
	strcpy( uds_addr.sun_path, dst );

	// 전송한다.
	wrcnt = sendto( obj->fd, buf, len, 0, (struct sockaddr *)&uds_addr, sizeof(uds_addr) );

	if ( 0 > wrcnt )
	{
		char msg[256];
		
		sprintf( msg, "uds send error(to %s)", dst );
		perror( msg );	
	}
	
	return wrcnt;
}
//------------------------------------------------------------------------------
/** @brief    uds 소켓을 통해 데이타를 읽는다.
    @param    obj  폴객체 포인터
    @param    buf  전송버퍼
    @param    len  버퍼의 길이
    @return   전송된 데이타 개수
*///----------------------------------------------------------------------------
int  uds_read( poll_obj_t *obj, char *buf, int len )
{
	struct sockaddr_un uds_addr;
	int  addr_len;
	int  rdcnt;
	
	// 데이타를 읽는다.
	addr_len = sizeof(uds_addr);
	rdcnt = recvfrom( obj->fd, buf, len, 0, (struct sockaddr *)&uds_addr, (socklen_t *)&addr_len );
	
	if ( 0 > rdcnt )
	{
		perror( "uds recv error:" );
	}
	//else
	//{
	//	if ( from )	strcpy( from, uds_addr.sun_path );
	//}
	
	return rdcnt;
}

//------------------------------------------------------------------------------
/** @brief    poll 객체없이 uds 소켓을 통해 데이타를 전송한다.
    @param    to   상대방 파일이름 문자열포인터
    @param    buf  전송버퍼
    @param    len  버퍼의 길이
    @return   전송한 데이타 개수
    @remark   uds_open_server(), uds_open_client() 함수는 한번 호출되어야 한다.
*///----------------------------------------------------------------------------
int  uds_write_simple( char *to, char *buf, int len )
{
	if ( tmp_uds_poll )
	{
		return uds_write( tmp_uds_poll, to, buf, len );
	}

	return -1;
}
//------------------------------------------------------------------------------
/** @brief    poll 객체없이 uds 소켓을 통해 데이타를 읽는다.
    @param    buf  전송버퍼
    @param    len  버퍼의 길이
    @return   전송된 데이타 개수
    @remark   uds_open_server(), uds_open_client() 함수는 한번 호출되어야 한다.
*///----------------------------------------------------------------------------
int  uds_read_simple( char *buf, int len )
{
	if ( tmp_uds_poll )
	{
		return uds_read( tmp_uds_poll, buf, len );
	}

	return -1;
}