📄 ncbi_socket.c
字号:
assert(0); break; }}extern ESwitch SOCK_SetDataLoggingAPI(ESwitch log){ ESwitch old = s_Log; if (log == eDefault) log = eOff; s_Log = log; return old;}extern ESwitch SOCK_SetDataLogging(SOCK sock, ESwitch log){ ESwitch old = sock->log; sock->log = log; return old;}/****************************************************************************** * API Initialization and Shutdown/Cleanup */extern void SOCK_AllowSigPipeAPI(void){#ifdef NCBI_OS_UNIX s_AllowSigPipe = 1/*true - API will not mask SIGPIPE out at init*/;#endif /*NCBI_OS_UNIX*/ return;}#if 0/*defined(_DEBUG) && !defined(NDEBUG)*/# if !defined(__GNUC__) && !defined(offsetof)# define offsetof(T, F) ((size_t)((char*) &(((T*) 0)->F) - (char*) 0))# endifstatic void s_ShowDataLayout(void){ CORE_LOGF(eLOG_Note, ("SOCK data layout:\n" " Sizeof(SOCK_struct) = %u, offsets follow\n" "\tsock: %u\n" "\tid: %u\n" "\thost: %u\n" "\tport: %u\n" "\tbitfield: 16 bits\n" "\tr_timeout: %u\n" "\tr_tv: %u\n" "\tr_to: %u\n" "\tw_timeout: %u\n" "\tw_tv: %u\n" "\tw_to: %u\n" "\tc_timeout: %u\n" "\tc_tv: %u\n" "\tc_to: %u\n" "\tr_buf: %u\n" "\tw_buf: %u\n" "\tw_len: %u\n" "\tn_read: %u\n" "\tn_written: %u\n" "\tn_in: %u\n" "\tn_out: %u"# ifdef NCBI_OS_UNIX "\n\tfile: %u"# endif /*NCBI_OS_UNIX*/ , (unsigned int) sizeof(SOCK_struct), (unsigned int) offsetof(SOCK_struct, sock), (unsigned int) offsetof(SOCK_struct, id), (unsigned int) offsetof(SOCK_struct, host), (unsigned int) offsetof(SOCK_struct, port), (unsigned int) offsetof(SOCK_struct, r_timeout), (unsigned int) offsetof(SOCK_struct, r_tv), (unsigned int) offsetof(SOCK_struct, r_to), (unsigned int) offsetof(SOCK_struct, w_timeout), (unsigned int) offsetof(SOCK_struct, w_tv), (unsigned int) offsetof(SOCK_struct, w_to), (unsigned int) offsetof(SOCK_struct, c_timeout), (unsigned int) offsetof(SOCK_struct, c_tv), (unsigned int) offsetof(SOCK_struct, c_to), (unsigned int) offsetof(SOCK_struct, r_buf), (unsigned int) offsetof(SOCK_struct, w_buf), (unsigned int) offsetof(SOCK_struct, w_len), (unsigned int) offsetof(SOCK_struct, n_read), (unsigned int) offsetof(SOCK_struct, n_written), (unsigned int) offsetof(SOCK_struct, n_in), (unsigned int) offsetof(SOCK_struct, n_out)# ifdef NCBI_OS_UNIX , (unsigned int) offsetoff(SOCK_struct, file)# endif /*NCBI_OS_UNIX*/ ));}#endifextern EIO_Status SOCK_InitializeAPI(void){ static int/*bool*/ s_AtExitSet = 0; CORE_LOCK_WRITE; if ( s_Initialized ) { CORE_UNLOCK; return eIO_Success; }#if 0/*defined(_DEBUG) && !defined(NDEBUG)*/ s_ShowDataLayout();#endif#if defined(NCBI_OS_MSWIN) {{ WSADATA wsadata; int x_errno = WSAStartup(MAKEWORD(1,1), &wsadata); if (x_errno != 0) { CORE_UNLOCK; CORE_LOG_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), "[SOCK::InitializeAPI] Failed WSAStartup()"); return eIO_Unknown; } }}#elif defined(NCBI_OS_UNIX) if ( !s_AllowSigPipe ) { struct sigaction sa; if (sigaction(SIGPIPE, 0, &sa) < 0 || sa.sa_handler == SIG_DFL) { memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, 0); } }#endif /*platform-specific init*/ s_Initialized = 1/*true*/; if ( !s_AtExitSet ) { atexit((void (*)(void)) SOCK_ShutdownAPI); s_AtExitSet = 1; } CORE_UNLOCK; return eIO_Success;}extern EIO_Status SOCK_ShutdownAPI(void){ CORE_LOCK_WRITE; if ( !s_Initialized ) { CORE_UNLOCK; return eIO_Success; } s_Initialized = 0/*false*/;#if defined(NCBI_OS_MSWIN) {{ int x_errno = WSACleanup() ? SOCK_ERRNO : 0; CORE_UNLOCK; if ( x_errno ) { CORE_LOG_ERRNO_EX(eLOG_Warning, x_errno, SOCK_STRERROR(x_errno), "[SOCK::ShutdownAPI] Failed WSACleanup()"); return eIO_Unknown; } }}#else CORE_UNLOCK;#endif /*NCBI_OS_MSWIN*/ return eIO_Success;}/****************************************************************************** * LSOCK & SOCK AUXILIARIES *//* STimeout <--> struct timeval conversions */static STimeout *s_tv2to(const struct timeval* tv, STimeout* to){ if ( !tv ) return 0; to->sec = (unsigned int) tv->tv_sec; to->usec = (unsigned int) tv->tv_usec; return to;}static struct timeval* s_to2tv(const STimeout* to, struct timeval* tv){ if ( !to ) return 0; tv->tv_sec = to->usec / 1000000 + to->sec; tv->tv_usec = to->usec % 1000000; return tv;}/* Switch the specified socket I/O between blocking and non-blocking mode */static int/*bool*/ s_SetNonblock(TSOCK_Handle sock, int/*bool*/ nonblock){#if defined(NCBI_OS_MSWIN) unsigned long argp = nonblock ? 1 : 0; return ioctlsocket(sock, FIONBIO, &argp) == 0;#elif defined(NCBI_OS_UNIX) || defined(NCBI_OS_MAC) return fcntl(sock, F_SETFL, nonblock ? fcntl(sock, F_GETFL, 0) | O_NONBLOCK : fcntl(sock, F_GETFL, 0) & (int) ~O_NONBLOCK) != -1;#else# error "Unsupported platform"#endif /*platform-specific ioctl*/}static int/*bool*/ s_SetReuseAddress(TSOCK_Handle x_sock, int/*bool*/ on_off){#if defined(NCBI_OS_UNIX) || defined(NCBI_OS_MSWIN) /* setsockopt() is not implemented for MAC (in MIT socket emulation lib) */# ifdef NCBI_OS_MSWIN BOOL reuse_addr = on_off ? TRUE : FALSE;# else int reuse_addr = on_off ? 1 : 0;# endif /*NCBI_OS_MSWIN*/ return !setsockopt(x_sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse_addr, sizeof(reuse_addr));#else return 1;#endif /*NCBI_OS_UNIX || NCBI_OS_MSWIN*/}static EIO_Status s_Status(SOCK sock, EIO_Event direction){ assert(sock && sock->sock != SOCK_INVALID); switch ( direction ) { case eIO_Read: return sock->type != eSOCK_Datagram && sock->eof ? eIO_Closed : sock->r_status; case eIO_Write: return sock->w_status; default: /*should never get here*/ assert(0); break; } return eIO_InvalidArg;}/* compare 2 normialized timeval timeouts: "whether v1 is less than v2" */static int/*bool*/ s_Less(const struct timeval* v1, const struct timeval* v2){ if (!v1) return 0; if (!v2) return !!v1; if (v1->tv_sec > v2->tv_sec) return 0; if (v1->tv_sec < v2->tv_sec) return 1; return v1->tv_usec < v2->tv_usec;}/* Select on the socket I/O (multiple sockets). * "Event" field is not considered for entries, whose "sock" field is 0, * "revent" for those entries is always "eIO_Open". For all other entries * only those sockets will be considered, whose "revent" field does not * contain "eIO_Open" value. If at least one non-"eIO_Open" status found * in "revent", the call terminates with "eIO_Success" status (after, * however checking all other entries for validity). No additional checks * are made for the pre-ready entries. * * This function does not check datagram sockets with the select() system call * at all if the number of requested sockets is more than 1 (cf. SOCK_Poll()). * * If "eIO_Write" event is inquired on a stream socket, and the socket is * marked for upread, then returned "revent" may also include "eIO_Read" to * indicate that some input is available on that socket. * If "eIO_Read" event is inquired on an array (n != 1) including stream * socket(s) and some sockets still have connection/data pending, those * "revent" field may then include "eIO_Write" to indicate that * connection can be completed/data sent. * * Return eIO_Success when at least one socket is found either ready * (including "eIO_Read" event on "eIO_Write" for upreadable sockets * and "eIO_Write" on "eIO_Read" for sockets in pending state) * or failing ("revent" contains "eIO_Close"). * Return "eIO_Timeout", if timeout expired before any socket became available. * Any other return code indicates some failure. */static EIO_Status s_Select(size_t n, SSOCK_Poll polls[], const struct timeval* tv){ int/*bool*/ write_only = 1; int/*bool*/ read_only = 1; int/*bool*/ ready = 0; int/*bool*/ bad = 0; fd_set r_fds, w_fds, e_fds; int n_fds; struct timeval x_tv; size_t i; if ( tv ) x_tv = *tv; for (;;) { /* (optionally) auto-resume if interrupted by a signal */ struct timeval xx_tv; n_fds = 0; FD_ZERO(&r_fds); FD_ZERO(&w_fds); FD_ZERO(&e_fds); for (i = 0; i < n; i++) { if ( !polls[i].sock ) { polls[i].revent = eIO_Open; continue; } if ( polls[i].revent ) { ready = 1; continue; } if (polls[i].event && (EIO_Event)(polls[i].event | eIO_ReadWrite) == eIO_ReadWrite) { TSOCK_Handle fd = polls[i].sock->sock; if (fd != SOCK_INVALID) { int/*bool*/ ls = IS_LISTENING(polls[i].sock); if (!ls && n != 1 && polls[i].sock->type == eSOCK_Datagram) continue; if (ready || bad) continue; switch (polls[i].event) { case eIO_Write: case eIO_ReadWrite: if (!ls) { if (polls[i].sock->type == eSOCK_Datagram || polls[i].sock->w_status != eIO_Closed) { read_only = 0; FD_SET(fd, &w_fds); if (polls[i].sock->type == eSOCK_Datagram || polls[i].sock->pending) break; if (polls[i].event == eIO_Write && (polls[i].sock->r_on_w == eOff || (polls[i].sock->r_on_w == eDefault && s_ReadOnWrite != eOn))) break; } else if (polls[i].event == eIO_Write) break; } else if (polls[i].event == eIO_Write) break; /*FALLTHRU*/ case eIO_Read:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -