/* * tipc_stream_stream.c * * Created on: 2015. 9. 3. * Author: jwjw */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /// tcp 소켓의 형태를 구분한다. #define SOCK_TYPE_CLIENT 0 #define SOCK_TYPE_SERVER 1 #define SOCK_TYPE_SERVER_CLIENT 2 /// tcp 개별 구조체 typedef struct { int type; int inst; // 서버용 정보 tlist *client_list; int client_max; int sock_type; poll_obj_t *obj_server; // 서버에서 분리된 클라이언트를 위해 } tipc_stream_priv_t; poll_obj_t *tipc_stream_open_server( int type, int inst, int client_max) { struct sockaddr_tipc server_addr; server_addr.family = AF_TIPC; server_addr.addrtype = TIPC_ADDR_NAMESEQ; server_addr.addr.nameseq.type = type; server_addr.addr.nameseq.lower = inst; server_addr.addr.nameseq.upper = inst; server_addr.scope = TIPC_ZONE_SCOPE; int sockfd = socket (AF_TIPC, SOCK_STREAM, 0); if ( sockfd < 0 ){ perror( "tipc server open error:" ); return NULL; } if (0 != bind( sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))) { perror("tipc bind error :"); close( sockfd ); return NULL; } if (0 != listen( sockfd, 0)) { perror("tipc listen error :"); close( sockfd ); return NULL; } // tcp 만의 정보를 설정한다. tipc_stream_priv_t *tipc = (tipc_stream_priv_t *)malloc( sizeof(tipc_stream_priv_t) ); tipc->sock_type = SOCK_TYPE_SERVER; tipc->type = type; tipc->inst = inst; tipc->client_max = client_max; tipc->client_list = tlist_create(); // 폴관리객체에 등록한다. poll_obj_t *obj = poll_add( sockfd ); obj->type = STYP_TIPC; obj->priv = (void *)tipc; poll_rebuild(); return obj; } poll_obj_t *tipc_stream_open_client( int type, int inst ) { struct sockaddr_tipc server_addr; server_addr.family = AF_TIPC; server_addr.addrtype = TIPC_ADDR_NAME; server_addr.addr.name.name.type = type; server_addr.addr.name.name.instance = inst; server_addr.addr.name.domain = 0; int sockfd = socket (AF_TIPC, SOCK_STREAM, 0); if ( sockfd < 0 ){ perror( "tipc open error:" ); return NULL; } if ( 0 != connect( sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) ) { perror( "tipc connect error :" ); close( sockfd ); return NULL; } poll_obj_t *obj; tipc_stream_priv_t *tipc = (tipc_stream_priv_t *)malloc( sizeof(tipc_stream_priv_t) ); tipc->sock_type = SOCK_TYPE_CLIENT; tipc->type = type; tipc->inst = inst; // 폴관리객체에 등록한다. obj = poll_add( sockfd ); obj->type = STYP_TIPC; obj->priv = (void *)tipc; return obj; } //------------------------------------------------------------------------------ /** @brief tcp 소켓을 close 한다. @param obj 폴객체 포인터 *///---------------------------------------------------------------------------- void tipc_stream_close( poll_obj_t *obj ) { tipc_stream_priv_t *tipc, *server_tipc; if ( obj->on_disconnect ){ // 소켓 끊어짐을 사용자에게 알린다. obj->on_disconnect( obj ); } tipc = (tipc_stream_priv_t *)obj->priv; switch( tipc->sock_type ) { case SOCK_TYPE_SERVER_CLIENT : // 서버가 관리하는 클라이언트를 리스트에서 삭제 server_tipc = (tipc_stream_priv_t *)(tipc->obj_server->priv); if ( server_tipc ){ tlist_remove( server_tipc->client_list, obj ); } break; case SOCK_TYPE_SERVER : tlist_free( tipc->client_list ); // 서버가 관리하는 클라이언트의 server_tipc 를 모두 NULL 로 만든다. break; } shutdown( obj->fd, SHUT_RDWR); close( obj->fd ); if ( obj->priv ){ free( obj->priv ); } poll_delete( obj ); } static poll_obj_t *tipc_stream_connect_client( poll_obj_t *obj_server, int sockfd) { // 클라이언트 접속의 개수를 파악한다. tipc_stream_priv_t *server_tipc = (tipc_stream_priv_t *)obj_server->priv; if ( tlist_getcount(server_tipc->client_list) >= server_tipc->client_max ){ shutdown(sockfd, SHUT_RDWR); close( sockfd ); printf( "tipc connect error : client is full (%d)\n", server_tipc->client_max ); return NULL; } // tipc 만의 정보를 설정한다. tipc_stream_priv_t *tipc = (tipc_stream_priv_t *)malloc( sizeof(tipc_stream_priv_t) ); tipc->sock_type = SOCK_TYPE_SERVER_CLIENT; tipc->obj_server = obj_server; // 클라이언트 소켓을 할당한 서버정보 // 폴관리객체에 등록한다. poll_obj_t *obj = poll_add( sockfd ); if ( obj ){ // 서버에 접속된 클라이언트를 리스트에 등록 tlist_add( server_tipc->client_list, obj ); obj->type = STYP_TIPC; obj->priv = (void *)tipc; return obj; } else { shutdown(sockfd, SHUT_RDWR); close( sockfd ); free( tipc ); return NULL; } } poll_obj_t *tipc_stream_accept_client( poll_obj_t *obj_server ) { int peer_sd = accept( obj_server->fd, 0, 0); if (peer_sd < 0 ) { printf ("Server: accept failed\n"); exit(1); } return tipc_stream_connect_client( obj_server, peer_sd); } //------------------------------------------------------------------------------ /** @brief tipc 소켓을 통해 데이타를 전송한다. @param obj 폴객체 포인터 @param buf 전송버퍼 @param len 버퍼의 길이 @return 전송한 데이타 개수 @remark 에러에 대한 처리를 해야한다. tipc_stream_close( obj ) 를 호출하여 접속을 끊는 방법이 일반적이다. BF_POLICY_AUTO_CLOSE 옵션이 있을경우 자동으로 소켓을 닫는다. *///---------------------------------------------------------------------------- int tipc_stream_write( poll_obj_t *obj, char *buf, int len ) { int wrcnt = write( obj->fd, buf, len ); if ( 0 > wrcnt ){ perror( "[sys]tipc send error:" ); tipc_stream_close( obj ); } return wrcnt; } //------------------------------------------------------------------------------ /** @brief tipc 소켓을 통해 데이타를 읽는다. @param obj 폴객체 포인터 @param len 버퍼의 길이 @return 전송된 데이타 개수 @remark 에러에 대한 처리를 해야한다. tipc_stream_close( obj ) 를 호출하여 접속을 끊는 방법이 일반적이다. BF_POLICY_AUTO_CLOSE 옵션이 있을경우 자동으로 소켓을 닫는다. *///---------------------------------------------------------------------------- int tipc_stream_read( poll_obj_t *obj, char *buf, int len ) { int rdcnt = read( obj->fd, buf, len ); if ( 0 > rdcnt ) { perror( "tipc recv error:" ); tipc_stream_close( obj ); } else if ( 0 == rdcnt ){ if ( 0 > errno ){ perror( "tipc recv error:" ); tipc_stream_close( obj ); } else { tipc_stream_close( obj ); } } return rdcnt; }