1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <cstring>
8 : #include <string>
9 : #include <vector>
10 :
11 : #include "native_client/src/shared/platform/nacl_log.h"
12 : #include "native_client/src/shared/platform/nacl_time.h"
13 : #include "native_client/src/shared/srpc/nacl_srpc.h"
14 :
15 : #include "native_client/src/trusted/sel_universal/parsing.h"
16 : #include "native_client/src/trusted/sel_universal/pnacl_emu_handler.h"
17 : #include "native_client/src/trusted/sel_universal/rpc_universal.h"
18 :
19 : using std::string;
20 : using std::vector;
21 :
22 : namespace {
23 :
24 : int
25 0 : SendDataChunk(NaClCommandLoop* ncl, nacl_abi_size_t size, const char *data) {
26 0 : const string signature = string("StreamChunk:C:");
27 : NaClSrpcArg in[1];
28 : NaClSrpcArg* inv[2];
29 0 : BuildArgVec(inv, in, 1);
30 0 : in[0].tag = NACL_SRPC_ARG_TYPE_CHAR_ARRAY;
31 0 : in[0].arrays.carr = static_cast<char*>(malloc(size));
32 0 : if (0 == in[0].arrays.carr) {
33 0 : NaClLog(LOG_ERROR, "allocation failed\n");
34 0 : FreeArrayArgs(inv);
35 0 : return -1;
36 : }
37 0 : in[0].u.count = size;
38 0 : memcpy(in[0].arrays.carr, data, size);
39 :
40 : NaClSrpcArg* outv[1];
41 0 : outv[0] = NULL;
42 0 : if (!ncl->InvokeNexeRpc(signature, inv, outv)) {
43 0 : NaClLog(LOG_ERROR, "StreamChunk failed\n");
44 0 : FreeArrayArgs(inv);
45 0 : return -1;
46 : }
47 0 : return 0;
48 : }
49 :
50 : // Stream the file to the client with a series of StreamChunk RPCs.
51 : // Rate-limit the sending to bits_per_sec to emulate a download
52 : bool PnaclStreamFile(NaClCommandLoop* ncl, FILE* input_file,
53 0 : int chunk_size, int bits_per_sec) {
54 0 : char* data = new char[chunk_size];
55 0 : NaClLog(LOG_INFO, "Streaming file at %d bps\n", bits_per_sec);
56 0 : uint64_t start_time = NaClGetTimeOfDayMicroseconds();
57 0 : size_t data_sent = 0;
58 0 : while (!feof(input_file) && !ferror(input_file)) {
59 0 : size_t data_read = fread(data, 1, chunk_size, input_file);
60 0 : uint64_t cur_elapsed_us = NaClGetTimeOfDayMicroseconds() - start_time;
61 : uint64_t target_elapsed_us = static_cast<uint64_t>(data_sent + data_read)
62 0 : * 8 * 1000000 / bits_per_sec;
63 0 : if (cur_elapsed_us < target_elapsed_us) {
64 0 : uint64_t sleep_us = target_elapsed_us - cur_elapsed_us;
65 : struct nacl_abi_timespec req;
66 : struct nacl_abi_timespec rem;
67 0 : req.tv_sec = sleep_us / 1000000;
68 0 : req.tv_nsec = sleep_us % 1000000 * 1000;
69 0 : int ret = NaClNanosleep(&req, &rem);
70 0 : if (ret == -1) {
71 0 : NaClLog(LOG_ERROR, "NaClNanosleep failed");
72 0 : return false;
73 : }
74 : }
75 0 : if (SendDataChunk(ncl, static_cast<nacl_abi_size_t>(data_read), data)) {
76 0 : return false;
77 : }
78 0 : data_sent += data_read;
79 : }
80 0 : delete data;
81 0 : return true;
82 : }
83 :
84 : } // namespace
85 :
86 : bool HandlerPnaclFileStream(NaClCommandLoop* ncl,
87 0 : const vector<string>& args) {
88 0 : if (args.size() != 4) {
89 0 : NaClLog(LOG_ERROR, "not enough args to file_stream\n");
90 0 : return false;
91 : }
92 :
93 0 : FILE* input_file = fopen(args[1].c_str(), "rb");
94 0 : if (NULL == input_file) {
95 0 : NaClLog(LOG_ERROR, "could not open input file %s\n", args[1].c_str());
96 0 : return false;
97 : }
98 : return PnaclStreamFile(ncl, input_file, strtol(args[2].c_str(), 0, 0),
99 0 : strtol(args[3].c_str(), 0, 0));
100 : }
|