blob: 159503f845fb6e0a7d1a2c81862e90b76361a737 [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <string.h>
10#include <sys/socket.h>
11#include <netinet/in.h>
12#include <sys/types.h>
13#include <arpa/inet.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include "Sender.h"
17#include "Logging.h"
18#include "OlySocket.h"
19#include "SessionData.h"
20
21Sender::Sender(OlySocket* socket) {
22 mDataFile = NULL;
23 mDataSocket = NULL;
24
25 // Set up the socket connection
26 if (socket) {
27 char streamline[64] = {0};
28 mDataSocket = socket;
29
30 // Receive magic sequence - can wait forever
31 // Streamline will send data prior to the magic sequence for legacy support, which should be ignored for v4+
32 while (strcmp("STREAMLINE", streamline) != 0) {
33 if (mDataSocket->receiveString(streamline, sizeof(streamline)) == -1) {
34 logg->logError(__FILE__, __LINE__, "Socket disconnected");
35 handleException();
36 }
37 }
38
39 // Send magic sequence - must be done first, after which error messages can be sent
40 char magic[32];
41 snprintf(magic, 32, "GATOR %i\n", PROTOCOL_VERSION);
42 mDataSocket->send(magic, strlen(magic));
43
44 gSessionData->mWaitingOnCommand = true;
45 logg->logMessage("Completed magic sequence");
46 }
47
48 pthread_mutex_init(&mSendMutex, NULL);
49}
50
51Sender::~Sender() {
52 delete mDataSocket;
53 mDataSocket = NULL;
54 if (mDataFile) {
55 fclose(mDataFile);
56 }
57}
58
59void Sender::createDataFile(char* apcDir) {
60 if (apcDir == NULL) {
61 return;
62 }
63
64 mDataFileName = (char*)malloc(strlen(apcDir) + 12);
65 sprintf(mDataFileName, "%s/0000000000", apcDir);
66 mDataFile = fopen(mDataFileName, "wb");
67 if (!mDataFile) {
68 logg->logError(__FILE__, __LINE__, "Failed to open binary file: %s", mDataFileName);
69 handleException();
70 }
71}
72
73template<typename T>
74inline T min(const T a, const T b) {
75 return (a < b ? a : b);
76}
77
78void Sender::writeData(const char* data, int length, int type) {
79 if (length < 0 || (data == NULL && length > 0)) {
80 return;
81 }
82
83 // Multiple threads call writeData()
84 pthread_mutex_lock(&mSendMutex);
85
86 // Send data over the socket connection
87 if (mDataSocket) {
88 // Start alarm
89 const int alarmDuration = 8;
90 alarm(alarmDuration);
91
92 // Send data over the socket, sending the type and size first
93 logg->logMessage("Sending data with length %d", length);
94 if (type != RESPONSE_APC_DATA) {
95 // type and length already added by the Collector for apc data
96 mDataSocket->send((char*)&type, 1);
97 mDataSocket->send((char*)&length, sizeof(length));
98 }
99
100 // 100Kbits/sec * alarmDuration sec / 8 bits/byte
101 const int chunkSize = 100*1000 * alarmDuration / 8;
102 int pos = 0;
103 while (true) {
104 mDataSocket->send((char*)data + pos, min(length - pos, chunkSize));
105 pos += chunkSize;
106 if (pos >= length) {
107 break;
108 }
109
110 // Reset the alarm
111 alarm(alarmDuration);
112 logg->logMessage("Resetting the alarm");
113 }
114
115 // Stop alarm
116 alarm(0);
117 }
118
119 // Write data to disk as long as it is not meta data
120 if (mDataFile && type == RESPONSE_APC_DATA) {
121 logg->logMessage("Writing data with length %d", length);
122 // Send data to the data file
123 if (fwrite(data, 1, length, mDataFile) != (unsigned int)length) {
124 logg->logError(__FILE__, __LINE__, "Failed writing binary file %s", mDataFileName);
125 handleException();
126 }
127 }
128
129 pthread_mutex_unlock(&mSendMutex);
130}