Changeset 46 in libcf for trunk/src/cf_socket.c
- Timestamp:
- 03/29/13 14:40:25 (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/cf_socket.c
r45 r46 8 8 #include "cf_error.h" 9 9 10 #include <stdio.h> 11 #include <string.h> 12 10 13 #ifdef _WIN32 14 /* for windows {{{ */ 15 # include <WinSock2.h> 11 16 # pragma comment (lib, "ws2_32.lib") 12 # define close(__sock) closesocket(__sock) 13 # define sa_family_t unsigned short 17 /* }}} for windows */ 14 18 #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 18 30 19 31 #define CHECK_SOCKET_INIT() \ … … 25 37 return CF_ERROR_SOCKET_INVALID_SOCKET 26 38 39 #ifdef WIN32 40 typedef 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 27 52 static CF_BOOL gInitialized = CF_FALSE; 53 54 static void 55 CF_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 73 static int 74 CF_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 } 28 108 29 109 /** … … 46 126 CF_Socket_Initialize (void) 47 127 { 48 int result = 0;49 50 128 #ifdef WIN32 51 129 WSADATA winsockData; 52 result = WSAStartup (MAKEWORD (2, 0), &winsockData); 130 if (WSAStartup (MAKEWORD (2, 0), &winsockData)) 131 return CF_ERROR_SOCKET_INITIALIZE; 53 132 #endif 54 133 gInitialized = CF_TRUE; 55 56 if (result != 0)57 return CF_ERROR_SOCKET_INITIALIZE;58 134 59 135 return CF_OK; … … 68 144 CF_Socket_Finalize (void) 69 145 { 70 int result = 0;71 72 146 CHECK_SOCKET_INIT (); 73 147 74 148 #ifdef WIN32 75 result = WSACleanup (); 76 #endif 77 if (result != 0) 149 if (WSACleanup ()) 78 150 return CF_ERROR_SOCKET_FINALIZE; 151 #endif 79 152 80 153 return CF_OK; … … 174 247 175 248 /** 176 * 소켓에 타임아웃 설정177 *178 * @return 성공 시 CF_OK; 실패 시, 오류 코드179 *180 * @param sock 소켓181 * @param timeout 타임아웃(sec)182 */183 int184 CF_Socket_SetTimeout (const int sock,185 const int timeout)186 {187 int result = 0;188 189 #ifdef _WIN32190 int time_ms = timeout * 1000;191 #else192 struct timeval timeval;193 timeval.tv_sec = timeout;194 timeval.tv_usec= 0;195 #endif196 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 _WIN32205 &time_ms,206 sizeof (time_ms));207 #else208 &timeval,209 sizeof (timeval));210 #endif211 if (result < 0)212 return CF_ERROR_SOCKET_SET_TIMEOUT;213 214 return CF_OK;215 }216 217 /**218 249 * 소켓 연결 219 250 * 220 251 * @return 성공 시, 연결된 소켓; 실패 시, 오류 코드 221 252 * 222 * @param ip 연결할 호스트의 주소 (도메인 이름 가능)223 * @param port 연결할 호스트의 포트번호253 * @param ip 연결할 호스트의 주소 (도메인 이름 가능) 254 * @param port 연결할 호스트의 포트번호 224 255 */ 225 256 int 226 257 CF_Socket_Connect (const char * ip, 227 258 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 */ 274 int 275 CF_Socket_ConnectTimeout (const char * ip, 276 const unsigned short port, 277 const int timeout) 228 278 { 229 279 int result = 0; … … 231 281 struct sockaddr_in address; 232 282 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; 233 290 234 291 CHECK_SOCKET_INIT (); 235 292 293 /* 1. create socket */ 236 294 sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); 237 295 if (sock < 0) 238 296 return CF_ERROR_SOCKET_CREATE; 239 297 298 /* 2. set data */ 240 299 address.sin_family = AF_INET; 241 300 address.sin_port = htons (port); 242 301 address.sin_addr.s_addr = inet_addr (ip); 243 302 303 linger.l_onoff = 1; 304 linger.l_linger = 0; 305 244 306 TRY 245 307 { 308 /* 3. get ip from hostname if inet_addr() is failed */ 246 309 if (address.sin_addr.s_addr == (unsigned int)-1) 247 310 { … … 254 317 255 318 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 */ 259 336 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 261 382 { 262 383 result = CF_ERROR_SOCKET_CONNECT; … … 269 390 return result; 270 391 } 392 393 if (timeout > CF_SOCKET_NO_TIMEOUT) 394 CF_Socket_Local_SetNonBlocking (sock, CF_FALSE); 271 395 272 396 return sock; … … 330 454 * 331 455 * @param sock 서버 소켓 332 * @param address [옵션] 클라이언트 정보를 담을 sockaddr_in 구조체 포인터 456 * @param address [옵션] 클라이언트 정보를 담을 CF_Socket_HostInfo 구조체 포인터 457 * 458 * @see CF_Socket_HostInfo 333 459 */ 334 460 int 335 461 CF_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); 341 467 342 468 CHECK_INVALID_SOCKET (sock); 343 469 344 sockClient = accept (sock, (struct sockaddr *) & remoteAddress, &len);470 sockClient = accept (sock, (struct sockaddr *) &address, &len); 345 471 if (sockClient < 0) 346 472 return CF_ERROR_SOCKET_ACCEPT; 347 473 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 } 350 481 351 482 return sockClient; … … 366 497 const int len) 367 498 { 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 */ 514 int 515 CF_Socket_SendTimeout (const int sock, 516 const void * buf, 517 const int len, 518 const int timeout) 519 { 368 520 int result = 0; 369 521 … … 391 543 const int len) 392 544 { 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 */ 560 int 561 CF_Socket_RecvTimeout (const int sock, 562 void * buf, 563 const int len, 564 const int timeout) 565 { 393 566 int result = 0; 394 567 395 568 CHECK_INVALID_SOCKET (sock); 396 569 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 } 400 589 401 590 return result;
Note:
See TracChangeset
for help on using the changeset viewer.