/** @file fabind.c @date 2008/10/08 @author 오재경 freefrug@falinux.com FALinux.Co.,Ltd. @brief fa-bind 드라이버를 사용하기 위한 API 를 구현한다.. 2009/06/10(오재경) fanet 에 포함하기 위해 수정 @todo @bug @remark @warning */ // // 저작권 에프에이리눅스(주) // 외부공개 금지 // //---------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char desc_fabind[] = "falinux fa-bind ver 0.2.1"; /// fabind 개별 구조체 typedef struct { int port; int group; int need_ack; // 응답요구가 필요한것 ioctl_bind_msg_t ack_info; } fabind_priv_t; /// @{ /// @brief 로컬 함수 리스트 int fabind_post_message_simple( int fd, int port , unsigned char *buf, int count ); /// 일반적인 메세지 전송 int fabind_post_message ( int fd, int port , unsigned char *buf, int count, msg_howto_t howto ); /// 일반적인 메세지 전송 int fabind_group_message ( int fd, int group, unsigned char *buf, int count ); /// 그룹 메세지 전송(방송도 포함) int fabind_recv_message ( int fd, unsigned char *buf, int count, ioctl_bind_msg_t *info ); /// 메세지 수신 int fabind_request_response ( int fd, int port , unsigned char *tx_buf, unsigned char *rx_buf, int tx_cnt, int rx_cnt ); /// 응답 대기형 메세지 전송 int fabind_send_ack ( int fd, int port , unsigned char *buf, int count ); /// ack 메세지 전송 /// @} //------------------------------------------------------------------------------ /** @brief fabind 드라이버 열고 객체를 초기화한다. @param port 나의 포트 @param group 나의 그룹 @param recv_queue_count 내가 받을 큐의 개수 @retrun obj 폴객체 포인터 *///---------------------------------------------------------------------------- poll_obj_t *fabind_open( int port, int group, int recv_queue_count ) { fabind_priv_t *fabind; poll_obj_t *obj; ioctl_set_bind_info_t info; int dev; int rtn, major = 0; char nodfile[256]; major = find_dev_major( FABIND_DEV_NAME ); if ( 0 > major ) { printf( "can not find device %s\n", FABIND_DEV_NAME ); return NULL; } sprintf( nodfile, "/dev/%s", FABIND_DEV_NAME ); dev = dev_open( nodfile, major, 0 ); if ( 0 > dev ) { return NULL; } //printf( "open major=%d\n", major ); info.port = port; info.group = group; info.recv_queue_count = recv_queue_count; rtn = ioctl( dev, IOCTL_SET_BIND_INFO, &info ); if ( rtn < 0 ) { printf( "fbind) unable to open port-%d\n", port ); close(dev); return NULL; } // fabind 만의 정보를 설정한다. fabind = (fabind_priv_t *)malloc( sizeof(fabind_priv_t) ); memset( (void *)fabind, 0, sizeof(fabind_priv_t) ); fabind->port = port; fabind->group = group; fabind->need_ack = 0; // 폴매니져에 등록한다. obj = poll_add( dev ); obj->type = STYP_FABIND; obj->priv = (void *)fabind; return obj; } //------------------------------------------------------------------------------ /** @brief fabind 객체를 해제한다. @param obj 폴객체 포인터 *///---------------------------------------------------------------------------- void fabind_close( poll_obj_t *obj ) { close( obj->fd ); if ( obj->priv ) { free( obj->priv ); } poll_delete( obj ); } //------------------------------------------------------------------------------ /** @brief fabind 폴객체를 포트번호로 찾는다. @param port 포트번호 @return obj 폴객체 포인터 *///---------------------------------------------------------------------------- poll_obj_t *fabind_get_byport( int port ) { poll_obj_t *obj; fabind_priv_t *fabind; int idx, count; count = poll_count(); for(idx=0; idxpriv; if ( fabind ) { if ( port == fabind->port ) { return obj; } } } return NULL; } //------------------------------------------------------------------------------ /** @brief fabind 를 통해 데이타를 전송한다. @param obj 폴객체 포인터 @param port 상대편 포트번호 @param buf 전송버퍼 @param len 버퍼의 길이 @return 전송한 데이타 개수 *///---------------------------------------------------------------------------- int fabind_write( poll_obj_t *obj, int port, char *buf, int len ) { fabind_priv_t *fabind; fabind = (fabind_priv_t *)obj->priv; if ( FABIND_LAST_RECV_PORT == port ) { port = fabind->ack_info.port; } if ( 0 > port ) { printf( "fabind) invalid port=%d\n", port ); return -1; } // 이전 데이타에서 응답이 필요한 데이타가 들어왔다면 if ( fabind->need_ack ) { fabind->need_ack = 0; return fabind_send_ack( obj->fd, port, buf, len ); } else { return fabind_post_message( obj->fd, port , buf, len, SR_TYPE_NORMAL ); } } //------------------------------------------------------------------------------ /** @brief fabind 를 통해 데이타를 전송한다. @param obj 폴객체 포인터 @param port 상대편 포트번호 @param buf 전송버퍼 @param len 버퍼의 길이 @param timeout_sec 전송 대기시간 0보다 작으면 무한대로 대기하여 전송한다 @return 전송한 데이타 개수 *///---------------------------------------------------------------------------- int fabind_write_timeout( poll_obj_t *obj, int port, char *buf, int len, int timeout_sec ) { int rtn; unsigned int end_sec; end_sec = get_cur_sec() + timeout_sec; while(1) { rtn = fabind_post_message( obj->fd, port , buf, len, SR_TYPE_NORMAL ); if ( 0 < rtn ) return rtn; if ( rtn != -EAGAIN ) break; if ( 0 > timeout_sec ) continue; if ( end_sec < get_cur_sec() ) break; } printf( "fbind) unable to send-timeout (port=%d)\n", port ); return -1; } //------------------------------------------------------------------------------ /** @brief fabind 를 통해 데이타를 읽는다. @param obj 폴객체 포인터 @param buf 읽기버퍼 @param len 버퍼의 길이 @param need_ack 현재의 버퍼가 응답이 필요한것인지의 여부를 알려주는 포인터 @return 읽은 데이타 개수 @remark need_ack_port 가 0 이상이면 곧바로 fabind_write() 함수로 응답을 보내주어야 한다. *///---------------------------------------------------------------------------- int fabind_read( poll_obj_t *obj, char *buf, int len, int *need_ack ) { fabind_priv_t *fabind; int rdcnt; fabind = (fabind_priv_t *)obj->priv; *need_ack = 0; // 데이타를 읽는다. rdcnt = fabind_recv_message( obj->fd, buf, len, &fabind->ack_info ); if ( 0 < rdcnt ) { if ( (fabind->ack_info.sr_type&SR_TYPE_REQ_ACK) == SR_TYPE_REQ_ACK ) { *need_ack = 1; } } fabind->need_ack = *need_ack; return rdcnt; } //------------------------------------------------------------------------------ /** @brief fabind 를 통해 데이타를 전송한 후 응답을 받는다. @retrun 받은 데이타 개수 *///---------------------------------------------------------------------------- int fabind_write_and_response( poll_obj_t *obj, int port, char *tx_buf, char *rx_buf, int tx_cnt, int rx_cnt ) { fabind_priv_t *fabind; fabind = (fabind_priv_t *)obj->priv; // 내가 점유한 포트에는 응답요구 전송을 하지 않는다. if ( fabind->port == port ) return 0; return fabind_request_response( obj->fd, port, tx_buf, rx_buf, tx_cnt, rx_cnt ); } //------------------------------------------------------------------------------ /** @brief fabind 를 통해 그룹단위로 데이타를 전송한다. @retrun 받은 데이타 개수 *///---------------------------------------------------------------------------- int fabind_write_group( poll_obj_t *obj, int grp_port, char *buf, int len ) { return fabind_group_message( obj->fd, grp_port, buf, len ); } //------------------------------------------------------------------------------ /** @brief fabind 를 통해 들어온 포트번호를 얻는다. @retrun 받은 데이타 개수 *///---------------------------------------------------------------------------- int fabind_get_recv_port( poll_obj_t *obj ) { fabind_priv_t *fabind; fabind = (fabind_priv_t *)obj->priv; return fabind->ack_info.port; } //____개별 api 함수_____________________________________________________________ //------------------------------------------------------------------------------ /** @brief 단순하게 메세지 보내기 @param fd fa-bind 디바이스 핸들 @param port 상대편 포트번호 @param buf 버퍼 @param count 버퍼의 개수 @retrun 전송된 개수 *///---------------------------------------------------------------------------- int fabind_post_message_simple( int fd, int port, unsigned char *buf, int count ) { ioctl_bind_msg_t msg; int rtn; msg.port = port; msg.group = -1; msg.sr_type = SR_TYPE_NORMAL; msg.count = count; msg.buf = buf; rtn = ioctl( fd, IOCTL_BIND_SEND, &msg ); if ( rtn < 0 ) { printf( "fbind) unable to send (port=%d)\n", port ); return -errno; } return rtn; } //------------------------------------------------------------------------------ /** @brief 메세지 보내기 @param fd fa-bind 디바이스 핸들 @param port 상대편 포트번호 @param buf 버퍼 @param count 버퍼의 개수 @param howto 전송의 방법 SR_TYPE_NORMAL, SR_TYPE_EXPRESS, SR_TYPE_EMERENCY @retrun 전송된 개수 *///---------------------------------------------------------------------------- int fabind_post_message( int fd, int port , unsigned char *buf, int count, msg_howto_t howto ) { ioctl_bind_msg_t msg; int rtn; msg.port = port; msg.group = -1; msg.sr_type = howto; msg.count = count; msg.buf = buf; rtn = ioctl( fd, IOCTL_BIND_SEND, &msg ); if ( rtn < 0 ) { if ( errno != EAGAIN ) printf( "fbind) unable to send (port=%d) rtn=%d\n", port, rtn ); return -errno; } return rtn; } //------------------------------------------------------------------------------ /** @brief 메세지 받아오기 @param fd fa-bind 디바이스 핸들 @param buf 버퍼 @param count 버퍼의 개수 @param info 상대편 정보 구조체 포인터 @retrun 받은 데이타 개수 @remark *///---------------------------------------------------------------------------- int fabind_recv_message( int fd, unsigned char *buf, int count, ioctl_bind_msg_t *info ) { ioctl_bind_msg_t bind_msg, *msg = &bind_msg; int rtn; if (info) msg = info; msg->port = -1; msg->group = -1; msg->count = count; msg->buf = buf; rtn = ioctl( fd, IOCTL_BIND_RECV, msg ); if ( rtn <= 0 ) printf( "fbind) unable to recv\n" ); return rtn; } //------------------------------------------------------------------------------ /** @brief 메세지를 전송한 후 응답을 받는다. @param fd fa-bind 디바이스 핸들 @param port 상대편 포트번호 @param tx_buf 전송 버퍼 @param rx_buf 수신 버퍼 @param tx_cnt 전송버퍼의 개수 @param rx_cnt 수신버퍼의 개수 @retrun 받은 데이타 개수 *///---------------------------------------------------------------------------- int fabind_request_response( int fd, int port , unsigned char *tx_buf, unsigned char *rx_buf, int tx_cnt, int rx_cnt ) { ioctl_bind_msg_t msg; int rtn; msg.port = port; msg.group = -1; msg.sr_type = SR_TYPE_EMERENCY; msg.count = tx_cnt; msg.buf = tx_buf; rtn = ioctl( fd, IOCTL_BIND_SEND_REQ, &msg ); // 송신 (blocking) if ( rtn <= 0 ) { printf( "fbind) unable to send-req port=%d\n", port ); return -1; } msg.port = -1; msg.group = -1; msg.count = rx_cnt; msg.buf = rx_buf; rtn = ioctl( fd, IOCTL_BIND_RECV_ACK, &msg ); // 수신 return rtn; } //------------------------------------------------------------------------------ /** @brief 그룹별 메세지 전송 @param fd fa-bind 디바이스 핸들 @param group 전송할 그룹번호 @param buf 버퍼 @param count 버퍼의 개수 @retrun 전송된 목적지의 개수 *///---------------------------------------------------------------------------- int fabind_group_message( int fd, int group, unsigned char *buf, int count ) { ioctl_bind_msg_t msg; int rtn; msg.port = -1; msg.group = group; msg.sr_type = SR_TYPE_NORMAL; msg.count = count; msg.buf = buf; rtn = ioctl( fd, IOCTL_BIND_SEND_GROUP, &msg ); if ( rtn <= 0 ) printf( "fbind) unable to send-grp grp=%d\n", group ); return rtn; } //------------------------------------------------------------------------------ /** @brief 요구 메세지에 대한 응답 전송 @param fd fa-bind 디바이스 핸들 @param port 응답을 보낼 포트 @param buf 버퍼 @param count 버퍼의 개수 @retrun 전송된 목적지의 개수 *///---------------------------------------------------------------------------- int fabind_send_ack( int fd, int port , unsigned char *buf, int count ) { ioctl_bind_msg_t msg; int rtn; msg.port = port; msg.group = -1; msg.sr_type = -1; msg.count = count; msg.buf = buf; rtn = ioctl( fd, IOCTL_BIND_SEND_ACK, &msg ); if ( rtn <= 0 ) printf( "fbind) unable to send-ack port=%d\n", port ); return rtn; }