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