Index: trunk/src/cf_socket.c
===================================================================
--- trunk/src/cf_socket.c	(revision 142)
+++ trunk/src/cf_socket.c	(revision 151)
@@ -9,4 +9,5 @@
 #include "cf_local.h"
 #include "cf_error.h"
+#include "cf_util.h"
 
 #include <stdio.h>
@@ -33,6 +34,18 @@
 #endif
 
+#define ASSERT_CTX(__ctx)	\
+	if (__ctx == NULL)		\
+		return CF_ERROR_SOCKET_INVALID_CTX
+
+#define ASSERT_ARGS(x)	\
+	if ((x))			\
+		return CF_ERROR_SOCKET_INVALID_ARGS
+
 #define ASSERT_INIT()					\
 	if (!CF_Socket_IsInitialized ())	\
+		return CF_ERROR_SOCKET_NOT_INITIALIZED 
+
+#define TRY_INIT()					\
+	if (CF_Socket_Initialize ())	\
 		return CF_ERROR_SOCKET_NOT_INITIALIZED 
 
@@ -45,10 +58,18 @@
 # define sa_family_t		unsigned short
 # define close(__sock)		closesocket(__sock)
-# define GET_SYSTEM_ERROR()	WSAGetLastError ()
 # define ERROR_INTR			WSAEINTR
 #else
-# define GET_SYSTEM_ERROR()	errno
 # define ERROR_INTR			EINTR
 #endif
+
+#define MAX_IP_LENGTH	256
+
+typedef struct __cf_socket_ctx__
+{
+	int				sock;
+	int				timeout;
+	char			ip[MAX_IP_LENGTH];
+	unsigned short	port;
+} CF_SOCKET_CONTEXT;
 
 static CF_BOOL gInitialized = CF_FALSE;
@@ -64,8 +85,6 @@
 	int flags = fcntl (sock, F_GETFL, 0);
 
-	if (boolean)
-		flags |=  O_NONBLOCK;
-	else
-		flags &= ~O_NONBLOCK;
+	if (boolean)	flags |=  O_NONBLOCK;
+	else			flags &= ~O_NONBLOCK;
 
 	fcntl (sock, F_SETFL, flags);
@@ -74,148 +93,8 @@
 
 static int
-CF_Socket_Local_SetLinger (const int sock)
-{
-	struct linger linger;
-
-	linger.l_onoff = 1;
-	linger.l_linger = 0;
-
-	return CF_Socket_SetOption (sock,
-								SO_LINGER,
-								&linger,
-								sizeof (linger));
-}
-
-static int
-CF_Socket_Local_SetReUseAddr (const int sock)
-{
-	int reuseaddr = 1;
-
-	return CF_Socket_SetOption (sock,
-								SO_REUSEADDR,
-								&reuseaddr,
-								sizeof (reuseaddr));
-}
-
-static int
-CF_Socket_Local_CheckTimeout (const int	sock,
-							  const int	timeout)
-{
-	int				result = 0;
-	fd_set			readfds;
-	struct timeval	tv;
-	int				error;
-
-	if (!(timeout > CF_SOCKET_NO_TIMEOUT))
-		return CF_OK;
-
-	tv.tv_sec = timeout;
-	tv.tv_usec = 0;
-
-	FD_ZERO (&readfds);
-	FD_SET (sock, &readfds);
-
-	while ((result = select (sock + 1, &readfds, NULL, NULL, &tv)) < 0)
-	{
-		error = GET_SYSTEM_ERROR ();
-		if (error != ERROR_INTR)
-		{
-			result = CF_ERROR_SOCKET_TIMEOUT;
-			return result;
-		}
-	}
-
-	if (FD_ISSET (sock, &readfds) == 0)
-	{
-		return CF_ERROR_SOCKET_INTERNAL;
-	}
-
-	return CF_OK;
-}
-
-/**
- * 소켓의 초기화 상태 확인
- *
- * \return 초기화 된 경우, CF_TRUE; 그렇지 않은 경우, CF_FALSE
- */
-CF_BOOL
-CF_Socket_IsInitialized (void)
-{
-	return gInitialized;
-}
-
-/**
- * 소켓 초기화
- *
- * \return 성공 시, CF_OK; 실패 시, 오류 코드
- */
-int
-CF_Socket_Initialize (void)
-{
-#if defined(_WIN32) || defined(_WIN64)
-	WSADATA winsockData;
-	if (WSAStartup (MAKEWORD (2, 0), &winsockData))
-	   return CF_ERROR_SOCKET_INITIALIZE;
-#endif
-	gInitialized = CF_TRUE;
-	
-	return CF_OK;
-}
-
-/**
- * 소켓 해제
- *
- * \return 성공 시, CF_OK; 실패 시, 오류 코드
- */
-int
-CF_Socket_Finalize (void)
-{
-	ASSERT_INIT ();
-
-#if defined(_WIN32) || defined(_WIN64)
-   	if (WSACleanup ())
-	   return CF_ERROR_SOCKET_FINALIZE;
-#endif
-
-	return CF_OK;
-}
-
-/**
- * 소켓 닫기
- *
- * \return 성공 시, CF_OK; 실패 시, 오류 코드
- *
- * \param sock 소켓
- */
-int
-CF_Socket_Close (const int sock)
-{
-	int result = 0;
-
-	ASSERT_SOCKET (sock);
-
-	result = close (sock);
-
-	if (result != 0)
-		return CF_ERROR_SOCKET_CLOSE;
-
-	return CF_OK;
-}
-
-/**
- * 소켓 옵션 설정
- *
- * \return 성공 시 CF_OK; 실패 시, 오류 코드
- *
- * \param sock		소켓
- * \param optname	옵션 이름
- * \param optval	설정할 옵션 값의 메모리
- * \param optlen	설정할 옵션의 길이
- */
-int
-CF_Socket_SetOption (const int		sock,
-					 const int		optname,
-					 const void		* optval,
-					 const size_t	optlen)
+CF_Socket_Local_SetOption (const int	sock,
+						   const int	optname,
+						   const void	* optval,
+						   const size_t	optlen)
 {
 	int	result = 0;
@@ -238,19 +117,9 @@
 }
 
-/**
- * 소켓 옵션 얻기
- *
- * \return 성공 시 CF_OK; 실패 시, 오류 코드
- *
- * \param sock		소켓
- * \param optname	옵션 이름
- * \param optval	옵션 값을 가져올 메모리
- * \param optlen	옵션 길이를 가져올 메모리
- */
-int
-CF_Socket_GetOption (const int	sock,
-					 const int	optname,
-					 void		* optval,
-					 size_t		* optlen)
+static int
+CF_Socket_Local_GetOption (const int	sock,
+						   const int	optname,
+						   void			* optval,
+						   size_t		* optlen)
 {
 	int	result = 0;
@@ -273,37 +142,203 @@
 }
 
+static int
+CF_Socket_Local_SetLinger (const int sock)
+{
+	struct linger linger;
+
+	linger.l_onoff = 1;
+	linger.l_linger = 0;
+
+	return CF_Socket_Local_SetOption (sock,
+									  SO_LINGER,
+									  &linger,
+									  sizeof (linger));
+}
+
+static int
+CF_Socket_Local_SetReUseAddr (const int sock)
+{
+	int reuseaddr = 1;
+
+	return CF_Socket_Local_SetOption (sock,
+									  SO_REUSEADDR,
+									  &reuseaddr,
+									  sizeof (reuseaddr));
+}
+
+static int
+CF_Socket_Local_CheckTimeout (const int	sock,
+							  const int	timeout)
+{
+	int				result = 0;
+	fd_set			readfds;
+	struct timeval	tv;
+	int				error;
+
+	if (timeout <= CF_SOCKET_NO_TIMEOUT)
+		return CF_OK;
+
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+
+	FD_ZERO (&readfds);
+	FD_SET (sock, &readfds);
+
+	while ((result = select (sock + 1, &readfds, NULL, NULL, &tv)) < 0)
+	{
+		error = CF_Util_GetSystemError ();
+		if (error != ERROR_INTR)
+		{
+			result = CF_ERROR_SOCKET_TIMEOUT;
+			return result;
+		}
+	}
+
+	if (FD_ISSET (sock, &readfds) == 0)
+		return CF_ERROR_SOCKET_CHECK_DESC_SET;
+
+	return CF_OK;
+}
+
+/**
+ * 소켓의 초기화 상태 확인
+ *
+ * \return 초기화 된 경우, CF_TRUE; 그렇지 않은 경우, CF_FALSE
+ */
+static CF_BOOL
+CF_Socket_IsInitialized (void)
+{
+	return gInitialized;
+}
+
+/**
+ * 소켓 초기화
+ *
+ * \return 성공 시, CF_OK; 실패 시, 오류 코드
+ */
+int
+CF_Socket_Initialize (void)
+{
+	if (!CF_Socket_IsInitialized ())
+	{
+#if defined(_WIN32) || defined(_WIN64)
+		WSADATA winsockData;
+		if (WSAStartup (MAKEWORD (2, 0), &winsockData))
+			return CF_ERROR_SOCKET_INITIALIZE;
+#endif
+		gInitialized = CF_TRUE;
+	}
+	
+	return CF_OK;
+}
+
+/**
+ * 소켓 해제
+ *
+ * \return 성공 시, CF_OK; 실패 시, 오류 코드
+ */
+int
+CF_Socket_Finalize (void)
+{
+	ASSERT_INIT ();
+
+#if defined(_WIN32) || defined(_WIN64)
+   	if (WSACleanup ())
+	   return CF_ERROR_SOCKET_FINALIZE;
+#endif
+
+	return CF_OK;
+}
+
+/**
+ * 소켓 컨텍스트 생성
+ *
+ * \return 성공 시, CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx	소켓 컨텍스트
+ */
+int
+CF_Socket_Create (cf_ctx * ctx)
+{
+	int result = 0;
+
+	CF_SOCKET_CONTEXT * context = NULL;
+
+	ASSERT_CTX (ctx);
+
+	TRY
+	{
+		context = NEWCTX (CF_SOCKET_CONTEXT);
+		if (context == NULL)
+		{
+			result = CF_ERROR_SOCKET_CREATE_CTX;
+			TRY_BREAK;
+		}
+
+		context->sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+		if (context->sock < 0)
+		{
+			result = CF_ERROR_SOCKET_CREATE;
+			TRY_BREAK;
+		}
+
+		context->timeout = CF_SOCKET_NO_TIMEOUT;
+		*ctx = (CF_SOCKET_CONTEXT *) context;
+	}
+	CATCH_IF (result < 0)
+	{
+		CF_Socket_Close (context);
+	}
+
+	return result;
+}
+
+/**
+ * 소켓 닫기
+ *
+ * \return 성공 시, CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx	소켓 컨텍스트
+ */
+int
+CF_Socket_Close (cf_ctx ctx)
+{
+	int result = 0;
+	int sock = 0;
+
+	CF_SOCKET_CONTEXT * context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (context);
+	ASSERT_SOCKET (context->sock);
+
+	sock = context->sock;
+
+	free (context);
+
+	result = close (sock);
+
+	if (result != 0)
+		return CF_ERROR_SOCKET_CLOSE;
+
+	return CF_OK;
+}
+
 /**
  * 소켓 연결
  *
- * \return 성공 시, 연결된 소켓; 실패 시, 오류 코드
- *
- * \param ip		연결할 호스트의 주소 (도메인 이름 가능)
- * \param port		연결할 호스트의 포트번호
- */
-int
-CF_Socket_Connect (const char			* ip,
+ * \return 성공 시, CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx	소켓 컨텍스트
+ * \param ip	연결할 호스트의 주소 (도메인 이름 가능)
+ * \param port	연결할 호스트의 포트번호
+ */
+int
+CF_Socket_Connect (cf_ctx				ctx,
+				   const char			* ip,
 				   const unsigned short	port)
-{
-	return CF_Socket_ConnectTimeout (ip, port, CF_SOCKET_NO_TIMEOUT);
-}
-
-/**
- * 타임아웃 동안 소켓 연결
- *
- * \return 성공 시, 연결된 소켓; 실패 시, 오류 코드
- *
- * \param ip		연결할 호스트의 주소 (도메인 이름 가능)
- * \param port		연결할 호스트의 포트번호
- * \param timeout	타임아웃 (초)
- *
- * \see CF_SOCKET_NO_TIMEOUT
- */
-int
-CF_Socket_ConnectTimeout (const char			* ip,
-						  const unsigned short	port,
-						  const int				timeout)
 {
 	int					result = 0;
 	int					sock = 0;
+	int					timeout = 0;
 	struct sockaddr_in	address;
 	struct hostent		* hostEnt;
@@ -315,10 +350,14 @@
 	fd_set				writefds;
 
-	ASSERT_INIT ();
-
-	/* 1. create socket */
-	sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
-	if (sock < 0)
-		return CF_ERROR_SOCKET_CREATE;
+	CF_SOCKET_CONTEXT	* context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (ctx);
+	TRY_INIT ();
+
+	/* 1. get and set socket info. */
+	sock = context->sock;
+	snprintf (context->ip, sizeof (context->ip), "%s", ip);
+	context->port = port;
+	timeout = context->timeout;
 
 	/* 2. set data */
@@ -390,5 +429,5 @@
 			retval = 0;
 
-			result = CF_Socket_GetOption (sock, SO_ERROR, &retval, &length);
+			result = CF_Socket_GetOption (ctx, SO_ERROR, &retval, &length);
 			if (result < 0)
 			{
@@ -410,5 +449,5 @@
 	CATCH_IF (result < 0)
 	{
-		CF_Socket_Close (sock);
+		CF_Socket_Close (ctx);
 		return result;
 	}
@@ -417,5 +456,5 @@
 		CF_Socket_Local_SetNonBlocking (sock, CF_FALSE);
 
-	return sock;
+	return result;
 }
 
@@ -423,11 +462,13 @@
  * 서버 열기
  *
- * \return 성공 시, 서버 소켓; 실패 시, 오류 코드
- *
+ * \return 성공 시, CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx		소켓 컨텍스트
  * \param port		서버 포트
  * \param backlog	listen 시의 backlog 수
  */
 int
-CF_Socket_Server (const unsigned short	port,
+CF_Socket_Server (cf_ctx				ctx,
+				  const unsigned short	port,
 				  const int				backlog)
 {
@@ -436,9 +477,11 @@
 	struct sockaddr_in	address;
 
-	ASSERT_INIT ();
-
-	sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
-	if (sock < 0)
-		return CF_ERROR_SOCKET_CREATE;
+	CF_SOCKET_CONTEXT	* context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (ctx);
+	TRY_INIT ();
+
+	sock = context->sock;
+	context->port = port;
 
 	address.sin_family		= AF_INET;
@@ -462,4 +505,8 @@
 		}
 
+		snprintf (context->ip, sizeof (context->ip),
+				  "%s",
+				  inet_ntoa(address.sin_addr));
+
 		result = listen (sock, backlog);
 		if (result < 0)
@@ -471,32 +518,49 @@
 	CATCH_IF (result < 0)
 	{
-		CF_Socket_Close (sock);
-		return result;
-	}
-
-	return sock;
-}
-
-/**
- * 소켓 연결
- *
- * \return 성공 시, 연결된 소켓; 실패 시, 오류 코드
- *
- * \param sock	서버 소켓
- */
-int
-CF_Socket_Accept (const int sock)
-{
-	int					sockClient = 0;
+		CF_Socket_Close (ctx);
+	}
+
+	return result;
+}
+
+/**
+ * 소켓 연결 받기
+ *
+ * \return 성공 시, CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx		소켓 컨텍스트
+ * \param client	연결을 수락할 client 소켓 컨텍스트
+ */
+int
+CF_Socket_Accept (const cf_ctx	ctx,
+				  cf_ctx		* client)
+{
+	int					result = 0;
 	struct sockaddr_in	address;
 	socklen_t			len = sizeof (address);
 
-	ASSERT_SOCKET (sock);
-
-	sockClient = accept (sock, (struct sockaddr *) &address, &len);
-	if (sockClient < 0)
+	CF_SOCKET_CONTEXT	* clntctx = NULL;
+	CF_SOCKET_CONTEXT	* context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (context);
+	ASSERT_CTX (client);
+	ASSERT_SOCKET (context->sock);
+
+	result = CF_Socket_Create ((cf_ctx *)&clntctx);
+	if (result < 0)
+		return result;
+
+	close (clntctx->sock);
+
+	clntctx->sock = accept (context->sock, (struct sockaddr *) &address, &len);
+	if (clntctx->sock < 0)
+	{
+		CF_Socket_Close ((cf_ctx *)clntctx);
 		return CF_ERROR_SOCKET_ACCEPT;
-
-	return sockClient;
+	}
+
+	*client = (cf_ctx) clntctx;
+
+	return CF_OK;
 }
 
@@ -506,39 +570,20 @@
  * \return 성공 시, CF_OK; 실패 시, 오류 코드
  *
- * \param sock	소켓
- * \param buf	송신할 데이터
+ * \param ctx	소켓 컨텍스트 * \param buf	송신할 데이터
  * \param len	송신할 데이터의 길이
  */
 int
-CF_Socket_Send (const int		sock,
+CF_Socket_Send (const cf_ctx	ctx,
 				const void		* buf,
 				const size_t	len)
 {
-	return CF_Socket_SendTimeout (sock, buf, len, CF_SOCKET_NO_TIMEOUT);
-}
-
-/**
- * 타임아웃 동안 데이터 송신
- *
- * \return 성공 시, CF_OK; 실패 시, 오류 코드
- *
- * \param sock		소켓
- * \param buf		송신할 데이터
- * \param len		송신할 데이터의 길이
- * \param timeout	타임아웃 (초)
- *
- * \see CF_SOCKET_NO_TIMEOUT
- */
-int
-CF_Socket_SendTimeout (const int	sock,
-					   const void	* buf,
-					   const size_t	len,
-					   const int	timeout)
-{
 	int result = 0;
 
-	ASSERT_SOCKET (sock);
-
-	result = (int) send (sock, buf, len, 0);
+	CF_SOCKET_CONTEXT	* context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (context);
+	ASSERT_SOCKET (context->sock);
+
+	result = (int) send (context->sock, buf, len, 0);
 	if (result != len)
 		return CF_ERROR_SOCKET_SEND;
@@ -552,43 +597,25 @@
  * \return 성공 시, 수신한 데이터의 길이; 실패 시, 오류 코드
  *
- * \param sock	소켓
+ * \param ctx	소켓 컨텍스트
  * \param buf	데이터를 수신할 버퍼
  * \param len	데이터를 수신할 버퍼의 최대 크기
  */
 int
-CF_Socket_Recv (const int		sock,
+CF_Socket_Recv (const cf_ctx	ctx,
 				void			* buf,
 				const size_t	len)
 {
-	return CF_Socket_RecvTimeout (sock, buf, len, CF_SOCKET_NO_TIMEOUT);
-}
-
-/**
- * 타임아웃 동안 데이터 수신
- *
- * \return 성공 시, 수신한 데이터의 길이; 실패 시, 오류 코드
- *
- * \param sock		소켓
- * \param buf		데이터를 수신할 버퍼
- * \param len		데이터를 수신할 버퍼의 최대 크기
- * \param timeout	타임아웃 (초)
- *
- * \see CF_SOCKET_NO_TIMEOUT
- */
-int
-CF_Socket_RecvTimeout (const int	sock,
-					   void			* buf,
-					   const size_t	len,
-					   const int	timeout)
-{
 	int result = 0;
 
-	ASSERT_SOCKET (sock);
-
-	result = CF_Socket_Local_CheckTimeout (sock, timeout);
+	CF_SOCKET_CONTEXT	* context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (context);
+	ASSERT_SOCKET (context->sock);
+
+	result = CF_Socket_Local_CheckTimeout (context->sock, context->timeout);
 	if (result < 0)
 		return result;
 
-	result = (int) recv (sock, buf, len, 0);
+	result = (int) recv (context->sock, buf, len, 0);
 	if (result < 0)
 		return CF_ERROR_SOCKET_RECV;
@@ -596,2 +623,118 @@
 	return result;
 }
+
+/**
+ * 소켓 옵션 설정
+ *
+ * \return 성공 시 CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx		소켓 컨텍스트
+ * \param optname	옵션 이름
+ * \param optval	설정할 옵션 값의 메모리
+ * \param optlen	설정할 옵션의 길이
+ */
+int
+CF_Socket_SetOption (const cf_ctx	ctx,
+					 const int		optname,
+					 const void		* optval,
+					 const size_t	optlen)
+{
+	CF_SOCKET_CONTEXT * context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (context);
+
+	return CF_Socket_Local_SetOption (context->sock,
+									  optname,
+									  optval,
+									  optlen);
+}
+
+/**
+ * 소켓 옵션 얻기
+ *
+ * \return 성공 시 CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx		소켓 컨텍스트
+ * \param optname	옵션 이름
+ * \param optval	옵션 값을 가져올 메모리
+ * \param optlen	옵션 길이를 가져올 메모리
+ */
+int
+CF_Socket_GetOption (const cf_ctx	ctx,
+					 const int		optname,
+					 void			* optval,
+					 size_t			* optlen)
+{
+	CF_SOCKET_CONTEXT * context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (context);
+
+	return CF_Socket_Local_GetOption (context->sock,
+									  optname,
+									  optval,
+									  optlen);
+}
+
+/**
+ * 소켓 컨텍스트에 타임아웃 설정
+ *
+ * \return CF_OK 반환
+ *
+ * \param ctx		소켓 컨텍스트
+ * \param timeout	설정할 타임아웃 시간
+ */
+int
+CF_Socket_SetTimeOut (cf_ctx	ctx,
+					  int		timeout)
+{
+	CF_SOCKET_CONTEXT * context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (context);
+
+	context->timeout = timeout;
+
+	return CF_OK;
+}
+
+/**
+ * 소켓 컨텍스트에 타임아웃 설정
+ *
+ * \return 성공 시 CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx	소켓 컨텍스트
+ * \param ip	ip 주소를 저장할 충분한 공간의 메모리
+ */
+int
+CF_Socket_GetIP (const cf_ctx	ctx,
+				 char			* ip)
+{
+	CF_SOCKET_CONTEXT * context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_CTX (context);
+	ASSERT_ARGS (ip == NULL);
+
+	snprintf (ip, sizeof (context->ip), "%s", context->ip);
+
+	return CF_OK;
+}
+
+/**
+ * 소켓 컨텍스트에 타임아웃 설정
+ *
+ * \return 성공 시 CF_OK; 실패 시, 오류 코드
+ *
+ * \param ctx	소켓 컨텍스트
+ * \param port	포트 번호 저장할 포인터
+ */
+int
+CF_Socket_GetPort (const cf_ctx		ctx,
+				   unsigned short	* port)
+{
+	CF_SOCKET_CONTEXT * context = (CF_SOCKET_CONTEXT *) ctx;
+
+	ASSERT_ARGS (port == NULL);
+
+	*port = context->port;
+
+	return CF_OK;
+}
