summaryrefslogtreecommitdiffstats
path: root/xbmc/filesystem/NFSFile.h
blob: 9e9dde92ec91bc82dde7437ba1401cdb4246823b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 *  Copyright (C) 2011-2018 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#pragma once

// FileNFS.h: interface for the CNFSFile class.

#include "IFile.h"
#include "URL.h"
#include "threads/CriticalSection.h"

#include <chrono>
#include <list>
#include <map>

struct nfs_stat_64;

class CNfsConnection : public CCriticalSection
{
public:
  struct keepAliveStruct
  {
    std::string exportPath;
    std::chrono::time_point<std::chrono::steady_clock> refreshTime;
  };
  typedef std::map<struct nfsfh  *, struct keepAliveStruct> tFileKeepAliveMap;

  struct contextTimeout
  {
    struct nfs_context *pContext;
    std::chrono::time_point<std::chrono::steady_clock> lastAccessedTime;
  };

  typedef std::map<std::string, struct contextTimeout> tOpenContextMap;

  CNfsConnection();
  ~CNfsConnection();
  bool Connect(const CURL &url, std::string &relativePath);
  struct nfs_context *GetNfsContext() {return m_pNfsContext;}
  uint64_t GetMaxReadChunkSize() {return m_readChunkSize;}
  uint64_t GetMaxWriteChunkSize() {return m_writeChunkSize;}
  std::list<std::string> GetExportList(const CURL &url);
  //this functions splits the url into the exportpath (feed to mount) and the rest of the path
  //relative to the mounted export
  bool splitUrlIntoExportAndPath(const CURL& url, std::string &exportPath, std::string &relativePath, std::list<std::string> &exportList);
  bool splitUrlIntoExportAndPath(const CURL& url, std::string &exportPath, std::string &relativePath);

  //special stat which uses its own context
  //needed for getting intervolume symlinks to work
  int stat(const CURL& url, nfs_stat_64* statbuff);

  void AddActiveConnection();
  void AddIdleConnection();
  void CheckIfIdle();
  void Deinit();
  //adds the filehandle to the keep alive list or resets
  //the timeout for this filehandle if already in list
  void resetKeepAlive(const std::string& _exportPath, struct nfsfh* _pFileHandle);
  //removes file handle from keep alive list
  void removeFromKeepAliveList(struct nfsfh  *_pFileHandle);

  const std::string& GetConnectedIp() const {return m_resolvedHostName;}
  const std::string& GetConnectedExport() const {return m_exportPath;}
  const std::string GetContextMapId() const {return m_hostName + m_exportPath;}

private:
  enum class ContextStatus
  {
    INVALID,
    NEW,
    CACHED
  };

  struct nfs_context *m_pNfsContext;//current nfs context
  std::string m_exportPath;//current connected export path
  std::string m_hostName;//current connected host
  std::string m_resolvedHostName;//current connected host - as ip
  uint64_t m_readChunkSize = 0;//current read chunksize of connected server
  uint64_t m_writeChunkSize = 0;//current write chunksize of connected server
  int m_OpenConnections = 0; //number of open connections
  std::chrono::time_point<std::chrono::steady_clock> m_IdleTimeout;
  tFileKeepAliveMap m_KeepAliveTimeouts;//mapping filehandles to its idle timeout
  tOpenContextMap m_openContextMap;//unique map for tracking all open contexts
  std::chrono::time_point<std::chrono::steady_clock>
      m_lastAccessedTime; //last access time for m_pNfsContext
  std::list<std::string> m_exportList;//list of exported paths of current connected servers
  CCriticalSection keepAliveLock;
  CCriticalSection openContextLock;

  void clearMembers();
  struct nfs_context *getContextFromMap(const std::string &exportname, bool forceCacheHit = false);

  // get context for given export and add to open contexts map - sets m_pNfsContext (may return an already mounted cached context)
  ContextStatus getContextForExport(const std::string& exportname);
  void destroyOpenContexts();
  void destroyContext(const std::string &exportName);
  void resolveHost(const CURL &url);//resolve hostname by dnslookup
  void keepAlive(const std::string& _exportPath, struct nfsfh* _pFileHandle);
  static void setOptions(struct nfs_context* context);
};

extern CNfsConnection gNfsConnection;

namespace XFILE
{
  class CNFSFile : public IFile
  {
  public:
    CNFSFile();
    ~CNFSFile() override;
    void Close() override;
    int64_t Seek(int64_t iFilePosition, int iWhence = SEEK_SET) override;
    ssize_t Read(void* lpBuf, size_t uiBufSize) override;
    bool Open(const CURL& url) override;
    bool Exists(const CURL& url) override;
    int Stat(const CURL& url, struct __stat64* buffer) override;
    int Stat(struct __stat64* buffer) override;
    int64_t GetLength() override;
    int64_t GetPosition() override;
    ssize_t Write(const void* lpBuf, size_t uiBufSize) override;
    int Truncate(int64_t iSize) override;

    //implement iocontrol for seek_possible for preventing the stat in File class for
    //getting this info ...
    int IoControl(EIoControl request, void* param) override
    {
      return request == IOCTRL_SEEK_POSSIBLE ? 1 : -1;
    }
    int GetChunkSize() override {return static_cast<int>(gNfsConnection.GetMaxReadChunkSize());}

    bool OpenForWrite(const CURL& url, bool bOverWrite = false) override;
    bool Delete(const CURL& url) override;
    bool Rename(const CURL& url, const CURL& urlnew) override;
  protected:
    CURL m_url;
    bool IsValidFile(const std::string& strFileName);
    int64_t m_fileSize = 0;
    struct nfsfh *m_pFileHandle;
    struct nfs_context *m_pNfsContext;//current nfs context
    std::string m_exportPath;
  };
}