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

Revision 222, 7.6 KB (checked in by trnewman, 15 years ago)

Added libvtcross functionality. Made socketcomm a little more robust. Added libvtcross demo application to illustrate how to use the lib.

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