/* Copyright 2009 Virginia Polytechnic Institute and State University 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. */ /* TODO DESCRIPTION OF FILE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "vtcross/common.h" #include "vtcross/containers.h" #include "vtcross/debug.h" #include "vtcross/error.h" #include "vtcross/socketcomm.h" // TODO can someone write a description of how this function is operating? I'm // not sure I understand why it is making two separate blocking calls to recv // // TODO also, it appears that this function can, at maximum, receive 256 bytes // without causing a buffer overflow. can someone confirm/deny? int32_t ReadMessage(int32_t socketFD, char* msgBuffer) { // Peek at the buffer to get real message length. // Messages are termination with a "\0" to denote EOM. ssize_t msgLength = recv(socketFD, msgBuffer, 256, MSG_PEEK); if(msgLength <= 0) { //ERROR(1, "Remote component closed connection. 1\n"); //LOG("Client closed connection.\n"); return -1; } size_t i; for(i = 0; i < 256; i++) { if(strcmp(&msgBuffer[i], "\0") == 0) break; } // Read the message into msgBuffer msgLength = recv(socketFD, msgBuffer, i + 1, 0); if(msgLength <= 0) { //ERROR(1, "Remote component closed connection. 1\n"); //LOG("Client closed connection.\n"); return -1; } return 1; } int32_t ClientSocket(const char* serverName, const char* serverPort) { int32_t socketFD; int32_t portNumber; struct sockaddr_in serv_addr; struct hostent *server; server = gethostbyname(serverName); if(server == NULL) ERROR(1, "SocketComm::ClientSocket - No server found by that hostname.\n"); portNumber = atoi(serverPort); socketFD = socket(AF_INET, SOCK_STREAM, 0); if(socketFD < 0) ERROR(1, "SocketComm::ClientSocket - Error opening socket\n"); memset((void *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(portNumber); memcpy((char *) &serv_addr.sin_addr.s_addr, (char *) server->h_addr, \ server->h_length); if(connect(socketFD, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) ERROR(1, "SocketComm::ClientSocket - Error connecting to remote socket.\n"); return socketFD; } // TODO this function is here to handle calls to send const char* messages. Note // that the std::string.c_str() function auto-appends a null character at the // end of the cstring, so the strcat function call in the previous function // isn't necessary here... I think... although I still don't really understand // what exactly that call is for. int32_t SendMessage(int32_t socketFD, const char* message) { ssize_t numSentBytes = send(socketFD, message, (strlen(message) + 1), 0); if(numSentBytes < 0) { ERROR(1, "Error sending to server %i (%i): %s\n",socketFD, numSentBytes, message); } else if(numSentBytes == 0) { LOG("socket_comm::SendMessage - Server closed the socket.\n"); } return numSentBytes; } // TODO This function is currently returning 1... always... is this necessary? // If we want a fail/success return type, then why aren't we ever returning a // failure? int32_t GetParameter(int32_t socketFD, struct Parameter pList[], \ struct Radio_Info *radio_info) { char buffer[256]; memset(buffer, 0, 256); ReadMessage(socketFD, buffer); radio_info->numParameters = atoi(buffer); LOG("socket_comm::GetParameter - Number of parameters: %d\n", \ radio_info->numParameters); for(size_t i = 0; i < radio_info->numParameters; i++) { memset(buffer, 0, 256); ReadMessage(socketFD, buffer); LOG("socket_comm::GetParameter - Name: %s\n", buffer); pList[i].name = std::string(buffer); memset(buffer, 0, 256); ReadMessage(socketFD, buffer); LOG("socket_comm::GetParameter - Units: %s\n", buffer); pList[i].units = std::string(buffer); memset(buffer, 0, 256); ReadMessage(socketFD, buffer); LOG("socket_comm::GetParameter - Min: %s\n", buffer); pList[i].min = atof(buffer); memset(buffer, 0, 256); ReadMessage(socketFD, buffer); LOG("socket_comm::GetParameter - Max: %s\n", buffer); pList[i].max = atof(buffer); memset(buffer, 0, 256); ReadMessage(socketFD, buffer); LOG("socket_comm::GetParameter - Step: %s\n", buffer); pList[i].step = atof(buffer); memset(buffer, 0, 256); ReadMessage(socketFD, buffer); LOG("socket_comm::GetParameter - Value: %s\n", buffer); pList[i].value = atof(buffer); } return 1; } // TODO if we are just returing fail/success here, then why not return a bool // instead of an entire 32 bit integer? Seems wasteful. int32_t GetRequest(int32_t socketFD, struct Parameter pList[], struct Radio_Info *radio_info) { char buffer[256]; memset(buffer, 0, 256); ReadMessage(socketFD, buffer); if(strcmp(buffer, "val") != 0) { LOG("socket_comm::GetRequest - Unexpected control data received.\n\n"); return 0; } LOG("socket_comm::GetRequest - Getting parameters.\n\n"); GetParameter(socketFD, pList, radio_info); return 1; } int32_t AcceptTCPConnection(int32_t serverSock) { struct sockaddr_in echoClientAddr; uint32_t clientLength = sizeof(echoClientAddr); int32_t clientSocket = accept(serverSock, NULL, NULL); if(clientSocket < 0) { //WARNING("ALERT: Could not establish connection with client socket.\n"); return clientSocket; } //LOG("Handling client %s\n", inet_ntoa(echoClientAddr.sin_addr)); return clientSocket; } int32_t CreateTCPServerSocket(uint16_t port) { struct sockaddr_in echoServerAddr; int32_t localSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (localSocket < 0) ERROR(1, "socket() failed\n"); /* Construct the local address structure */ memset(&echoServerAddr, 0, sizeof(echoServerAddr)); echoServerAddr.sin_family = AF_INET; echoServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); echoServerAddr.sin_port = htons(port); /* Bind to the local address */ if(bind(localSocket, (struct sockaddr *) &echoServerAddr, \ sizeof(echoServerAddr)) < 0) ERROR(1, "bind() failed\n"); /* Mark the socket so it will listen for incoming connections */ if(listen(localSocket, 5) < 0) ERROR(1, "listen() failed\n"); return localSocket; } int32_t InitializeTCPServerPort(int32_t servSock) { int32_t rc, on = 1; rc = setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)); if(rc < 0) { shutdown(servSock, 2); close(servSock); ERROR(1,"setsockopt() failed\n"); } rc = ioctl(servSock, FIONBIO, (char*)&on); if(rc < 0) { shutdown(servSock, 2); close(servSock); ERROR(1,"ioctl() failed\n"); } return 1; }