📄 sockets.c
字号:
// ----------------------------------------------------------------------------// Copyright 2006-2007, Martin D. Flynn// All rights reserved// ----------------------------------------------------------------------------//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// // http://www.apache.org/licenses/LICENSE-2.0// // Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//// ----------------------------------------------------------------------------// Description:// Example UDP/TCP socket utilities for data transport use.// ---// Change History:// 2006/01/04 Martin D. Flynn// -Initial release// 2006/01/12 Martin D. Flynn// -Fixed read timeout problem on Linux.// 2007/01/28 Martin D. Flynn// -WindowsCE port// -Enabled non-blocking mode on tcp sockets (TARGET_WINCE only)// -Added 'send' select check (see 'socketIsSendReady')// -Fixed premature timeout problem in socketReadTCP// 2007/02/05 Martin D. Flynn// -Fixed size of 'heBuf' in call to 'gethostbyname_r'. Was 256, which was// too small for uClibc. (Thanks to Tomasz Rostanski for catching this!).// ----------------------------------------------------------------------------#include "stdafx.h" // TARGET_WINCE#define SKIP_TRANSPORT_MEDIA_CHECK // only if TRANSPORT_MEDIA not used in this file #include "custom/defaults.h"#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <ctype.h>#include <time.h>#include <string.h>#include <limits.h>#if defined(TARGET_WINCE)# include <winsock2.h>typedef int socklen_t;#else# include <unistd.h># include <errno.h># include <termios.h># include <netdb.h># include <netinet/in.h># include <sys/types.h># include <sys/ioctl.h># include <sys/stat.h># include <sys/socket.h># include <sys/select.h>#endif#include "tools/stdtypes.h"#include "tools/strtools.h"#include "tools/utctools.h"#include "tools/sockets.h"#include "custom/log.h"// ----------------------------------------------------------------------------#define ALWAYS_RESOLVE_HOST utFalse// ----------------------------------------------------------------------------// Overhead:// TCP => 20(IP) + 20{TCP) = 40// UDP => 20(IP) + 8(UDP) = 28// Minimum IP datagram size = 576 bytes (include the above overhead)// Maximum IP datagram size = 65516//// Protocol overhead: http://sd.wareonearth.com/~phil/net/overhead/// ----------------------------------------------------------------------------#if defined(TARGET_CYGWIN)// This works on Cygwin# define IOCTIL_REQUEST_BYTES_AVAIL TIOCINQ // (int*) Cygwin# define CLOSE_SOCKET(F) close(F)# define IOCTL_SOCKET(F,R,A) ioctl(F,R,A)# define IOCTL_ARG_TYPE int# define INVALID_SOCKET (-1)# define SOCKET_ERROR (-1)#elif defined(TARGET_WINCE)// Windows CE# define IOCTIL_REQUEST_BYTES_AVAIL FIONREAD // (u_long*) Windows CE# define IOCTIL_REQUEST_NON_BLOCKING FIONBIO // (u_long*) Windows CE# define CLOSE_SOCKET(F) closesocket(F)# define IOCTL_SOCKET(F,R,A) ioctlsocket(F,R,A) // [A=(ulong*)]# define IOCTL_ARG_TYPE u_long//# define INVALID_SOCKET (-1) <- already defined//# define SOCKET_ERROR (-1) <- already defined#else// This works fine on Linux and GumStix# include <asm/ioctls.h># define IOCTIL_REQUEST_BYTES_AVAIL FIONREAD // (int*)//# define IOCTIL_REQUEST_NON_BLOCKING FIONBIO // (int*)# define CLOSE_SOCKET(F) close(F)# define IOCTL_SOCKET(F,R,A) ioctl(F,R,A)# define IOCTL_ARG_TYPE int# define INVALID_SOCKET (-1)# define SOCKET_ERROR (-1)#endif// ----------------------------------------------------------------------------// Windows CE 'errno' redefinitions#if defined(TARGET_WINCE)# define RESET_ERRNO WSASetLastError(0) // docs claim this is required# define ERRNO WSAGetLastError() // 'errno' undefined on WinCE# define ECONNRESET WSAECONNRESET# define EWOULDBLOCK WSAEWOULDBLOCK# define EAGAIN WSAEWOULDBLOCK#else# define ERRNO errno# define RESET_ERRNO /*NO-OP*/ // errno = 0#endif// ----------------------------------------------------------------------------/* client/server: clear socket structure */void socketInitStruct(Socket_t *sock, const char *host, int port, int type){ if (sock) { memset(sock, 0, sizeof(Socket_t));#if defined(ENABLE_SERVER_SOCKET) sock->serverfd = INVALID_SOCKET;#endif sock->sockfd = INVALID_SOCKET; sock->type = type; // SOCK_DGRAM/SOCK_STREAM if (host) { int len = strLength(host, sizeof(sock->host) - 1); strncpy(sock->host, host, len); sock->host[len] = 0; } sock->port = port; }}// ----------------------------------------------------------------------------static int socketResolveHost(const char *host, UInt8 *addr, utBool alwaysResolve){ // Note: 'addr' is assumed to be 6 bytes in length /* invalid addr */ if (!addr) { return COMERR_SOCKET_HOST; } /* check for already resolved */ if (!alwaysResolve) { // don't resolve if address has already been resolved // [NOTE: may have no effect if the socket structure is initialized to nulls on each open] int i; for (i = 0; i < 6; i++) { if (addr[i]) { return COMERR_SUCCESS; } } } /* invalid host name */ if (!host || !*host) { return COMERR_SOCKET_HOST; } /* get host entry */ struct hostent *he = (struct hostent*)0;#if defined(TARGET_LINUX) // thread safe struct hostent rhe; char heBuf[512]; // was 256 - (too small for uClibc) // Exact size would be '460': // sizeof(struct in_addr) + // sizeof(struct in_addr*)*2 + // sizeof(char*)*(ALIAS_DIM) + // (ALIAS_DIM is (2 + 5/*MAX_ALIASES*/ + 1)) // 384/*namebuffer*/ + // 32/*margin*/; int heErrno = 0; gethostbyname_r(host, &rhe, heBuf, sizeof(heBuf), &he, &heErrno);#elif defined(TARGET_WINCE) // not thread safe WSASetLastError(0); he = gethostbyname(host); // this may fail if 'host' contains an IP address int heErrno = WSAGetLastError(); // WSAHOST_NOT_FOUND [11001] if (!he && isdigit(*host)) { // <-- simple test for IP address logWARNING(LOGSRC,"Attempting to parse IP address: %s", host); u_long ipAddr = inet_addr(host); if (ipAddr != INADDR_NONE) { he = gethostbyaddr((char*)&ipAddr, 4, AF_INET); if (he) { logINFO(LOGSRC,"Successful at obtaining hostent from IP address!"); heErrno = 0; } else { heErrno = WSAGetLastError(); } } else { logWARNING(LOGSRC,"Unable to parse IP address"); } }#else // not thread safe he = gethostbyname(host); int heErrno = h_errno;#endif /* extract address */ if (he) { int len = (he->h_length < 6)? he->h_length : 6; memcpy(addr, he->h_addr_list[0], len); return COMERR_SUCCESS; } else { logWARNING(LOGSRC,"Unable to resolve host [%d]: %s", heErrno, host); return COMERR_SOCKET_HOST; } }// ----------------------------------------------------------------------------/* enable non-blocking mode */utBool socketEnableNonBlockingClient(Socket_t *sock, utBool enable){#if defined(IOCTIL_REQUEST_NON_BLOCKING) if (sock && (sock->sockfd != INVALID_SOCKET)) { IOCTL_ARG_TYPE enableNonBlocking = enable? 1 : 0; RESET_ERRNO; // WSASetLastError(0); int status = IOCTL_SOCKET(sock->sockfd, IOCTIL_REQUEST_NON_BLOCKING, &enableNonBlocking); if (status >= 0) { sock->nonBlock = enable; //logINFO(LOGSRC,"Socket set to non-blocking mode"); return utTrue; } else { int err = ERRNO; // WSAGetLastError(); logERROR(LOGSRC,"Unable to enable non-blocking mode [errno=%d]", err); return utFalse; } }#endif return utFalse;}/* return true if non-blocking mode has been set for this client socket */utBool socketIsNonBlockingClient(Socket_t *sock){ if (sock && (sock->sockfd != INVALID_SOCKET)) { return sock->nonBlock; } else { return utFalse; }}// ----------------------------------------------------------------------------/* client: open a UDP socket for writing */int socketOpenUDPClient(Socket_t *sock, const char *host, int port){ /* create socket */ socketInitStruct(sock, host, port, SOCK_DGRAM); sock->sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sock->sockfd < 0) { // unlikely to occur return COMERR_SOCKET_OPEN; } /* resolve hostname */ int err = socketResolveHost(host, sock->hostAddr, ALWAYS_RESOLVE_HOST); if (err != COMERR_SUCCESS) { //fprintf(stderr, "Unable to resolve host: %s\n", host); CLOSE_SOCKET(sock->sockfd); sock->sockfd = INVALID_SOCKET; return COMERR_SOCKET_HOST; } return COMERR_SUCCESS;}/* server: open a UDP socket for reading */#if defined(ENABLE_SERVER_SOCKET)int socketOpenUDPServer(Socket_t *sock, int port){ /* create socket */ socketInitStruct(sock, (char*)0, port, SOCK_DGRAM); sock->sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sock->sockfd < 0) { // unlikely to occur return COMERR_SOCKET_OPEN; } /* bind to local port (RX only) */ struct sockaddr_in my_addr; // connector's address information my_addr.sin_family = AF_INET; // host byte order my_addr.sin_port = htons(sock->port); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sock->sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1) { // Unable to bind server to specified port //fprintf(stderr, "Unable to bind to port %d\n", port); CLOSE_SOCKET(sock->sockfd); sock->sockfd = INVALID_SOCKET; return COMERR_SOCKET_BIND; } return COMERR_SUCCESS;}#endif// ----------------------------------------------------------------------------/* client: open a TCP client socket */int socketOpenTCPClient(Socket_t *sock, const char *host, int port){ /* init socket */ socketInitStruct(sock, host, port, SOCK_STREAM); sock->sockfd = socket(AF_INET, SOCK_STREAM, 0); // SOCK_DGRAM if (sock->sockfd == INVALID_SOCKET) { // unlikely to occur return COMERR_SOCKET_OPEN; } /* resolve hostname */ int err = socketResolveHost(host, sock->hostAddr, ALWAYS_RESOLVE_HOST); if (err != COMERR_SUCCESS) { //fprintf(stderr, "Unable to resolve host: %s\n", host); CLOSE_SOCKET(sock->sockfd); sock->sockfd = INVALID_SOCKET; return COMERR_SOCKET_HOST; } /* connect */ struct sockaddr_in their_addr; // connector's address information their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(port); // short, network byte order their_addr.sin_addr = *((struct in_addr *)sock->hostAddr); memset(&(their_addr.sin_zero), 0, sizeof(their_addr.sin_zero)); // (8) zero the rest of the struct RESET_ERRNO; // WSASetLastError(0); if (connect(sock->sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) < 0) { // Unable to connect to specified host:port int err = ERRNO; logERROR(LOGSRC,"Unable to establish socket connect [errno=%d]", err); CLOSE_SOCKET(sock->sockfd); sock->sockfd = INVALID_SOCKET; return COMERR_SOCKET_CONNECT; } /* non-blocking mode */#if defined(TARGET_WINCE) // set non-blocking AFTER connection socketEnableNonBlockingClient(sock, utTrue);#endif /* send timeout (SO_SNDTIMEO) */ //(This is not supported on all platforms) //struct timeval timeo; //utcGetTimestampDelta(&timeo, 10000L); //if (setsockopt(sock->sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeo, sizeof(timeo)) == -1) { // // Unable to set client socket options // CLOSE_SOCKET(sock->sockfd); // sock->sockfd = INVALID_SOCKET; // return COMERR_SOCKET_OPTION; //} /* success */ return COMERR_SUCCESS;}/* server: is client socket open */utBool socketIsOpenClient(Socket_t *sock){ return (sock && (sock->sockfd != INVALID_SOCKET))? utTrue : utFalse;}// ----------------------------------------------------------------------------#if defined(ENABLE_SERVER_SOCKET)/* server: open a TCP server socket */int socketOpenTCPServer(Socket_t *sock, int port){ /* init */ socketInitStruct(sock, 0, port, SOCK_STREAM); /* socket */ sock->serverfd = socket(AF_INET, SOCK_STREAM, 0); // SOCK_DGRAM if (sock->serverfd == INVALID_SOCKET) { return COMERR_SOCKET_OPEN; } /* reuse address */ int yes = 1; if (setsockopt(sock->serverfd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int)) == -1) { // Unable to set server socket options CLOSE_SOCKET(sock->serverfd); sock->serverfd = INVALID_SOCKET; return COMERR_SOCKET_OPTION; } /* send timeout? (SO_SNDTIMEO) */ /* linger on close */ struct linger so_linger; so_linger.l_onoff = 1; // linger on so_linger.l_linger = 2; // 2 seconds if (setsockopt(sock->serverfd, SOL_SOCKET, SO_LINGER, (char*)&so_linger, sizeof(struct linger)) == -1) { // Unable to set server socket options CLOSE_SOCKET(sock->serverfd); sock->serverfd = INVALID_SOCKET; return COMERR_SOCKET_OPTION; } /* bind to port */ struct sockaddr_in my_addr; // my address information my_addr.sin_family = AF_INET; // host byte order my_addr.sin_port = htons(sock->port); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP memset(&my_addr.sin_zero, 0, 8); // zero the rest of the struct if (bind(sock->serverfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { // Unable to bind server to specified port CLOSE_SOCKET(sock->serverfd); sock->serverfd = INVALID_SOCKET; return COMERR_SOCKET_BIND;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -