root/vtcross/trunk/src/lib/socketcomm/socketcomm.cpp

Revision 498, 7.6 KB (checked in by bhilburn, 15 years ago)

Numerous changes. A VTCROSS shell can now be remote relative to the radio host platform. The remote server/port is set through a new function in libvtcross, which has also been added as an option to the benchmark_dsa script. Other changes include bug fixes in the benchmark code and some SQL fixes.

Line 
1/*
2 Copyright 2009 Virginia Polytechnic Institute and State University 
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/* TODO DESCRIPTION OF FILE.
18 */
19
20
21#include <arpa/inet.h>
22#include <cstdlib>
23#include <cstring>
24#include <iostream>
25#include <fcntl.h>
26#include <sys/ioctl.h>
27#include <netdb.h>
28#include <netinet/in.h>
29#include <stdint.h>
30#include <string>
31#include <sys/types.h>
32#include <sys/socket.h>
33
34#include "vtcross/common.h"
35#include "vtcross/containers.h"
36#include "vtcross/debug.h"
37#include "vtcross/error.h"
38#include "vtcross/socketcomm.h"
39
40
41// TODO can someone write a description of how this function is operating? I'm
42// not sure I understand why it is making two separate blocking calls to recv
43//
44// TODO also, it appears that this function can, at maximum, receive 256 bytes
45// without causing a buffer overflow. can someone confirm/deny?
46int32_t
47ReadMessage(int32_t socketFD, char* msgBuffer)
48{
49
50    // Peek at the buffer to get real message length.
51    // Messages are termination with a "\0" to denote EOM.
52    ssize_t msgLength = recv(socketFD, msgBuffer, 256, MSG_PEEK);
53    if(msgLength <= 0) {
54        //ERROR(1, "Remote component closed connection. 1\n");
55        //LOG("Client closed connection.\n");
56        return -1;
57    }
58    size_t i;
59    for(i = 0; i < 256; i++) {
60        if(strcmp(&msgBuffer[i], "\0") == 0)
61            break;
62    }
63
64    // Read the message into msgBuffer
65    msgLength = recv(socketFD, msgBuffer, i + 1, 0);
66    if(msgLength <= 0) {
67        //ERROR(1, "Remote component closed connection. 1\n");
68        //LOG("Client closed connection.\n");
69        return -1;
70    }
71
72    return 1;
73}
74
75
76int32_t
77ClientSocket(const char* serverName, const char* serverPort)
78{
79    int32_t socketFD;
80    int32_t portNumber;
81
82    struct sockaddr_in serv_addr;
83    struct hostent *server;
84   
85    server = gethostbyname(serverName);
86    if(server == NULL)
87        ERROR(1, "SocketComm::ClientSocket - No server found by that hostname.\n");
88
89    portNumber = atoi(serverPort);
90
91    socketFD = socket(AF_INET, SOCK_STREAM, 0);
92    if(socketFD < 0)
93        ERROR(1, "SocketComm::ClientSocket - Error opening socket\n");
94
95    memset((void *) &serv_addr, 0, sizeof(serv_addr));
96    serv_addr.sin_family = AF_INET;
97    serv_addr.sin_port = htons(portNumber);
98    memcpy((char *) &serv_addr.sin_addr.s_addr, (char *) server->h_addr, \
99            server->h_length);
100
101    if(connect(socketFD, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
102        ERROR(1, "SocketComm::ClientSocket - Error connecting to remote socket.\n");
103
104    return socketFD;
105}
106
107   
108// TODO this function is here to handle calls to send const char* messages. Note
109// that the std::string.c_str() function auto-appends a null character at the
110// end of the cstring, so the strcat function call in the previous function
111// isn't necessary here... I think... although I still don't really understand
112// what exactly that call is for.
113int32_t
114SendMessage(int32_t socketFD, const char* message)
115{
116    ssize_t numSentBytes = send(socketFD, message, (strlen(message) + 1), 0);
117    if(numSentBytes < 0) {
118        ERROR(1, "Error sending to server %i (%i): %s\n",socketFD, numSentBytes, message);
119    }
120    else if(numSentBytes == 0) {
121        LOG("socket_comm::SendMessage - Server closed the socket.\n");
122    }
123   
124    return numSentBytes;
125}
126
127
128// TODO This function is currently returning 1... always... is this necessary?
129// If we want a fail/success return type, then why aren't we ever returning a
130// failure?
131int32_t
132GetParameter(int32_t socketFD, struct Parameter pList[], \
133        struct Radio_Info *radio_info)
134{
135    char buffer[256];
136    memset(buffer, 0, 256);
137
138    ReadMessage(socketFD, buffer);
139    radio_info->numParameters = atoi(buffer);
140    LOG("socket_comm::GetParameter - Number of parameters: %d\n", \
141            radio_info->numParameters);
142   
143    for(size_t i = 0; i < radio_info->numParameters; i++) {
144        memset(buffer, 0, 256);
145        ReadMessage(socketFD, buffer);
146        LOG("socket_comm::GetParameter - Name: %s\n", buffer);
147        pList[i].name = std::string(buffer);
148   
149        memset(buffer, 0, 256);
150        ReadMessage(socketFD, buffer);
151        LOG("socket_comm::GetParameter - Units: %s\n", buffer);
152        pList[i].units = std::string(buffer);
153
154        memset(buffer, 0, 256);
155        ReadMessage(socketFD, buffer);
156        LOG("socket_comm::GetParameter - Min: %s\n", buffer);
157        pList[i].min = atof(buffer);
158   
159        memset(buffer, 0, 256);
160        ReadMessage(socketFD, buffer);
161        LOG("socket_comm::GetParameter - Max: %s\n", buffer);
162        pList[i].max = atof(buffer);
163   
164        memset(buffer, 0, 256);
165        ReadMessage(socketFD, buffer);
166        LOG("socket_comm::GetParameter - Step: %s\n", buffer);
167        pList[i].step = atof(buffer);
168   
169        memset(buffer, 0, 256);
170        ReadMessage(socketFD, buffer);
171        LOG("socket_comm::GetParameter - Value: %s\n", buffer);
172        pList[i].value = atof(buffer);
173    }
174
175    return 1;
176}
177
178
179// TODO if we are just returing fail/success here, then why not return a bool
180// instead of an entire 32 bit integer?  Seems wasteful.
181int32_t
182GetRequest(int32_t socketFD, struct Parameter pList[], struct Radio_Info *radio_info)
183{
184    char buffer[256];
185    memset(buffer, 0, 256);
186   
187    ReadMessage(socketFD, buffer);
188
189    if(strcmp(buffer, "val") != 0) {
190        LOG("socket_comm::GetRequest - Unexpected control data received.\n\n");
191        return 0;
192    }
193
194    LOG("socket_comm::GetRequest - Getting parameters.\n\n");
195    GetParameter(socketFD, pList, radio_info);
196
197    return 1;
198}
199
200
201int32_t
202AcceptTCPConnection(int32_t serverSock)
203{
204    struct sockaddr_in echoClientAddr;
205
206    uint32_t clientLength = sizeof(echoClientAddr);
207
208    int32_t clientSocket = accept(serverSock, NULL, NULL);
209    if(clientSocket < 0) {
210        //WARNING("ALERT: Could not establish connection with client socket.\n");
211        return clientSocket;
212    }
213    //LOG("Handling client %s\n", inet_ntoa(echoClientAddr.sin_addr));
214
215    return clientSocket;
216}
217
218
219int32_t
220CreateTCPServerSocket(uint16_t port)
221{
222    struct sockaddr_in echoServerAddr;
223
224    int32_t localSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
225    if (localSocket < 0)
226        ERROR(1, "socket() failed\n");
227     
228    /* Construct the local address structure */
229    memset(&echoServerAddr, 0, sizeof(echoServerAddr));
230    echoServerAddr.sin_family = AF_INET;
231    echoServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
232    echoServerAddr.sin_port = htons(port);
233
234    /* Bind to the local address */
235    if(bind(localSocket, (struct sockaddr *) &echoServerAddr, \
236            sizeof(echoServerAddr)) < 0)
237        ERROR(1, "bind() failed\n");
238
239    /* Mark the socket so it will listen for incoming connections */
240    if(listen(localSocket, 5) < 0)
241        ERROR(1, "listen() failed\n");
242
243    return localSocket;
244}
245
246int32_t
247InitializeTCPServerPort(int32_t servSock)
248{
249    int32_t rc, on = 1;
250
251    rc = setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
252    if(rc < 0) {
253        shutdown(servSock, 2);
254        close(servSock);
255        ERROR(1,"setsockopt() failed\n");
256    }
257
258    rc = ioctl(servSock, FIONBIO, (char*)&on);
259    if(rc < 0) {
260        shutdown(servSock, 2);
261        close(servSock);
262        ERROR(1,"ioctl() failed\n");
263    }
264
265    return 1;
266}
Note: See TracBrowser for help on using the browser.