8eb348ff3a069bd9319de78e4dbf53e4e2731bfe
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / Sender.cpp
1 /**
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
21 Sender::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
51 Sender::~Sender() {
52         delete mDataSocket;
53         mDataSocket = NULL;
54         if (mDataFile) {
55                 fclose(mDataFile);
56         }
57 }
58
59 void 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
73 template<typename T>
74 inline T min(const T a, const T b) {
75         return (a < b ? a : b);
76 }
77
78 void 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                         unsigned char header[5];
97                         header[0] = type;
98                         header[1] = (length >> 0) & 0xff;
99                         header[2] = (length >> 8) & 0xff;
100                         header[3] = (length >> 16) & 0xff;
101                         header[4] = (length >> 24) & 0xff;
102                         mDataSocket->send((char*)&header, sizeof(header));
103                 }
104
105                 // 100Kbits/sec * alarmDuration sec / 8 bits/byte
106                 const int chunkSize = 100*1000 * alarmDuration / 8;
107                 int pos = 0;
108                 while (true) {
109                         mDataSocket->send((char*)data + pos, min(length - pos, chunkSize));
110                         pos += chunkSize;
111                         if (pos >= length) {
112                                 break;
113                         }
114
115                         // Reset the alarm
116                         alarm(alarmDuration);
117                         logg->logMessage("Resetting the alarm");
118                 }
119
120                 // Stop alarm
121                 alarm(0);
122         }
123
124         // Write data to disk as long as it is not meta data
125         if (mDataFile && type == RESPONSE_APC_DATA) {
126                 logg->logMessage("Writing data with length %d", length);
127                 // Send data to the data file
128                 if (fwrite(data, 1, length, mDataFile) != (unsigned int)length) {
129                         logg->logError(__FILE__, __LINE__, "Failed writing binary file %s", mDataFileName);
130                         handleException();
131                 }
132         }
133
134         pthread_mutex_unlock(&mSendMutex);
135 }