/*************************************************************************** * * CurlS#arp * * Copyright (c) 2013-2017 Dr. Masroor Ehsan (masroore@gmail.com) * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) * Portions copyright (c) 2017 Katelyn Gigante (https://github.com/silasary) * * This software is licensed as described in the file LICENSE, which you * should have received as part of this distribution. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of this Software, and permit persons to whom the Software is * furnished to do so, under the terms of the LICENSE file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF * ANY KIND, either express or implied. * **************************************************************************/ //#define USE_LIBCURLSHIM using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using CurlSharp.Enums; namespace CurlSharp { /// /// P/Invoke signatures. /// internal static unsafe class NativeMethods { private const string LIBCURL = "libcurl"; private const string LIBCURLSHIM = "libcurlshim"; private const string LIBC_LINUX = "libc"; private const string WINSOCK_LIB = "ws2_32.dll"; private const string LIB_DIR_WIN64 = "amd64"; private const string LIB_DIR_WIN32 = "i386"; static NativeMethods() { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { if (Environment.Is64BitOperatingSystem) { SetDllDirectory(Path.Combine(AssemblyDirectory, LIB_DIR_WIN64)); } else { SetDllDirectory(Path.Combine(AssemblyDirectory, LIB_DIR_WIN32)); } } #if USE_LIBCURLSHIM if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) throw new InvalidOperationException("Can not run on other platform than Win NET"); #endif } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetDllDirectory(string lpPathName); private static string AssemblyDirectory { get { var codeBase = typeof(NativeMethods).GetTypeInfo().Assembly.CodeBase; var uri = new UriBuilder(codeBase); var path = Uri.UnescapeDataString(uri.Path); return Path.GetDirectoryName(path); } } #region curl_global_init [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_global_init(int flags); #endregion #region curl_global_cleanup [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_global_cleanup(); #endregion #region curl_easy_escape [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr curl_easy_escape(IntPtr pEasy, string url, int length); #endregion #region curl_easy_unescape [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr curl_easy_unescape(IntPtr pEasy, string url, int inLength, out int outLength); #endregion #region curl_free [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_free(IntPtr p); #endregion #region curl_version [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_version(); #endregion #region curl_version_info [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_version_info(CurlVersion ver); #endregion #region curl_easy_init [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_easy_init(); #endregion #region curl_easy_cleanup [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_easy_cleanup(IntPtr pCurl); #endregion #region curl_easy_setopt #region Delegates [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int _CurlGenericCallback(IntPtr ptr, int sz, int nmemb, IntPtr userdata); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int _CurlProgressCallback( IntPtr extraData, double dlTotal, double dlNow, double ulTotal, double ulNow); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int _CurlDebugCallback( IntPtr ptrCurl, CurlInfoType infoType, string message, int size, IntPtr ptrUserData); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int _CurlSslCtxCallback(IntPtr ctx, IntPtr parm); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate CurlIoError _CurlIoctlCallback(CurlIoCommand cmd, IntPtr parm); #endregion [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, IntPtr parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, string parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, byte[] parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, long parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, bool parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, _CurlGenericCallback parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, _CurlProgressCallback parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, _CurlDebugCallback parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, _CurlSslCtxCallback parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_setopt(IntPtr pCurl, CurlOption opt, _CurlIoctlCallback parm); #endregion #region curl_easy_perform [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_perform(IntPtr pCurl); #endregion #region curl_easy_duphandle [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_easy_duphandle(IntPtr pCurl); #endregion #region curl_easy_strerror [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_easy_strerror(CurlCode err); #endregion #region curl_easy_getinfo [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_getinfo(IntPtr pCurl, CurlInfo info, ref IntPtr pInfo); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlCode curl_easy_getinfo(IntPtr pCurl, CurlInfo info, ref double dblVal); #endregion #region curl_easy_reset [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_easy_reset(IntPtr pCurl); #endregion #region curl_multi_init [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_multi_init(); #endregion #region curl_multi_cleanup [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlMultiCode curl_multi_cleanup(IntPtr pmulti); #endregion #region curl_multi_add_handle [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlMultiCode curl_multi_add_handle(IntPtr pmulti, IntPtr peasy); #endregion #region curl_multi_remove_handle [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlMultiCode curl_multi_remove_handle(IntPtr pmulti, IntPtr peasy); #endregion #region curl_multi_setopt [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlMultiCode curl_multi_setopt(IntPtr pmulti, CurlMultiOption opt, bool parm); [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlMultiCode curl_multi_setopt(IntPtr pmulti, CurlMultiOption opt, long parm); #endregion #region curl_multi_strerror [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_multi_strerror(CurlMultiCode errorNum); #endregion #region curl_multi_perform [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlMultiCode curl_multi_perform(IntPtr pmulti, ref int runningHandles); #endregion #if !USE_LIBCURLSHIM #region curl_multi_fdset [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlMultiCode curl_multi_fdset(IntPtr pmulti, [In] [Out] ref fd_set read_fd_set, [In] [Out] ref fd_set write_fd_set, [In] [Out] ref fd_set exc_fd_set, [In] [Out] ref int max_fd); [StructLayout(LayoutKind.Sequential)] public struct fd_set { public uint fd_count; // [MarshalAs(UnmanagedType.ByValArray, SizeConst = FD_SETSIZE)] public IntPtr[] fd_array; public fixed uint fd_array[FD_SETSIZE]; public const int FD_SETSIZE = 64; public void Cleanup() { // fd_array = null; } public static fd_set Create() { return new fd_set { // fd_array = new IntPtr[FD_SETSIZE], fd_count = 0 }; } public static fd_set Create(IntPtr socket) { var handle = Create(); handle.fd_count = 1; handle.fd_array[0] = (uint)socket; return handle; } } public static void FD_ZERO(fd_set fds) { for (var i = 0; i < fd_set.FD_SETSIZE; i++) { fds.fd_array[i] = 0; } fds.fd_count = 0; } #endregion #region select [StructLayout(LayoutKind.Sequential)] public struct timeval { /// /// Time interval, in seconds. /// public int tv_sec; /// /// Time interval, in microseconds. /// public int tv_usec; public static timeval Create(int milliseconds) { return new timeval { tv_sec = milliseconds / 1000, tv_usec = milliseconds % 1000 * 1000 }; } } [DllImport(LIBC_LINUX, EntryPoint = "select")] private static extern int select_unix( int nfds, // number of sockets, (ignored in winsock) [In] [Out] ref fd_set readfds, // read sockets to watch [In] [Out] ref fd_set writefds, // write sockets to watch [In] [Out] ref fd_set exceptfds, // error sockets to watch ref timeval timeout); [DllImport(WINSOCK_LIB, EntryPoint = "select")] private static extern int select_win( int nfds, // number of sockets, (ignored in winsock) [In] [Out] ref fd_set readfds, // read sockets to watch [In] [Out] ref fd_set writefds, // write sockets to watch [In] [Out] ref fd_set exceptfds, // error sockets to watch ref timeval timeout); public static int select( int nfds, // number of sockets, (ignored in winsock) [In] [Out] ref fd_set readfds, // read sockets to watch [In] [Out] ref fd_set writefds, // write sockets to watch [In] [Out] ref fd_set exceptfds, // error sockets to watch ref timeval timeout) { int result; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { result = select_win( nfds, // number of sockets, (ignored in winsock) ref readfds, // read sockets to watch ref writefds, // write sockets to watch ref exceptfds, // error sockets to watch ref timeout); } else { result = select_unix( nfds, // number of sockets, (ignored in winsock) ref readfds, // read sockets to watch ref writefds, // write sockets to watch ref exceptfds, // error sockets to watch ref timeout); } return result; } #endregion #endif #region curl_share_init [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_share_init(); #endregion #region curl_share_cleanup [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlShareCode curl_share_cleanup(IntPtr pShare); #endregion #region curl_share_strerror [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_share_strerror(CurlShareCode errorCode); #endregion #region curl_share_setopt [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern CurlShareCode curl_share_setopt( IntPtr pShare, CurlShareOption optCode, IntPtr option); #endregion #region curl_formadd #if !USE_LIBCURLSHIM [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern int curl_formadd(ref IntPtr pHttppost, ref IntPtr pLastPost, int codeFirst, IntPtr bufFirst, int codeNext, IntPtr bufNext, int codeLast); #endif #endregion #region curl_formfree [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_formfree(IntPtr pForm); #endregion #region curl_slist_append [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr curl_slist_append(IntPtr slist, string data); #endregion #region curl_slist_free_all [DllImport(LIBCURL, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_slist_free_all(IntPtr pList); #endregion #if USE_LIBCURLSHIM #region libcurlshim imports [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_initialize(); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_cleanup(); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_shim_alloc_strings(); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr curl_shim_add_string_to_slist(IntPtr pStrings, string str); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr curl_shim_get_string_from_slist(IntPtr pSlist, ref IntPtr pStr); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr curl_shim_add_string(IntPtr pStrings, string str); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_free_strings(IntPtr pStrings); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern int curl_shim_install_delegates( IntPtr pCurl, IntPtr pThis, _ShimWriteCallback pWrite, _ShimReadCallback pRead, _ShimProgressCallback pProgress, _ShimDebugCallback pDebug, _ShimHeaderCallback pHeader, _ShimSslCtxCallback pCtx, _ShimIoctlCallback pIoctl); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_cleanup_delegates(IntPtr pThis); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_get_file_time( int unixTime, ref int yy, ref int mm, ref int dd, ref int hh, ref int mn, ref int ss); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_free_slist(IntPtr p); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_shim_alloc_fd_sets(); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_free_fd_sets(IntPtr fdsets); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern CurlMultiCode curl_shim_multi_fdset(IntPtr multi, IntPtr fdsets, ref int maxFD); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern int curl_shim_select(int maxFD, IntPtr fdsets, int milliseconds); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_shim_multi_info_read(IntPtr multi, ref int nMsgs); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_multi_info_free(IntPtr multiInfo); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern int curl_shim_formadd(IntPtr[] ppForms, IntPtr[] pParams, int nParams); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern int curl_shim_install_share_delegates( IntPtr pShare, IntPtr pThis, _ShimLockCallback pLock, _ShimUnlockCallback pUnlock); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern void curl_shim_cleanup_share_delegates(IntPtr pShare); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern int curl_shim_get_version_int_value(IntPtr p, int offset); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_shim_get_version_char_ptr(IntPtr p, int offset); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern int curl_shim_get_number_of_protocols(IntPtr p, int offset); [DllImport(LIBCURLSHIM, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr curl_shim_get_protocol_string(IntPtr p, int offset, int index); public delegate void _ShimLockCallback(int data, int access, IntPtr userPtr); public delegate void _ShimUnlockCallback(int data, IntPtr userPtr); public delegate int _ShimDebugCallback(CurlInfoType infoType, IntPtr msgBuf, int msgBufSize, IntPtr parm); public delegate int _ShimHeaderCallback(IntPtr buf, int sz, int nmemb, IntPtr stream); public delegate CurlIoError _ShimIoctlCallback(CurlIoCommand cmd, IntPtr parm); public delegate int _ShimProgressCallback( IntPtr parm, double dlTotal, double dlNow, double ulTotal, double ulNow); public delegate int _ShimReadCallback(IntPtr buf, int sz, int nmemb, IntPtr parm); public delegate int _ShimSslCtxCallback(IntPtr ctx, IntPtr parm); public delegate int _ShimWriteCallback(IntPtr buf, int sz, int nmemb, IntPtr parm); #endregion #endif } }