Changeset 46 in libcf


Ignore:
Timestamp:
03/29/13 14:40:25 (11 years ago)
Author:
cheese
Message:

#1 change timeout mechanism from setting socket option to using select

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/cf_error.h

    r41 r46  
    77#define CF_ERROR_BASE                       CF_ERROR * 1000
    88
    9 /* socket {{{ */
     9/* file {{{ */
    1010#define CF_ERROR_FILE                       CF_ERROR_BASE * 2
    1111/*------------------------------------------------------------*/
     
    1919#define CF_ERROR_FILE_MAKE_DIRECTORY        CF_ERROR_FILE - 8
    2020
    21 /* }}} socket */
     21/* }}} file */
    2222
    2323/* socket {{{ */
     
    3232#define CF_ERROR_SOCKET_SET_OPTION          CF_ERROR_SOCKET - 7
    3333#define CF_ERROR_SOCKET_GET_OPTION          CF_ERROR_SOCKET - 8
    34 #define CF_ERROR_SOCKET_SET_TIMEOUT         CF_ERROR_SOCKET - 9
     34#define CF_ERROR_SOCKET_TIMEOUT             CF_ERROR_SOCKET - 9
    3535#define CF_ERROR_SOCKET_INVALID_ARGS        CF_ERROR_SOCKET - 10
    3636#define CF_ERROR_SOCKET_INVALID_SOCKET      CF_ERROR_SOCKET - 11
     
    4141#define CF_ERROR_SOCKET_SEND                CF_ERROR_SOCKET - 16
    4242#define CF_ERROR_SOCKET_RECV                CF_ERROR_SOCKET - 17
     43#define CF_ERROR_SOCKET_INTERNAL            CF_ERROR_SOCKET - 18
    4344/* }}} socket */
    4445
  • trunk/include/cf_socket.h

    r40 r46  
    1313
    1414#include "cf_base.h"
     15
    1516#include <stddef.h>
    1617
    17 #ifdef _WIN32
    18 # include <WinSock2.h>
    19 #else
    20 # include <netinet/in.h>
    21 # include <sys/socket.h>
    22 # include <arpa/inet.h>
    23 # include <netdb.h>
    24 # include <unistd.h>
    25 #endif
     18/** 타임아웃을 설정하지 않음 */
     19#define CF_SOCKET_NO_TIMEOUT        -1
    2620
    27 #ifdef _WIN32
    28 typedef int socklen_t;
    29 #endif // #ifdef _WIN32
     21/** 호스트 정보 */
     22typedef struct cf_socket_hostinfo {
     23    char            address[128];   /**< 원격 호스트 주소 */
     24    unsigned short  port;           /**< 원격 호스트 포트 */
     25} CF_Socket_HostInfo;
    3026
    3127#ifdef __cplusplus
     
    3430
    3531CF_EXPORT CF_BOOL
    36 CF_Socket_IsInitialized (void);
     32CF_Socket_IsInitialized     (void);
    3733
    3834CF_EXPORT int
    39 CF_Socket_Initialize    (void);
     35CF_Socket_Initialize        (void);
    4036
    4137CF_EXPORT int
    42 CF_Socket_Finalize      (void);
     38CF_Socket_Finalize          (void);
    4339
    4440CF_EXPORT int
    45 CF_Socket_Close         (const int sock);
     41CF_Socket_Close             (const int sock);
    4642
    4743CF_EXPORT int
    48 CF_Socket_SetOption     (const int      sock,
    49                         const int      optname,
    50                         const void     * optval,
    51                         const size_t   optlen);
     44CF_Socket_SetOption         (const int      sock,
     45                            const int      optname,
     46                            const void     * optval,
     47                            const size_t   optlen);
    5248
    5349CF_EXPORT int
    54 CF_Socket_GetOption     (const int  sock,
    55                         const int  optname,
    56                         void       * optval,
    57                         size_t     * optlen);
     50CF_Socket_GetOption         (const int  sock,
     51                            const int  optname,
     52                            void       * optval,
     53                            size_t     * optlen);
    5854
    5955CF_EXPORT int
    60 CF_Socket_SetTimeout    (const int  sock,
    61                          const int  timeout);
     56CF_Socket_Connect           (const char             * ip,
     57                             const unsigned short   port);
    6258
    6359CF_EXPORT int
    64 CF_Socket_Connect       (const char             * ip,
    65                          const unsigned short   port);
     60CF_Socket_ConnectTimeout    (const char             * ip,
     61                             const unsigned short   port,
     62                             const int              timeout);
    6663
    6764CF_EXPORT int
    68 CF_Socket_Server        (const unsigned short   port,
    69                         const int              backlog);
     65CF_Socket_Server            (const unsigned short   port,
     66                            const int              backlog);
    7067
    7168CF_EXPORT int
    72 CF_Socket_Accept        (const int          sock,
    73                          struct sockaddr_in * address);
     69CF_Socket_Accept            (const int          sock,
     70                             CF_Socket_HostInfo * host);
    7471
    7572CF_EXPORT int
    76 CF_Socket_Send          (const int  sock,
    77                         const void * buf,
    78                         const int  len);
     73CF_Socket_Send              (const int  sock,
     74                            const void * buf,
     75                            const int  len);
    7976
    8077CF_EXPORT int
    81 CF_Socket_Recv          (const int  sock,
    82                          void       * buf,
    83                          const int  len);
     78CF_Socket_SendTimeout       (const int  sock,
     79                             const void * buf,
     80                             const int  len,
     81                             const int  timeout);
     82
     83CF_EXPORT int
     84CF_Socket_Recv              (const int  sock,
     85                             void       * buf,
     86                             const int  len);
     87
     88CF_EXPORT int
     89CF_Socket_RecvTimeout       (const int  sock,
     90                             void       * buf,
     91                             const int  len,
     92                             const int  timeout);
    8493
    8594#ifdef __cplusplus
  • trunk/src/cf_file.c

    r44 r46  
    188188    char    * d = stepPath;
    189189
    190     sprintf (fullPath, "%s%c", path, DELIMITER);
     190    snprintf (fullPath, sizeof (fullPath) - 1, "%s%c", path, DELIMITER);
    191191
    192192    for (*d++ = *f++ ; *f ; *d++ = *f++)
  • trunk/src/cf_log.c

    r45 r46  
    304304
    305305    CF_Log_Local_GetTimeString (datetime);
    306     sprintf (buffer, "[%s][%s] ", datetime, prefix);
     306    snprintf (buffer, sizeof (buffer) - 1, "[%s][%s] ", datetime, prefix);
    307307    vsprintf (buffer + strlen (buffer), fmt, valist);
    308308
     
    408408            TRY_BREAK;
    409409        }
    410         sprintf (context->path, "%s", path);
     410        snprintf (context->path, sizeof (context->path) -1, "%s", path);
    411411
    412412        if (size > 0)
  • trunk/src/cf_socket.c

    r45 r46  
    88#include "cf_error.h"
    99
     10#include <stdio.h>
     11#include <string.h>
     12
    1013#ifdef _WIN32
     14/* for windows {{{ */
     15# include <WinSock2.h>
    1116# pragma comment (lib, "ws2_32.lib")
    12 # define close(__sock)  closesocket(__sock)
    13 # define sa_family_t    unsigned short
     17/* }}} for windows */
    1418#else
    15 #endif
    16 
    17 #include <string.h>
     19/* for linux/unix {{{ */
     20# include <netinet/in.h>
     21# include <sys/socket.h>
     22# include <arpa/inet.h>
     23# include <netdb.h>
     24# include <unistd.h>
     25# include <sys/un.h>
     26# include <fcntl.h>
     27# include <errno.h>
     28/* }}} for linux/unix */
     29#endif
    1830
    1931#define CHECK_SOCKET_INIT()                 \
     
    2537        return CF_ERROR_SOCKET_INVALID_SOCKET
    2638
     39#ifdef WIN32
     40typedef int                 socklen_t;
     41# define sa_family_t        unsigned short
     42# define close(__sock)      closesocket(__sock)
     43# define CHECK_SELECT(x)    ((x) == SOCKET_ERROR)
     44# define GET_SYSTEM_ERROR() WSAGetLastError ()
     45# define ERROR_INTR         WSAEINTR
     46#else
     47# define CHECK_SELECT(x)    ((x) < 0)
     48# define GET_SYSTEM_ERROR() errno
     49# define ERROR_INTR         EINTR
     50#endif
     51
    2752static CF_BOOL gInitialized = CF_FALSE;
     53
     54static void
     55CF_Socket_Local_SetNonBlocking (const int   sock,
     56                                CF_BOOL     boolean)
     57{
     58#ifdef WIN32
     59    unsigned long mode = (boolean == CF_TRUE) ? 1 : 0;
     60    ioctlsocket (sock, FIONBIO, &mode);
     61#else
     62    int flags = fcntl (sock, F_GETFL, 0);
     63
     64    if (boolean)
     65        flags |=  O_NONBLOCK;
     66    else
     67        flags &= ~O_NONBLOCK;
     68
     69    fcntl (sock, F_SETFL, flags);
     70#endif
     71}
     72
     73static int
     74CF_Socket_Local_CheckTimeout (const int sock,
     75                              const int timeout)
     76{
     77    int             result = 0;
     78    fd_set          readfds;
     79    struct timeval  tv;
     80    int             error;
     81
     82    if (!(timeout > CF_SOCKET_NO_TIMEOUT))
     83        return CF_OK;
     84
     85    tv.tv_sec = timeout;
     86    tv.tv_usec = 0;
     87
     88    FD_ZERO (&readfds);
     89    FD_SET (sock, &readfds);
     90
     91    while (CHECK_SELECT (result = select (sock + 1, &readfds, NULL, NULL, &tv)))
     92    {
     93        error = GET_SYSTEM_ERROR ();
     94        if (error != ERROR_INTR)
     95        {
     96            result = CF_ERROR_SOCKET_TIMEOUT;
     97            return result;
     98        }
     99    }
     100
     101    if (FD_ISSET (sock, &readfds) == 0)
     102    {
     103        return CF_ERROR_SOCKET_INTERNAL;
     104    }
     105
     106    return CF_OK;
     107}
    28108
    29109/**
     
    46126CF_Socket_Initialize (void)
    47127{
    48     int result = 0;
    49 
    50128#ifdef WIN32
    51129    WSADATA winsockData;
    52     result = WSAStartup (MAKEWORD (2, 0), &winsockData);
     130    if (WSAStartup (MAKEWORD (2, 0), &winsockData))
     131       return CF_ERROR_SOCKET_INITIALIZE;
    53132#endif
    54133    gInitialized = CF_TRUE;
    55 
    56     if (result != 0)
    57        return CF_ERROR_SOCKET_INITIALIZE;
    58134   
    59135    return CF_OK;
     
    68144CF_Socket_Finalize (void)
    69145{
    70     int result = 0;
    71 
    72146    CHECK_SOCKET_INIT ();
    73147
    74148#ifdef WIN32
    75     result = WSACleanup ();
    76 #endif
    77     if (result != 0)
     149    if (WSACleanup ())
    78150       return CF_ERROR_SOCKET_FINALIZE;
     151#endif
    79152
    80153    return CF_OK;
     
    174247
    175248/**
    176  * 소켓에 타임아웃 설정
    177  *
    178  * @return 성공 시 CF_OK; 실패 시, 오류 코드
    179  *
    180  * @param sock      소켓
    181  * @param timeout   타임아웃(sec)
    182  */
    183 int
    184 CF_Socket_SetTimeout (const int sock,
    185                       const int timeout)
    186 {
    187     int result = 0;
    188 
    189 #ifdef _WIN32
    190     int time_ms = timeout * 1000;
    191 #else
    192     struct timeval  timeval;
    193     timeval.tv_sec = timeout;
    194     timeval.tv_usec= 0;
    195 #endif
    196 
    197     CHECK_INVALID_SOCKET (sock);
    198 
    199     if (timeout < 0)
    200         return CF_ERROR_SOCKET_INVALID_ARGS;
    201 
    202     result = CF_Socket_SetOption (sock,
    203                                   SO_RCVTIMEO,
    204 #ifdef _WIN32
    205                                   &time_ms,
    206                                   sizeof (time_ms));
    207 #else
    208                                   &timeval,
    209                                   sizeof (timeval));
    210 #endif
    211     if (result < 0)
    212         return CF_ERROR_SOCKET_SET_TIMEOUT;
    213 
    214     return CF_OK;
    215 }
    216 
    217 /**
    218249 * 소켓 연결
    219250 *
    220251 * @return 성공 시, 연결된 소켓; 실패 시, 오류 코드
    221252 *
    222  * @param ip    연결할 호스트의 주소 (도메인 이름 가능)
    223  * @param port  연결할 호스트의 포트번호
     253 * @param ip        연결할 호스트의 주소 (도메인 이름 가능)
     254 * @param port      연결할 호스트의 포트번호
    224255 */
    225256int
    226257CF_Socket_Connect (const char           * ip,
    227258                   const unsigned short port)
     259{
     260    return CF_Socket_ConnectTimeout (ip, port, CF_SOCKET_NO_TIMEOUT);
     261}
     262
     263/**
     264 * 타임아웃 동안 소켓 연결
     265 *
     266 * @return 성공 시, 연결된 소켓; 실패 시, 오류 코드
     267 *
     268 * @param ip        연결할 호스트의 주소 (도메인 이름 가능)
     269 * @param port      연결할 호스트의 포트번호
     270 * @param timeout   타임아웃 (초)
     271 *
     272 * @see CF_SOCKET_NO_TIMEOUT
     273 */
     274int
     275CF_Socket_ConnectTimeout (const char            * ip,
     276                          const unsigned short  port,
     277                          const int             timeout)
    228278{
    229279    int                 result = 0;
     
    231281    struct sockaddr_in  address;
    232282    struct hostent      * hostEnt;
     283    struct linger       linger;
     284
     285    int                 retval = 0;
     286    size_t              length = 0;
     287    struct timeval      tv;
     288    fd_set              readfds;
     289    fd_set              writefds;
    233290
    234291    CHECK_SOCKET_INIT ();
    235292
     293    /* 1. create socket */
    236294    sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
    237295    if (sock < 0)
    238296        return CF_ERROR_SOCKET_CREATE;
    239297
     298    /* 2. set data */
    240299    address.sin_family      = AF_INET;
    241300    address.sin_port        = htons (port);
    242301    address.sin_addr.s_addr = inet_addr (ip);
    243302
     303    linger.l_onoff = 1;
     304    linger.l_linger = 0;
     305
    244306    TRY
    245307    {
     308        /* 3. get ip from hostname if inet_addr() is failed */
    246309        if (address.sin_addr.s_addr == (unsigned int)-1)
    247310        {
     
    254317
    255318            address.sin_family = (sa_family_t) hostEnt->h_addrtype;
    256             memcpy (&(address.sin_addr.s_addr), hostEnt->h_addr, (size_t) hostEnt->h_length);
    257         }
    258 
     319            memcpy (&(address.sin_addr.s_addr),
     320                    hostEnt->h_addr,
     321                    (size_t) hostEnt->h_length);
     322        }
     323
     324        /* 4. set options */
     325        result = CF_Socket_SetOption (sock, SO_LINGER, &linger, sizeof (linger));
     326        if (result < 0)
     327        {
     328            result = CF_ERROR_SOCKET_SET_OPTION;
     329            TRY_BREAK;
     330        }
     331
     332        if (timeout > CF_SOCKET_NO_TIMEOUT)
     333            CF_Socket_Local_SetNonBlocking (sock, CF_TRUE);
     334
     335        /* 5. connect */
    259336        result = connect (sock, (struct sockaddr *) &address, sizeof (address));
    260         if (result < 0)
     337        if (result == 0)
     338        {
     339            result = CF_OK;
     340            TRY_BREAK;
     341        }
     342
     343        /* 6. if connect() is returned, check timeout */
     344        if (timeout == CF_SOCKET_NO_TIMEOUT)
     345        {
     346            result = CF_ERROR_SOCKET_TIMEOUT;
     347            TRY_BREAK;
     348        }
     349
     350        FD_ZERO (&readfds);
     351        FD_SET ((unsigned int)sock, &readfds);
     352        writefds = readfds;
     353
     354        tv.tv_sec = timeout;
     355        tv.tv_usec = 0;
     356
     357        result = select (sock + 1, &readfds, &writefds, NULL, &tv);
     358        if (result == 0)
     359        {
     360            result = CF_ERROR_SOCKET_TIMEOUT;
     361            TRY_BREAK;
     362        }
     363
     364        if (FD_ISSET (sock, &readfds) || FD_ISSET (sock, &writefds))
     365        {
     366            length = sizeof (retval);
     367            retval = 0;
     368
     369            result = CF_Socket_GetOption (sock, SO_ERROR, &retval, &length);
     370            if (result < 0)
     371            {
     372                result = CF_ERROR_SOCKET_GET_OPTION;
     373                TRY_BREAK;
     374            }
     375            else if (retval)
     376            {
     377                result = CF_ERROR_SOCKET_CONNECT;
     378                TRY_BREAK;
     379            }
     380        }
     381        else
    261382        {
    262383            result = CF_ERROR_SOCKET_CONNECT;
     
    269390        return result;
    270391    }
     392
     393    if (timeout > CF_SOCKET_NO_TIMEOUT)
     394        CF_Socket_Local_SetNonBlocking (sock, CF_FALSE);
    271395
    272396    return sock;
     
    330454 *
    331455 * @param sock      서버 소켓
    332  * @param address   [옵션] 클라이언트 정보를 담을 sockaddr_in 구조체 포인터
     456 * @param address   [옵션] 클라이언트 정보를 담을 CF_Socket_HostInfo 구조체 포인터
     457 *
     458 * @see CF_Socket_HostInfo
    333459 */
    334460int
    335461CF_Socket_Accept (const int             sock,
    336                   struct sockaddr_in    * address)
    337 {
    338     int                 sockClient;
    339     struct sockaddr_in  remoteAddress;
    340     socklen_t           len = sizeof (remoteAddress);
     462                  CF_Socket_HostInfo    * host)
     463{
     464    int                 sockClient = 0;
     465    struct sockaddr_in  address;
     466    socklen_t           len = sizeof (address);
    341467
    342468    CHECK_INVALID_SOCKET (sock);
    343469
    344     sockClient = accept (sock, (struct sockaddr *) &remoteAddress, &len);
     470    sockClient = accept (sock, (struct sockaddr *) &address, &len);
    345471    if (sockClient < 0)
    346472        return CF_ERROR_SOCKET_ACCEPT;
    347473
    348     if (address != NULL)
    349         memcpy ((void *) address, (void *) &remoteAddress, sizeof (struct sockaddr_in));
     474    if (host != NULL)
     475    {
     476        snprintf (host->address, sizeof (host->address) - 1,
     477                  "%s",
     478                  inet_ntoa (address.sin_addr));
     479        host->port = ntohs (address.sin_port);
     480    }
    350481
    351482    return sockClient;
     
    366497                const int   len)
    367498{
     499    return CF_Socket_SendTimeout (sock, buf, len, CF_SOCKET_NO_TIMEOUT);
     500}
     501
     502/**
     503 * 타임아웃 동안 데이터 송신
     504 *
     505 * @return 성공 시, CF_OK; 실패 시, 오류 코드
     506 *
     507 * @param sock      소켓
     508 * @param buf       송신할 데이터
     509 * @param len       송신할 데이터의 길이
     510 * @param timeout   타임아웃 (초)
     511 *
     512 * @see CF_SOCKET_NO_TIMEOUT
     513 */
     514int
     515CF_Socket_SendTimeout (const int    sock,
     516                       const void   * buf,
     517                       const int    len,
     518                       const int    timeout)
     519{
    368520    int result = 0;
    369521
     
    391543                const int   len)
    392544{
     545    return CF_Socket_RecvTimeout (sock, buf, len, CF_SOCKET_NO_TIMEOUT);
     546}
     547
     548/**
     549 * 타임아웃 동안 데이터 수신
     550 *
     551 * @return 성공 시, 수신한 데이터의 길이; 실패 시, 오류 코드
     552 *
     553 * @param sock      소켓
     554 * @param buf       데이터를 수신할 버퍼
     555 * @param len       데이터를 수신할 버퍼의 최대 크기
     556 * @param timeout   타임아웃 (초)
     557 *
     558 * @see CF_SOCKET_NO_TIMEOUT
     559 */
     560int
     561CF_Socket_RecvTimeout (const int    sock,
     562                       void         * buf,
     563                       const int    len,
     564                       const int    timeout)
     565{
    393566    int result = 0;
    394567
    395568    CHECK_INVALID_SOCKET (sock);
    396569
    397     result = (int) recv (sock, buf, (size_t) len, 0);
    398     if (result < 0)
    399         return CF_ERROR_SOCKET_RECV;
     570    TRY
     571    {
     572        result = CF_Socket_Local_CheckTimeout (sock, timeout);
     573        if (result < 0)
     574        {
     575            TRY_BREAK;
     576        }
     577
     578        result = (int) recv (sock, buf, (size_t) len, 0);
     579        if (result < 0)
     580        {
     581            result = CF_ERROR_SOCKET_RECV;
     582            TRY_BREAK;
     583        }
     584    }
     585    CATCH_IF (result < 0)
     586    {
     587        return result;
     588    }
    400589
    401590    return result;
  • trunk/test/socket_client.c

    r39 r46  
    1010int main (void) {
    1111    int sock = 0;
    12     int recvd = 0;
     12    int result = 0;
    1313    char buf[] = "http://unsigned.kr";
    1414    unsigned short port = 12345;
     
    1919    sock = CF_Socket_Connect ("localhost", port);
    2020    if (sock < 0) {
    21         // error
     21        fprintf (stderr, "error : connect (%d)\n", sock);
    2222    }
    23     if (CF_Socket_Send (sock, buf, sizeof (buf)) < 0) {
    24         // error
     23
     24    result = CF_Socket_Send (sock, buf, sizeof (buf));
     25    if (result < 0) {
     26        fprintf (stderr, "error : send (%d)\n", sock);
    2527    }
    2628    memset (buf, 0x00, strlen (buf));
    27     if ((recvd = CF_Socket_Recv (sock, buf, sizeof (buf))) < 0) {
    28         // error
     29
     30    result = CF_Socket_Recv (sock, buf, sizeof (buf));
     31    if (result < 0) {
     32        fprintf (stderr, "error : recv (%d)\n", result);
    2933    }
    30     fprintf (stderr, "client recv : %s\n", buf);
     34    fprintf (stderr, "client recv : %s(%d)\n", buf,, result);
     35
    3136    CF_Socket_Close (sock);
    3237    CF_Socket_Finalize ();
  • trunk/test/socket_server.c

    r35 r46  
    1111    int clntsock = 0;
    1212    unsigned short port = 12345;
    13     int recvd = 0;
     13    int result = 0;
    1414    char buf[1024] = {0x00,};
    1515
     
    1919    srvsock = CF_Socket_Server (port, 5);
    2020    if (srvsock < 0) {
    21         // error
     21        fprintf (stderr, "error : server (%d)\n", srvsock);
    2222    }
     23
    2324    clntsock = CF_Socket_Accept (srvsock, NULL);
    2425    if (clntsock < 0) {
    25         // error
     26        fprintf (stderr, "error : accept (%d)\n", clntsock);
    2627    }
    27     if ((recvd = CF_Socket_Recv (clntsock, buf, sizeof (buf))) < 0) {
    28         // error
     28
     29    result = CF_Socket_Recv (clntsock, buf, sizeof (buf));
     30    if (result < 0) {
     31        fprintf (stderr, "error : recv (%d)\n", result);
    2932    }
    30     fprintf (stderr, "server recv : %s\n", buf);
    31     if (CF_Socket_Send (clntsock, buf, recvd) < 0) {
    32         // error
     33    fprintf (stderr, "server recv : %s(%d)\n", buf, result);
     34
     35    result = CF_Socket_Send (clntsock, buf, result);
     36    if (result < 0) {
     37        fprintf (stderr, "error : send (%d)\n", result);
    3338    }
     39
    3440    CF_Socket_Close (srvsock);
    3541    CF_Socket_Finalize ();
Note: See TracChangeset for help on using the changeset viewer.