From 1a8078af8764366a9e40913e1fd04824293cb88e Mon Sep 17 00:00:00 2001 From: Jason Watkins Date: Wed, 15 Apr 2015 14:59:47 -0700 Subject: [PATCH] Various changes to improve consistency and readability of low level UDP functions. - Tweaked variable names to be more concise. - Moved variable declarations from top of function to point of use. - Replaced memcpy with strncpy where appropriate. - Removed socket reuse options on *nix builds. - Improved error reporting. - Most failures when opening and closing sockets now cause the client to die. - sendUDP now ignores the length byte. --- C/src/xplaneConnect.c | 278 ++++++++++++++++++------------------------ 1 file changed, 122 insertions(+), 156 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index b85e73d..61aaab3 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -51,8 +51,9 @@ #ifdef _WIN32 /* WIN32 SYSTEM */ #include +// From http://www.c-plusplus.de/forum/109539-full void usleep(__int64 usec) -{ // From http://www.c-plusplus.de/forum/109539-full +{ HANDLE timer; LARGE_INTEGER ft; @@ -65,149 +66,159 @@ void usleep(__int64 usec) } #endif -short errorReport(char *functionName, char *errorMessage); +void printError(char *functionName, char *errorMessage); short sendRequest(XPCSocket recfd, char DREFArray[][100], short DREFSizes[], short listLength); -short errorReport(char *functionName, char *errorMessage) +void printError(char *functionName, char *errorMessage) { - printf("ERROR: %s-%s\n", functionName, errorMessage); - return -1; + printf("[%s] ERROR: %s\n", functionName, errorMessage); } -XPCSocket openUDP(unsigned short port_number, const char *xpIP, unsigned short xpPort) +/*****************************************************************************/ +/**** Low Level UDP functions ****/ +/*****************************************************************************/ +XPCSocket openUDP(unsigned short port, const char *xpIP, unsigned short xpPort) { - XPCSocket theSocket; - struct sockaddr_in server; - -#if (__APPLE__ || __linux) - struct timeval tv; - int optval = 1; -#endif + XPCSocket sock; // Setup Port - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = htons(port_number); + struct sockaddr_in recvaddr; + recvaddr.sin_family = AF_INET; + recvaddr.sin_addr.s_addr = INADDR_ANY; + recvaddr.sin_port = htons(port); // Set X-Plane Port and IP - if (strcasecmp(xpIP,"localhost") == 0) // IP - { - strncpy(theSocket.xpIP,"127.0.0.1",9); // Default - } - else - { - memcpy(theSocket.xpIP,xpIP,(size_t) fminl(strlen(xpIP),16)); - } - - if (xpPort <= 0) // Default Port - { - theSocket.xpPort = 49009; // Default - } - else - { - theSocket.xpPort = xpPort; - } + if (strcmp(xpIP, "localhost") == 0) + { + xpIP = "127.0.0.1"; + } + strncpy(sock.xpIP, xpIP, 16); + sock.xpPort = xpPort == 0 ? 49009 : xpPort; #ifdef _WIN32 WSADATA wsa; - if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) + if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { - perror("ERROR: openUDP- "); - return theSocket; - //ERROR IN Socket Message - } - - if ((theSocket.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) - { - perror("ERROR: openUDP- "); - return theSocket; - //ERROR IN Socket Message - } - - if (bind(theSocket.sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) - { - perror("ERROR: openUDP- "); - return theSocket; - //ERROR IN Socket Message - } -#elif (__APPLE__ || __linux) - // Create a SOCKET - if ((theSocket.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) - { - perror((char*) "ERROR: openUDP- "); - return theSocket; - } - - // Options - setsockopt(theSocket.sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); - setsockopt(theSocket.sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); - - //Bind - if ( bind(theSocket.sock, (struct sockaddr *) &server, sizeof(server)) == -1) - { - perror( (char*) "ERROR: openUDP- "); - return theSocket; + printError("OpenUDP", "WSAStartup failed"); + exit(EXIT_FAILURE); } #endif - //Set Timout - int usTimeOut = 500; + if ((sock.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + printError("OpenUDP", "Socket creation failed"); + exit(EXIT_FAILURE); + } + if (bind(sock.sock, (struct sockaddr*)&recvaddr, sizeof(recvaddr)) == -1) + { + printError("OpenUDP", "Socket bind failed"); + exit(EXIT_FAILURE); + } #ifdef _WIN32 - DWORD msTimeOutWin = 1; // Minimum socket timeout in Windows is 1ms - setsockopt(theSocket.sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&msTimeOutWin, sizeof(msTimeOutWin)); + DWORD timeout = 1; // Minimum socket timeout in Windows is 1ms #else - tv.tv_sec = 0; /* Sec Timeout */ - tv.tv_usec = usTimeOut; // Microsec Timeout - setsockopt(theSocket.sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(struct timeval)); + struct timeval timeout; + tv.tv_sec = 0; + tv.tv_usec = 500; #endif - - return theSocket; + if (setsockopt(sock.sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) + { + printError("OpenUDP", "Failed to set timeout"); + } + return sock; } void closeUDP(XPCSocket socketNumber) { #ifdef _WIN32 - closesocket(socketNumber.sock); -#elif (__APPLE__ || __linux) - close(socketNumber.sock); -#endif -} - -short sendUDP(XPCSocket recfd, char my_message[], short messageLength) -{ - struct sockaddr_in servaddr; - - my_message[4] = (char) messageLength; - - // Preconditions - if (messageLength <= 0)// Positive Message Length - { - return errorReport("sendUDP", "message length must be positive >0"); - } - - // Code - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(recfd.xpPort); - servaddr.sin_addr.s_addr = inet_addr(recfd.xpIP); - -#ifdef _WIN32 - const char on = 1; + int result = closesocket(socketNumber.sock); #else - int on=1; + int result = close(socketNumber.sock); #endif - - setsockopt(recfd.sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); - - if (sendto(recfd.sock, my_message, (int) messageLength, 0, (const struct sockaddr *) &servaddr, sizeof(servaddr))<0) + if (result < 0) { - perror("ERROR: sendUDP-"); + printError("closeUDP", "Failed to close socket"); exit(EXIT_FAILURE); } - - return 0; } +int sendUDP(XPCSocket sock, char buffer[], int len) +{ + // Preconditions + if (len <= 0) + { + printError("sendUDP", "Message length must be positive."); + return -1; + } + + // Set up destination address + struct sockaddr_in dst; + dst.sin_family = AF_INET; + dst.sin_port = htons(sock.xpPort); + inet_pton(AF_INET, sock.xpIP, &dst.sin_addr.s_addr); + + int result = sendto(sock.sock, buffer, len, 0, (const struct sockaddr*)&dst, sizeof(dst)); + if (result < 0) + { + printError("sendUDP", "Send operation failed."); + return -2; + } + if (result < len) + { + printError("sendUDP", "Unexpected number of bytes sent."); + } + return result; +} + +int readUDP(XPCSocket sock, char buffer[], int len, struct sockaddr* recvaddr) +{ + socklen_t recvaddrlen = sizeof(*recvaddr); +#ifdef _WIN32 + // Windows readUDP needs the select command- minimum timeout is 1ms. + // Without this playback becomes choppy + + // Definitions + FD_SET stReadFDS; + FD_SET stExceptFDS; + + // Setup for Select + FD_ZERO(&stReadFDS); + FD_SET(sock.sock, &stReadFDS); + FD_ZERO(&stExceptFDS); + FD_SET(sock.sock, &stExceptFDS); + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 250; + + // Select Command + int status = select(-1, &stReadFDS, (FD_SET*)0, &stExceptFDS, &tv); + if (status < 0) + { + printError("readUDP", "Select command error"); + return -1; + } + if (status == 0) + { + // No data + return 0; + } + status = recvfrom(sock.sock, buffer, len, 0, (struct sockaddr*)&recvaddr, &recvaddrlen); +#else + // For apple or linux-just read - will timeout in 0.5 ms + status = (int)recvfrom(sock.sock, dataRef, len, 0, recvaddr, &recvaddrlen); +#endif + if (status < 0) + { + printError("readUDP", "Error reading socket"); + } + return status; +} +/*****************************************************************************/ +/**** End Low Level UDP functions ****/ +/*****************************************************************************/ + short sendDATA(XPCSocket recfd, float dataRef[][9], unsigned short rows) { int i; @@ -454,51 +465,6 @@ short sendWYPT(XPCSocket sendfd, WYPT_OP op, float points[], int numPoints) //READ //---------------------------------------- -short readUDP(XPCSocket recfd, char *dataRef, struct sockaddr *recvaddr) -{ - socklen_t recvaddrlen = sizeof(*recvaddr); - int status = 0; - -#ifdef _WIN32 - // Windows readUDP needs the select command- minimum timeout is 1ms. - // Without this playback becomes choppy - - // Definitions - FD_SET stReadFDS; - FD_SET stExceptFDS; - struct timeval tv; - struct sockaddr_in testaddr; - int error = 0; - - // Setup for Select - FD_ZERO(&stReadFDS); - FD_SET(recfd.sock, &stReadFDS); - FD_ZERO(&stExceptFDS); - FD_SET(recfd.sock, &stExceptFDS); - tv.tv_sec = 0; /* Sec Timeout */ - tv.tv_usec = 250; // Microsec Timeout - - // Select Command - int tmp = select(-1, &stReadFDS, (FD_SET *)0, &stExceptFDS, &tv); - if (tmp <= 0) // No Data or error - { - return -1; - } - - // If no error: Read Data - recvaddrlen = sizeof(testaddr); - status = (int) recvfrom(recfd.sock,dataRef,5000,0,(SOCKADDR *) &testaddr,&recvaddrlen); - if (status == SOCKET_ERROR) - { - error = WSAGetLastError(); - } -#else - // For apple or linux-just read - will timeout in 0.5 ms - status = (int) recvfrom(recfd.sock,dataRef,5000,0,recvaddr,&recvaddrlen); -#endif - - return status; -} short readDATA(XPCSocket recfd, float dataRef[][9]) {