1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Network Provider for MPEG2 based networks
4  * FILE:            dll/directx/msdvbnp/networkprovider.cpp
5  * PURPOSE:         IBDA_NetworkProvider interface
6  *
7  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 #include "precomp.h"
10 
11 #define DEVICE_FILTER_MASK (0x80000000)
12 
13 class CNetworkProvider : public IBaseFilter,
14                          public IAMovieSetup,
15                          public IBDA_NetworkProvider
16 {
17 public:
18     typedef std::vector<IUnknown*>DeviceFilterStack;
19 
20     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
21 
22     STDMETHODIMP_(ULONG) AddRef()
23     {
24         InterlockedIncrement(&m_Ref);
25         return m_Ref;
26     }
27     STDMETHODIMP_(ULONG) Release()
28     {
29         InterlockedDecrement(&m_Ref);
30         if (!m_Ref)
31         {
32             delete this;
33             return 0;
34         }
35         return m_Ref;
36     }
37 
38     // IBaseFilter methods
39     HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
40     HRESULT STDMETHODCALLTYPE Stop( void);
41     HRESULT STDMETHODCALLTYPE Pause( void);
42     HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
43     HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *State);
44     HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
45     HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **pClock);
46     HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
47     HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
48     HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
49     HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
50     HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
51 
52     //IAMovieSetup methods
53     HRESULT STDMETHODCALLTYPE Register( void);
54     HRESULT STDMETHODCALLTYPE Unregister( void);
55 
56     //IBDA_NetworkProvider methods
57     HRESULT STDMETHODCALLTYPE PutSignalSource(ULONG ulSignalSource);
58     HRESULT STDMETHODCALLTYPE GetSignalSource(ULONG *pulSignalSource);
59     HRESULT STDMETHODCALLTYPE GetNetworkType(GUID *pguidNetworkType);
60     HRESULT STDMETHODCALLTYPE PutTuningSpace(REFGUID guidTuningSpace);
61     HRESULT STDMETHODCALLTYPE GetTuningSpace(GUID *pguidTuingSpace);
62     HRESULT STDMETHODCALLTYPE RegisterDeviceFilter(IUnknown *pUnkFilterControl, ULONG *ppvRegistrationContext);
63     HRESULT STDMETHODCALLTYPE UnRegisterDeviceFilter(ULONG pvRegistrationContext);
64 
65     CNetworkProvider(LPCGUID ClassID);
66     virtual ~CNetworkProvider(){};
67 
68 protected:
69     LONG m_Ref;
70     IFilterGraph *m_pGraph;
71     IReferenceClock * m_ReferenceClock;
72     FILTER_STATE m_FilterState;
73     IPin * m_Pins[1];
74     GUID m_ClassID;
75     DeviceFilterStack m_DeviceFilters;
76     IScanningTuner * m_Tuner;
77     IBDA_IPV6Filter * m_IPV6Filter;
78     IBDA_IPV4Filter * m_IPV4Filter;
79     IBDA_EthernetFilter * m_EthernetFilter;
80 };
81 
82 HRESULT
83 STDMETHODCALLTYPE
84 CNetworkProvider::QueryInterface(
85     IN  REFIID refiid,
86     OUT PVOID* Output)
87 {
88     ULONG Index;
89     HRESULT hr;
90 
91     *Output = NULL;
92 
93     if (IsEqualGUID(refiid, IID_IUnknown))
94     {
95         *Output = PVOID(this);
96         reinterpret_cast<IUnknown*>(*Output)->AddRef();
97         return NOERROR;
98     }
99     if (IsEqualGUID(refiid, IID_IBaseFilter))
100     {
101         *Output = (IBaseFilter*)(this);
102         reinterpret_cast<IBaseFilter*>(*Output)->AddRef();
103         return NOERROR;
104     }
105 
106     if (IsEqualGUID(refiid, IID_ITuner) ||
107         IsEqualGUID(refiid, IID_IScanningTuner))
108     {
109         // construct scanning tuner
110         if (!m_Tuner)
111         {
112             HRESULT hr = CScanningTunner_fnConstructor(m_DeviceFilters, refiid, (void**)&m_Tuner);
113             if (FAILED(hr))
114                 return hr;
115         }
116         m_Tuner->AddRef();
117         *Output = (IUnknown*)m_Tuner;
118 
119         return NOERROR;
120     }
121 
122     if (IsEqualGUID(refiid, IID_IBDA_IPV6Filter))
123     {
124         // construct scanning tuner
125         if (!m_IPV6Filter)
126         {
127             HRESULT hr = CIPV6Filter_fnConstructor((IBDA_NetworkProvider*)this, refiid, (void**)&m_IPV6Filter);
128             if (FAILED(hr))
129                 return hr;
130         }
131         m_IPV6Filter->AddRef();
132         *Output = (IUnknown*)m_IPV6Filter;
133 
134         return NOERROR;
135     }
136 
137     if (IsEqualGUID(refiid, IID_IBDA_IPV4Filter))
138     {
139         // construct scanning tuner
140         if (!m_IPV4Filter)
141         {
142             HRESULT hr = CIPV4Filter_fnConstructor((IBDA_NetworkProvider*)this, refiid, (void**)&m_IPV4Filter);
143             if (FAILED(hr))
144                 return hr;
145         }
146         m_IPV4Filter->AddRef();
147         *Output = (IUnknown*)m_IPV4Filter;
148 
149         return NOERROR;
150     }
151 
152     if (IsEqualGUID(refiid, IID_IBDA_EthernetFilter))
153     {
154         // construct scanning tuner
155         if (!m_EthernetFilter)
156         {
157             HRESULT hr = CIPV4Filter_fnConstructor((IBDA_NetworkProvider*)this, refiid, (void**)&m_EthernetFilter);
158             if (FAILED(hr))
159                 return hr;
160         }
161         m_EthernetFilter->AddRef();
162         *Output = (IUnknown*)m_EthernetFilter;
163 
164         return NOERROR;
165     }
166 
167     if (IsEqualGUID(refiid, IID_IBDA_NetworkProvider))
168     {
169         *Output = (IBDA_NetworkProvider*)(this);
170         reinterpret_cast<IBDA_NetworkProvider*>(*Output)->AddRef();
171         return NOERROR;
172     }
173 
174     for(Index = 0; Index < m_DeviceFilters.size(); Index++)
175     {
176         // get device filter
177         IUnknown *pFilter = m_DeviceFilters[Index];
178 
179         if (!pFilter)
180             continue;
181 
182         // query for requested interface
183         hr =  pFilter->QueryInterface(refiid, Output);
184         if (SUCCEEDED(hr))
185         {
186 #ifdef MSDVBNP_TRACE
187             WCHAR Buffer[MAX_PATH];
188             LPOLESTR lpstr;
189             StringFromCLSID(refiid, &lpstr);
190             swprintf(Buffer, L"CNetworkProvider::QueryInterface: DeviceFilter %lu supports %s !!!\n", Index, lpstr);
191             OutputDebugStringW(Buffer);
192             CoTaskMemFree(lpstr);
193 #endif
194             return hr;
195         }
196     }
197 
198     WCHAR Buffer[MAX_PATH];
199     LPOLESTR lpstr;
200     StringFromCLSID(refiid, &lpstr);
201     swprintf(Buffer, L"CNetworkProvider::QueryInterface: NoInterface for %s !!!\n", lpstr);
202     OutputDebugStringW(Buffer);
203     CoTaskMemFree(lpstr);
204 
205     return E_NOINTERFACE;
206 }
207 
208 CNetworkProvider::CNetworkProvider(LPCGUID ClassID) : m_Ref(0),
209                                                       m_pGraph(0),
210                                                       m_ReferenceClock(0),
211                                                       m_FilterState(State_Stopped),
212                                                       m_DeviceFilters(),
213                                                       m_Tuner(0),
214                                                       m_IPV6Filter(0),
215                                                       m_IPV4Filter(0),
216                                                       m_EthernetFilter(0)
217 {
218     m_Pins[0] = 0;
219 
220     CopyMemory(&m_ClassID, ClassID, sizeof(GUID));
221 };
222 
223 //-------------------------------------------------------------------
224 // IBaseFilter interface
225 //
226 
227 HRESULT
228 STDMETHODCALLTYPE
229 CNetworkProvider::GetClassID(
230     CLSID *pClassID)
231 {
232     OutputDebugStringW(L"CNetworkProvider::GetClassID\n");
233     CopyMemory(&pClassID, &m_ClassID, sizeof(GUID));
234 
235     return S_OK;
236 }
237 
238 HRESULT
239 STDMETHODCALLTYPE
240 CNetworkProvider::Stop()
241 {
242     OutputDebugStringW(L"CNetworkProvider::Stop\n");
243     m_FilterState = State_Stopped;
244     return S_OK;
245 }
246 
247 HRESULT
248 STDMETHODCALLTYPE
249 CNetworkProvider::Pause()
250 {
251     OutputDebugStringW(L"CNetworkProvider::Pause\n");
252 
253     m_FilterState = State_Paused;
254     return S_OK;
255 }
256 
257 HRESULT
258 STDMETHODCALLTYPE
259 CNetworkProvider::Run(
260     REFERENCE_TIME tStart)
261 {
262     OutputDebugStringW(L"CNetworkProvider::Run\n");
263 
264     m_FilterState = State_Running;
265     return S_OK;
266 }
267 
268 HRESULT
269 STDMETHODCALLTYPE
270 CNetworkProvider::GetState(
271     DWORD dwMilliSecsTimeout,
272     FILTER_STATE *State)
273 {
274     *State = m_FilterState;
275     return S_OK;
276 }
277 
278 HRESULT
279 STDMETHODCALLTYPE
280 CNetworkProvider::SetSyncSource(
281     IReferenceClock *pClock)
282 {
283     if (pClock)
284     {
285         pClock->AddRef();
286 
287     }
288     if (m_ReferenceClock)
289     {
290         m_ReferenceClock->Release();
291     }
292 
293     m_ReferenceClock = pClock;
294     return S_OK;
295 }
296 
297 HRESULT
298 STDMETHODCALLTYPE
299 CNetworkProvider::GetSyncSource(
300     IReferenceClock **pClock)
301 {
302     if (!pClock)
303         return E_POINTER;
304 
305     if (m_ReferenceClock)
306         m_ReferenceClock->AddRef();
307 
308     *pClock = m_ReferenceClock;
309     return S_OK;
310 }
311 
312 HRESULT
313 STDMETHODCALLTYPE
314 CNetworkProvider::EnumPins(
315     IEnumPins **ppEnum)
316 {
317     if (m_Pins[0] == 0)
318     {
319         HRESULT hr = CPin_fnConstructor(NULL, (IBaseFilter*)this, IID_IUnknown, (void**)&m_Pins[0]);
320         if (FAILED(hr))
321             return hr;
322     }
323 
324     return CEnumPins_fnConstructor(NULL, 1, m_Pins, IID_IEnumPins, (void**)ppEnum);
325 }
326 
327 HRESULT
328 STDMETHODCALLTYPE
329 CNetworkProvider::FindPin(
330     LPCWSTR Id, IPin **ppPin)
331 {
332     OutputDebugStringW(L"CNetworkProvider::FindPin : NotImplemented\n");
333     return E_NOTIMPL;
334 }
335 
336 
337 HRESULT
338 STDMETHODCALLTYPE
339 CNetworkProvider::QueryFilterInfo(
340     FILTER_INFO *pInfo)
341 {
342     if (!pInfo)
343         return E_POINTER;
344 
345     pInfo->achName[0] = L'\0';
346     pInfo->pGraph = m_pGraph;
347 
348     if (m_pGraph)
349         m_pGraph->AddRef();
350 
351     return S_OK;
352 }
353 
354 HRESULT
355 STDMETHODCALLTYPE
356 CNetworkProvider::JoinFilterGraph(
357     IFilterGraph *pGraph,
358     LPCWSTR pName)
359 {
360     if (pGraph)
361     {
362         // joining filter graph
363         m_pGraph = pGraph;
364     }
365     else
366     {
367         // leaving graph
368         m_pGraph = 0;
369     }
370 
371     OutputDebugStringW(L"CNetworkProvider::JoinFilterGraph\n");
372     return S_OK;
373 }
374 
375 
376 HRESULT
377 STDMETHODCALLTYPE
378 CNetworkProvider::QueryVendorInfo(
379     LPWSTR *pVendorInfo)
380 {
381     return E_NOTIMPL;
382 }
383 
384 //-------------------------------------------------------------------
385 // IAMovieSetup interface
386 //
387 
388 HRESULT
389 STDMETHODCALLTYPE
390 CNetworkProvider::Register()
391 {
392     OutputDebugStringW(L"CNetworkProvider::Register : NotImplemented\n");
393     return E_NOTIMPL;
394 }
395 
396 HRESULT
397 STDMETHODCALLTYPE
398 CNetworkProvider::Unregister()
399 {
400     OutputDebugStringW(L"CNetworkProvider::Unregister : NotImplemented\n");
401     return E_NOTIMPL;
402 }
403 
404 //-------------------------------------------------------------------
405 // IBDA_NetworkProvider interface
406 //
407 
408 HRESULT
409 STDMETHODCALLTYPE
410 CNetworkProvider::PutSignalSource(
411     ULONG ulSignalSource)
412 {
413     OutputDebugStringW(L"CNetworkProvider::PutSignalSource : NotImplemented\n");
414     return E_NOTIMPL;
415 }
416 
417 HRESULT
418 STDMETHODCALLTYPE
419 CNetworkProvider::GetSignalSource(
420     ULONG *pulSignalSource)
421 {
422     OutputDebugStringW(L"CNetworkProvider::GetSignalSource : NotImplemented\n");
423     return E_NOTIMPL;
424 }
425 
426 HRESULT
427 STDMETHODCALLTYPE
428 CNetworkProvider::GetNetworkType(
429     GUID *pguidNetworkType)
430 {
431     OutputDebugStringW(L"CNetworkProvider::GetNetworkType : NotImplemented\n");
432     return E_NOTIMPL;
433 }
434 
435 HRESULT
436 STDMETHODCALLTYPE
437 CNetworkProvider::PutTuningSpace(
438     REFGUID guidTuningSpace)
439 {
440     OutputDebugStringW(L"CNetworkProvider::PutTuningSpace : NotImplemented\n");
441     return E_NOTIMPL;
442 }
443 
444 HRESULT
445 STDMETHODCALLTYPE
446 CNetworkProvider::GetTuningSpace(
447     GUID *pguidTuingSpace)
448 {
449     OutputDebugStringW(L"CNetworkProvider::GetTuningSpace : NotImplemented\n");
450     return E_NOTIMPL;
451 }
452 
453 HRESULT
454 STDMETHODCALLTYPE
455 CNetworkProvider::RegisterDeviceFilter(
456     IUnknown *pUnkFilterControl,
457     ULONG *ppvRegistrationContext)
458 {
459     HRESULT hr;
460     IBDA_DeviceControl * pDeviceControl = NULL;
461     IBDA_Topology *pTopology = NULL;
462 
463     OutputDebugStringW(L"CNetworkProvider::RegisterDeviceFilter\n");
464 
465     if (!pUnkFilterControl || !ppvRegistrationContext)
466     {
467         //invalid argument
468         return E_POINTER;
469     }
470 
471     // the filter must support IBDA_DeviceControl and IBDA_Topology
472     hr = pUnkFilterControl->QueryInterface(IID_IBDA_DeviceControl, (void**)&pDeviceControl);
473     if (FAILED(hr))
474     {
475         OutputDebugStringW(L"CNetworkProvider::RegisterDeviceFilter Filter does not support IBDA_DeviceControl\n");
476         return hr;
477     }
478 
479     hr = pUnkFilterControl->QueryInterface(IID_IBDA_Topology, (void**)&pTopology);
480     if (FAILED(hr))
481     {
482         pDeviceControl->Release();
483         OutputDebugStringW(L"CNetworkProvider::RegisterDeviceFilter Filter does not support IID_IBDA_Topology\n");
484         return hr;
485     }
486 
487     //TODO
488     // analyize device filter
489 
490     // increment reference
491     pUnkFilterControl->AddRef();
492 
493     // release IBDA_DeviceControl interface
494     pDeviceControl->Release();
495 
496     // release IBDA_Topology interface
497     pTopology->Release();
498 
499     // store registration ctx
500     *ppvRegistrationContext = (m_DeviceFilters.size() | DEVICE_FILTER_MASK);
501 
502     // store filter
503     m_DeviceFilters.push_back(pUnkFilterControl);
504 
505     OutputDebugStringW(L"CNetworkProvider::RegisterDeviceFilter complete\n");
506 
507     return S_OK;
508 }
509 
510 HRESULT
511 STDMETHODCALLTYPE
512 CNetworkProvider::UnRegisterDeviceFilter(ULONG pvRegistrationContext)
513 {
514     ULONG Index;
515     IUnknown * pUnknown;
516 
517     OutputDebugStringW(L"CNetworkProvider::UnRegisterDeviceFilter\n");
518 
519     if (!(pvRegistrationContext & DEVICE_FILTER_MASK))
520     {
521         // invalid argument
522         return E_INVALIDARG;
523     }
524 
525     // get real index
526     Index = pvRegistrationContext & ~DEVICE_FILTER_MASK;
527 
528     if (Index >= m_DeviceFilters.size())
529     {
530         // invalid argument
531         return E_INVALIDARG;
532     }
533 
534     pUnknown = m_DeviceFilters[Index];
535     if (!pUnknown)
536     {
537         // filter was already de-registered
538         return E_INVALIDARG;
539     }
540 
541     // remove from vector
542     m_DeviceFilters[Index] = NULL;
543 
544     // release extra reference
545     pUnknown->Release();
546 
547     return NOERROR;
548 }
549 
550 HRESULT
551 WINAPI
552 CNetworkProvider_fnConstructor(
553     IUnknown *pUnknown,
554     REFIID riid,
555     LPVOID * ppv)
556 {
557     CNetworkProvider * handler = new CNetworkProvider(&CLSID_DVBTNetworkProvider);
558 
559 #ifdef MSDVBNP_TRACE
560     WCHAR Buffer[MAX_PATH];
561     LPOLESTR lpstr;
562     StringFromCLSID(riid, &lpstr);
563     swprintf(Buffer, L"CNetworkProvider_fnConstructor riid %s pUnknown %p\n", lpstr, pUnknown);
564     OutputDebugStringW(Buffer);
565 #endif
566 
567     if (!handler)
568         return E_OUTOFMEMORY;
569 
570     if (FAILED(handler->QueryInterface(riid, ppv)))
571     {
572         /* not supported */
573         delete handler;
574         return E_NOINTERFACE;
575     }
576     return NOERROR;
577 }
578