/** @file udp.c @date 2009-03-19 @author 오재경 freefrug@falinux.com @brief udp 를 사용한 통신을 담당한다. @modify 2010-08-18 (장길석) mingw와 함께 사용할 수 있는 코드 추가 @todo @bug @remark @warning */ // // 저작권 에프에이리눅스(주) // 외부공개 금지 // //---------------------------------------------------------------------------- #define EMBEDDED_LINUX // 이렇게 처리하지 않으면 EClipse에서 C 영역이 회색 바탕이 됨 #ifdef MS_WIN32 #undef EMBEDDED_LINUX #endif #include #include #include #include #include #include #include #ifdef EMBEDDED_LINUX #include #include #include #include #else #include #include #endif #include #include char desc_udp[] = "falinux udp ver 0.2.0"; /// udp 개별 구조체 typedef struct { int port; int im_server; struct sockaddr_in addr; } udp_priv_t; static poll_obj_t *tmp_udp_poll = NULL; // poll 관리객체없이 전송함수를 위해 //------------------------------------------------------------------------------ /** @brief udp 소켓을 서버형태로 open 한다. @param port 포트번호 @return poll_obj_t 형태의 포인터 *///---------------------------------------------------------------------------- #ifdef EMBEDDED_LINUX poll_obj_t *udp_open_server( int port ) { struct sockaddr_in addr_svr; poll_obj_t *obj; udp_priv_t *udp; int option; int sockfd; sockfd = socket( PF_INET, SOCK_DGRAM, 0 ); if ( sockfd < 0 ) { perror( "udp open error:" ); return NULL; } // TIME-WAIT 상태에 있는 소켓에 할당되어 있는 IP 주소와 포트를 바로 사용할 수 있도록 // SO_REUSEADDR 의 옵션 값을 TRUE 로 option = 1; setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); // 소켓을 시스템에 연결한다. bzero( &addr_svr, sizeof(struct sockaddr_in) ); addr_svr.sin_family = AF_INET; addr_svr.sin_addr.s_addr = htonl( INADDR_ANY ); addr_svr.sin_port = htons( port ); if( bind( sockfd, (struct sockaddr *)&addr_svr, sizeof(struct sockaddr_in) ) < 0 ) { perror("udp bind error :"); close( sockfd ); return NULL; } // udp 만의 정보를 설정한다. udp = (udp_priv_t *)malloc( sizeof(udp_priv_t) ); udp->im_server = 1; udp->port = port; obj = poll_add( sockfd ); obj->type = STYP_UDP; obj->priv = (void *)udp; tmp_udp_poll = obj; return obj; } #else poll_obj_t *udp_open_server( int port ) { SOCKET hSock; SOCKADDR_IN sckAddr; poll_obj_t *obj; udp_priv_t *udp; char option; hSock = socket( PF_INET, SOCK_DGRAM, 0 ); if ( INVALID_SOCKET == hSock){ perror( "udp open error:"); return NULL; } // TIME-WAIT 상태에 있는 소켓에 할당되어 있는 IP 주소와 포트를 바로 사용할 수 있도록 // SO_REUSEADDR 의 옵션 값을 TRUE 로 option = 1; setsockopt( hSock, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); // 소켓을 시스템에 연결한다. memset( &sckAddr, 0, sizeof( sckAddr)); sckAddr.sin_family = AF_INET; sckAddr.sin_addr.s_addr = htonl( INADDR_ANY ); sckAddr.sin_port = htons( port ); if( SOCKET_ERROR == bind( hSock, ( SOCKADDR *)&sckAddr, sizeof( sckAddr) )) { perror("udp bind error"); closesocket( hSock ); return NULL; } // udp 만의 정보를 설정한다. udp = (udp_priv_t *)malloc( sizeof(udp_priv_t) ); udp->im_server = 1; udp->port = port; fd_t pSock = malloc( sizeof( SOCKET)); *( SOCKET*)pSock = hSock; obj = poll_add( pSock); obj->type = STYP_UDP; obj->priv = (void *)udp; tmp_udp_poll = obj; return obj; } #endif //------------------------------------------------------------------------------ /** @brief udp 소켓을 클라이언트 형태로 open 한다. @return poll_obj_t 형태의 포인터 *///---------------------------------------------------------------------------- #ifdef EMBEDDED_LINUX poll_obj_t *udp_open_client( void ) { poll_obj_t *obj; udp_priv_t *udp; int sockfd; sockfd = socket( PF_INET, SOCK_DGRAM, 0 ); if ( sockfd < 0 ) { perror( "udp open error:" ); return NULL; } // udp 만의 정보를 설정한다. udp = (udp_priv_t *)malloc( sizeof(udp_priv_t) ); udp->im_server = 0; udp->port = -1; obj = poll_add( sockfd ); obj->type = STYP_UDP; obj->priv = (void *)udp; tmp_udp_poll = obj; return obj; } #else poll_obj_t *udp_open_client( void ) { SOCKET hSock; poll_obj_t *obj; udp_priv_t *udp; hSock = socket( PF_INET, SOCK_DGRAM, 0 ); if ( INVALID_SOCKET == hSock){ perror( "udp open error:"); return NULL; } // udp 만의 정보를 설정한다. udp = (udp_priv_t *)malloc( sizeof(udp_priv_t) ); udp->im_server = FALSE; udp->port = -1; fd_t pSock = malloc( sizeof( SOCKET)); *( SOCKET*)pSock = hSock; obj = poll_add( pSock); obj->type = STYP_UDP; obj->priv = (void *)udp; tmp_udp_poll = obj; return obj; } #endif //------------------------------------------------------------------------------ /** @brief udp 소켓을 close 한다. @param obj 폴객체 포인터 *///---------------------------------------------------------------------------- void udp_close( poll_obj_t *obj ) { #ifdef EMBEDDED_LINUX close( obj->fd ); #else closesocket( *( ( SOCKET *)obj->fd)); free( obj->fd); // SOCKET * 를 해제한다. #endif if ( obj->priv ) { free( obj->priv ); } poll_delete( obj ); if ( tmp_udp_poll == obj ) tmp_udp_poll = NULL; } //------------------------------------------------------------------------------ /** @brief udp 폴객체를 포트번호로 찾는다. @param port 포트번호 @return obj 폴객체 포인터 *///---------------------------------------------------------------------------- poll_obj_t *udp_get_byport( int port ) { poll_obj_t *obj; udp_priv_t *udp; int idx, count; count = poll_count(); for(idx=0; idxpriv; if ( udp ) { if ( udp->port == port ) { return obj; } } } return NULL; } //------------------------------------------------------------------------------ /** @brief 자료를 송신한 클라이언트로 데에터를 재 전송한다 @param obj 폴객체 포인터 @param len 버퍼의 길이 @return 전송된 데이타 개수 *///---------------------------------------------------------------------------- int udp_echo( poll_obj_t *obj, char *buf, int len ) { struct sockaddr_in *paddr; udp_priv_t *udp; int wrcnt; udp = (udp_priv_t *)(obj->priv); paddr = &(udp->addr); #ifdef EMBEDDED_LINUX wrcnt = sendto( obj->fd, buf, len, 0, (struct sockaddr *)paddr, sizeof( struct sockaddr_in) ); #else SOCKET hSock = *( SOCKET *)obj->fd; wrcnt = sendto( hSock, buf, len, 0, (struct sockaddr *)paddr, sizeof( struct sockaddr_in) ); #endif if ( 0 > wrcnt ) { perror( "udp send error:" ); } return wrcnt; } //------------------------------------------------------------------------------ /** @brief udp 소켓을 통해 데이타를 전송한다. @param obj 폴객체 포인터 @param host 상대방 IP 나 호스트이름 문자열포인터 @param port 상대방 포트번호 @param buf 전송버퍼 @param len 버퍼의 길이 @return 전송한 데이타 개수 *///---------------------------------------------------------------------------- int udp_write( poll_obj_t *obj, char *host, int port, char *buf, int len ) { struct sockaddr_in udp_addr; int wrcnt; // 상대편 주소를 설정한다. memset( &udp_addr, 0, sizeof( struct sockaddr_in) ); udp_addr.sin_family = AF_INET; udp_addr.sin_addr.s_addr = inet_addr( host ); udp_addr.sin_port = htons( port ); // 전송한다. #ifdef EMBEDDED_LINUX wrcnt = sendto( obj->fd, buf, len, 0, (struct sockaddr *)&udp_addr, sizeof(udp_addr) ); #else SOCKET hSock = *( SOCKET *)obj->fd; wrcnt = sendto( hSock, buf, len, 0, (struct sockaddr *)&udp_addr, sizeof(udp_addr) ); #endif if ( 0 > wrcnt ) { perror( "udp send error:" ); } return wrcnt; } //------------------------------------------------------------------------------ /** @brief udp 소켓을 통해 데이타를 읽는다. @param obj 폴객체 포인터 @param len 버퍼의 길이 @return 전송된 데이타 개수 *///---------------------------------------------------------------------------- int udp_read( poll_obj_t *obj, char *buf, int len ) { struct sockaddr_in *paddr; udp_priv_t *udp; int addr_len; int rdcnt; udp = (udp_priv_t *)(obj->priv); paddr = &(udp->addr); // 데이타를 읽는다. addr_len = sizeof( struct sockaddr_in); #ifdef EMBEDDED_LINUX rdcnt = recvfrom( obj->fd, buf, len, 0, (struct sockaddr *)paddr, (socklen_t *)&addr_len ); #else SOCKET hSock = *( SOCKET *)obj->fd; rdcnt = recvfrom( hSock, buf, len, 0, ( SOCKADDR *)paddr, &addr_len); #endif if ( 0 > rdcnt ) { perror( "udp recv error:" ); } //printf( "host=%s port=%d\n", inet_ntoa( udp->addr.sin_addr ), udp->addr.sin_port ); return rdcnt; } //------------------------------------------------------------------------------ /** @brief udp 소켓으로 마지막으로 수신한 호스트를 찾는다. @param obj 폴객체 포인터 @param host 상대편 호스트를 돌려줄 문자열 포인터 @param port 상대편 호스트가 사용한 포트번호를 돌려줄 정수형 포인터 @return 의미없음 *///---------------------------------------------------------------------------- int udp_get_remote_host( poll_obj_t *obj, char *host, int *port ) { udp_priv_t *udp; udp = (udp_priv_t *)(obj->priv); strcpy( host, inet_ntoa( udp->addr.sin_addr ) ); *port = udp->addr.sin_port; return 0; } //------------------------------------------------------------------------------ /** @brief poll 객체없이 udp 소켓을 통해 데이타를 전송한다. @param host 상대방 IP 나 호스트이름 문자열포인터 @param port 상대방 포트번호 @param buf 전송버퍼 @param len 버퍼의 길이 @return 전송한 데이타 개수 @remark udp_open_server(), udp_open_client() 함수는 한번 호출되어야 한다. *///---------------------------------------------------------------------------- int udp_write_simple( char *host, int port, char *buf, int len ) { if ( tmp_udp_poll ) { return udp_write( tmp_udp_poll, host, port, buf, len ); } return -1; } //------------------------------------------------------------------------------ /** @brief poll 객체없이 udp 소켓을 통해 데이타를 읽는다. @param buf 전송버퍼 @param len 버퍼의 길이 @return 전송된 데이타 개수 @remark udp_open_server(), udp_open_client() 함수는 한번 호출되어야 한다. *///---------------------------------------------------------------------------- int udp_read_simple( char *buf, int len ) { if ( tmp_udp_poll ) { return udp_read( tmp_udp_poll, buf, len ); } return -1; }