net.nim 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Dominik Picheta
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements a high-level cross-platform sockets interface.
  10. ## The procedures implemented in this module are primarily for blocking sockets.
  11. ## For asynchronous non-blocking sockets use the ``asyncnet`` module together
  12. ## with the ``asyncdispatch`` module.
  13. ##
  14. ## The first thing you will always need to do in order to start using sockets,
  15. ## is to create a new instance of the ``Socket`` type using the ``newSocket``
  16. ## procedure.
  17. ##
  18. ## SSL
  19. ## ====
  20. ##
  21. ## In order to use the SSL procedures defined in this module, you will need to
  22. ## compile your application with the ``-d:ssl`` flag.
  23. ##
  24. ## Examples
  25. ## ========
  26. ##
  27. ## Connecting to a server
  28. ## ----------------------
  29. ##
  30. ## After you create a socket with the ``newSocket`` procedure, you can easily
  31. ## connect it to a server running at a known hostname (or IP address) and port.
  32. ## To do so over TCP, use the example below.
  33. ##
  34. ## .. code-block:: Nim
  35. ## var socket = newSocket()
  36. ## socket.connect("google.com", Port(80))
  37. ##
  38. ## UDP is a connectionless protocol, so UDP sockets don't have to explicitly
  39. ## call the ``connect`` procedure. They can simply start sending data
  40. ## immediately.
  41. ##
  42. ## .. code-block:: Nim
  43. ## var socket = newSocket()
  44. ## socket.sendTo("192.168.0.1", Port(27960), "status\n")
  45. ##
  46. ## Creating a server
  47. ## -----------------
  48. ##
  49. ## After you create a socket with the ``newSocket`` procedure, you can create a
  50. ## TCP server by calling the ``bindAddr`` and ``listen`` procedures.
  51. ##
  52. ## .. code-block:: Nim
  53. ## var socket = newSocket()
  54. ## socket.bindAddr(Port(1234))
  55. ## socket.listen()
  56. ##
  57. ## You can then begin accepting connections using the ``accept`` procedure.
  58. ##
  59. ## .. code-block:: Nim
  60. ## var client = newSocket()
  61. ## var address = ""
  62. ## while true:
  63. ## socket.acceptAddr(client, address)
  64. ## echo("Client connected from: ", address)
  65. ##
  66. {.deadCodeElim: on.}
  67. import nativesockets, os, strutils, parseutils, times, sets, options
  68. export Port, `$`, `==`
  69. export Domain, SockType, Protocol
  70. const useWinVersion = defined(Windows) or defined(nimdoc)
  71. const defineSsl = defined(ssl) or defined(nimdoc)
  72. when defineSsl:
  73. import openssl
  74. # Note: The enumerations are mapped to Window's constants.
  75. when defineSsl:
  76. type
  77. SslError* = object of Exception
  78. SslCVerifyMode* = enum
  79. CVerifyNone, CVerifyPeer
  80. SslProtVersion* = enum
  81. protSSLv2, protSSLv3, protTLSv1, protSSLv23
  82. SslContext* = ref object
  83. context*: SslCtx
  84. referencedData: HashSet[int]
  85. extraInternal: SslContextExtraInternal
  86. SslAcceptResult* = enum
  87. AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
  88. SslHandshakeType* = enum
  89. handshakeAsClient, handshakeAsServer
  90. SslClientGetPskFunc* = proc(hint: string): tuple[identity: string, psk: string]
  91. SslServerGetPskFunc* = proc(identity: string): string
  92. SslContextExtraInternal = ref object of RootRef
  93. serverGetPskFunc: SslServerGetPskFunc
  94. clientGetPskFunc: SslClientGetPskFunc
  95. {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode,
  96. TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext,
  97. TSSLAcceptResult: SSLAcceptResult].}
  98. else:
  99. type
  100. SslContext* = void # TODO: Workaround #4797.
  101. const
  102. BufferSize*: int = 4000 ## size of a buffered socket's buffer
  103. MaxLineLength* = 1_000_000
  104. type
  105. SocketImpl* = object ## socket type
  106. fd: SocketHandle
  107. case isBuffered: bool # determines whether this socket is buffered.
  108. of true:
  109. buffer: array[0..BufferSize, char]
  110. currPos: int # current index in buffer
  111. bufLen: int # current length of buffer
  112. of false: nil
  113. when defineSsl:
  114. case isSsl: bool
  115. of true:
  116. sslHandle: SSLPtr
  117. sslContext: SSLContext
  118. sslNoHandshake: bool # True if needs handshake.
  119. sslHasPeekChar: bool
  120. sslPeekChar: char
  121. of false: nil
  122. lastError: OSErrorCode ## stores the last error on this socket
  123. domain: Domain
  124. sockType: SockType
  125. protocol: Protocol
  126. Socket* = ref SocketImpl
  127. SOBool* = enum ## Boolean socket options.
  128. OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
  129. OptOOBInline, OptReuseAddr, OptReusePort
  130. ReadLineResult* = enum ## result for readLineAsync
  131. ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone
  132. TimeoutError* = object of Exception
  133. SocketFlag* {.pure.} = enum
  134. Peek,
  135. SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown.
  136. {.deprecated: [TSocketFlags: SocketFlag, ETimeout: TimeoutError,
  137. TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
  138. TSocketImpl: SocketImpl].}
  139. type
  140. IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
  141. IPv6, ## IPv6 address
  142. IPv4 ## IPv4 address
  143. IpAddress* = object ## stores an arbitrary IP address
  144. case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
  145. of IpAddressFamily.IPv6:
  146. address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
  147. ## case of IPv6
  148. of IpAddressFamily.IPv4:
  149. address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
  150. ## case of IPv4
  151. {.deprecated: [TIpAddress: IpAddress].}
  152. proc socketError*(socket: Socket, err: int = -1, async = false,
  153. lastError = (-1).OSErrorCode): void {.gcsafe.}
  154. proc isDisconnectionError*(flags: set[SocketFlag],
  155. lastError: OSErrorCode): bool =
  156. ## Determines whether ``lastError`` is a disconnection error. Only does this
  157. ## if flags contains ``SafeDisconn``.
  158. when useWinVersion:
  159. SocketFlag.SafeDisconn in flags and
  160. lastError.int32 in {WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
  161. WSAEDISCON, ERROR_NETNAME_DELETED}
  162. else:
  163. SocketFlag.SafeDisconn in flags and
  164. lastError.int32 in {ECONNRESET, EPIPE, ENETRESET}
  165. proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
  166. ## Converts the flags into the underlying OS representation.
  167. for f in socketFlags:
  168. case f
  169. of SocketFlag.Peek:
  170. result = result or MSG_PEEK
  171. of SocketFlag.SafeDisconn: continue
  172. proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET,
  173. sockType: SockType = SOCK_STREAM,
  174. protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
  175. ## Creates a new socket as specified by the params.
  176. assert fd != osInvalidSocket
  177. result = Socket(
  178. fd: fd,
  179. isBuffered: buffered,
  180. domain: domain,
  181. sockType: sockType,
  182. protocol: protocol)
  183. if buffered:
  184. result.currPos = 0
  185. # Set SO_NOSIGPIPE on OS X.
  186. when defined(macosx) and not defined(nimdoc):
  187. setSockOptInt(fd, SOL_SOCKET, SO_NOSIGPIPE, 1)
  188. proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket =
  189. ## Creates a new socket.
  190. ##
  191. ## If an error occurs EOS will be raised.
  192. let fd = newNativeSocket(domain, sockType, protocol)
  193. if fd == osInvalidSocket:
  194. raiseOSError(osLastError())
  195. result = newSocket(fd, domain.Domain, sockType.SockType, protocol.Protocol,
  196. buffered)
  197. proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
  198. protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
  199. ## Creates a new socket.
  200. ##
  201. ## If an error occurs EOS will be raised.
  202. let fd = newNativeSocket(domain, sockType, protocol)
  203. if fd == osInvalidSocket:
  204. raiseOSError(osLastError())
  205. result = newSocket(fd, domain, sockType, protocol, buffered)
  206. proc parseIPv4Address(address_str: string): IpAddress =
  207. ## Parses IPv4 adresses
  208. ## Raises EInvalidValue on errors
  209. var
  210. byteCount = 0
  211. currentByte:uint16 = 0
  212. seperatorValid = false
  213. result.family = IpAddressFamily.IPv4
  214. for i in 0 .. high(address_str):
  215. if address_str[i] in strutils.Digits: # Character is a number
  216. currentByte = currentByte * 10 +
  217. cast[uint16](ord(address_str[i]) - ord('0'))
  218. if currentByte > 255'u16:
  219. raise newException(ValueError,
  220. "Invalid IP Address. Value is out of range")
  221. seperatorValid = true
  222. elif address_str[i] == '.': # IPv4 address separator
  223. if not seperatorValid or byteCount >= 3:
  224. raise newException(ValueError,
  225. "Invalid IP Address. The address consists of too many groups")
  226. result.address_v4[byteCount] = cast[uint8](currentByte)
  227. currentByte = 0
  228. byteCount.inc
  229. seperatorValid = false
  230. else:
  231. raise newException(ValueError,
  232. "Invalid IP Address. Address contains an invalid character")
  233. if byteCount != 3 or not seperatorValid:
  234. raise newException(ValueError, "Invalid IP Address")
  235. result.address_v4[byteCount] = cast[uint8](currentByte)
  236. proc parseIPv6Address(address_str: string): IpAddress =
  237. ## Parses IPv6 adresses
  238. ## Raises EInvalidValue on errors
  239. result.family = IpAddressFamily.IPv6
  240. if address_str.len < 2:
  241. raise newException(ValueError, "Invalid IP Address")
  242. var
  243. groupCount = 0
  244. currentGroupStart = 0
  245. currentShort:uint32 = 0
  246. seperatorValid = true
  247. dualColonGroup = -1
  248. lastWasColon = false
  249. v4StartPos = -1
  250. byteCount = 0
  251. for i,c in address_str:
  252. if c == ':':
  253. if not seperatorValid:
  254. raise newException(ValueError,
  255. "Invalid IP Address. Address contains an invalid seperator")
  256. if lastWasColon:
  257. if dualColonGroup != -1:
  258. raise newException(ValueError,
  259. "Invalid IP Address. Address contains more than one \"::\" seperator")
  260. dualColonGroup = groupCount
  261. seperatorValid = false
  262. elif i != 0 and i != high(address_str):
  263. if groupCount >= 8:
  264. raise newException(ValueError,
  265. "Invalid IP Address. The address consists of too many groups")
  266. result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
  267. result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
  268. currentShort = 0
  269. groupCount.inc()
  270. if dualColonGroup != -1: seperatorValid = false
  271. elif i == 0: # only valid if address starts with ::
  272. if address_str[1] != ':':
  273. raise newException(ValueError,
  274. "Invalid IP Address. Address may not start with \":\"")
  275. else: # i == high(address_str) - only valid if address ends with ::
  276. if address_str[high(address_str)-1] != ':':
  277. raise newException(ValueError,
  278. "Invalid IP Address. Address may not end with \":\"")
  279. lastWasColon = true
  280. currentGroupStart = i + 1
  281. elif c == '.': # Switch to parse IPv4 mode
  282. if i < 3 or not seperatorValid or groupCount >= 7:
  283. raise newException(ValueError, "Invalid IP Address")
  284. v4StartPos = currentGroupStart
  285. currentShort = 0
  286. seperatorValid = false
  287. break
  288. elif c in strutils.HexDigits:
  289. if c in strutils.Digits: # Normal digit
  290. currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('0'))
  291. elif c >= 'a' and c <= 'f': # Lower case hex
  292. currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('a')) + 10
  293. else: # Upper case hex
  294. currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('A')) + 10
  295. if currentShort > 65535'u32:
  296. raise newException(ValueError,
  297. "Invalid IP Address. Value is out of range")
  298. lastWasColon = false
  299. seperatorValid = true
  300. else:
  301. raise newException(ValueError,
  302. "Invalid IP Address. Address contains an invalid character")
  303. if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff
  304. if seperatorValid: # Copy remaining data
  305. if groupCount >= 8:
  306. raise newException(ValueError,
  307. "Invalid IP Address. The address consists of too many groups")
  308. result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
  309. result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
  310. groupCount.inc()
  311. else: # Must parse IPv4 address
  312. for i,c in address_str[v4StartPos..high(address_str)]:
  313. if c in strutils.Digits: # Character is a number
  314. currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
  315. if currentShort > 255'u32:
  316. raise newException(ValueError,
  317. "Invalid IP Address. Value is out of range")
  318. seperatorValid = true
  319. elif c == '.': # IPv4 address separator
  320. if not seperatorValid or byteCount >= 3:
  321. raise newException(ValueError, "Invalid IP Address")
  322. result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
  323. currentShort = 0
  324. byteCount.inc()
  325. seperatorValid = false
  326. else: # Invalid character
  327. raise newException(ValueError,
  328. "Invalid IP Address. Address contains an invalid character")
  329. if byteCount != 3 or not seperatorValid:
  330. raise newException(ValueError, "Invalid IP Address")
  331. result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
  332. groupCount += 2
  333. # Shift and fill zeros in case of ::
  334. if groupCount > 8:
  335. raise newException(ValueError,
  336. "Invalid IP Address. The address consists of too many groups")
  337. elif groupCount < 8: # must fill
  338. if dualColonGroup == -1:
  339. raise newException(ValueError,
  340. "Invalid IP Address. The address consists of too few groups")
  341. var toFill = 8 - groupCount # The number of groups to fill
  342. var toShift = groupCount - dualColonGroup # Nr of known groups after ::
  343. for i in 0..2*toShift-1: # shift
  344. result.address_v6[15-i] = result.address_v6[groupCount*2-i-1]
  345. for i in 0..2*toFill-1: # fill with 0s
  346. result.address_v6[dualColonGroup*2+i] = 0
  347. elif dualColonGroup != -1:
  348. raise newException(ValueError,
  349. "Invalid IP Address. The address consists of too many groups")
  350. proc parseIpAddress*(address_str: string): IpAddress =
  351. ## Parses an IP address
  352. ## Raises EInvalidValue on error
  353. if address_str == nil:
  354. raise newException(ValueError, "IP Address string is nil")
  355. if address_str.contains(':'):
  356. return parseIPv6Address(address_str)
  357. else:
  358. return parseIPv4Address(address_str)
  359. proc isIpAddress*(address_str: string): bool {.tags: [].} =
  360. ## Checks if a string is an IP address
  361. ## Returns true if it is, false otherwise
  362. try:
  363. discard parseIpAddress(address_str)
  364. except ValueError:
  365. return false
  366. return true
  367. when defineSsl:
  368. CRYPTO_malloc_init()
  369. SslLibraryInit()
  370. SslLoadErrorStrings()
  371. ErrLoadBioStrings()
  372. OpenSSL_add_all_algorithms()
  373. proc raiseSSLError*(s = "") =
  374. ## Raises a new SSL error.
  375. if s != "":
  376. raise newException(SSLError, s)
  377. let err = ErrPeekLastError()
  378. if err == 0:
  379. raise newException(SSLError, "No error reported.")
  380. if err == -1:
  381. raiseOSError(osLastError())
  382. var errStr = ErrErrorString(err, nil)
  383. raise newException(SSLError, $errStr)
  384. proc getExtraData*(ctx: SSLContext, index: int): RootRef =
  385. ## Retrieves arbitrary data stored inside SSLContext.
  386. if index notin ctx.referencedData:
  387. raise newException(IndexError, "No data with that index.")
  388. let res = ctx.context.SSL_CTX_get_ex_data(index.cint)
  389. if cast[int](res) == 0:
  390. raiseSSLError()
  391. return cast[RootRef](res)
  392. proc setExtraData*(ctx: SSLContext, index: int, data: RootRef) =
  393. ## Stores arbitrary data inside SSLContext. The unique `index`
  394. ## should be retrieved using getSslContextExtraDataIndex.
  395. if index in ctx.referencedData:
  396. GC_unref(getExtraData(ctx, index))
  397. if ctx.context.SSL_CTX_set_ex_data(index.cint, cast[pointer](data)) == -1:
  398. raiseSSLError()
  399. if index notin ctx.referencedData:
  400. ctx.referencedData.incl(index)
  401. GC_ref(data)
  402. # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
  403. proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) =
  404. if certFile != "" and not existsFile(certFile):
  405. raise newException(system.IOError, "Certificate file could not be found: " & certFile)
  406. if keyFile != "" and not existsFile(keyFile):
  407. raise newException(system.IOError, "Key file could not be found: " & keyFile)
  408. if certFile != "":
  409. var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
  410. if ret != 1:
  411. raiseSSLError()
  412. # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf
  413. if keyFile != "":
  414. if SSL_CTX_use_PrivateKey_file(ctx, keyFile,
  415. SSL_FILETYPE_PEM) != 1:
  416. raiseSSLError()
  417. if SSL_CTX_check_private_key(ctx) != 1:
  418. raiseSSLError("Verification of private key file failed.")
  419. proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
  420. certFile = "", keyFile = "", cipherList = "ALL"): SSLContext =
  421. ## Creates an SSL context.
  422. ##
  423. ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1
  424. ## are available with the addition of ``protSSLv23`` which allows for
  425. ## compatibility with all of them.
  426. ##
  427. ## There are currently only two options for verify mode;
  428. ## one is ``CVerifyNone`` and with it certificates will not be verified
  429. ## the other is ``CVerifyPeer`` and certificates will be verified for
  430. ## it, ``CVerifyPeer`` is the safest choice.
  431. ##
  432. ## The last two parameters specify the certificate file path and the key file
  433. ## path, a server socket will most likely not work without these.
  434. ## Certificates can be generated using the following command:
  435. ## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
  436. var newCTX: SSL_CTX
  437. case protVersion
  438. of protSSLv23:
  439. newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
  440. of protSSLv2:
  441. raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv23")
  442. of protSSLv3:
  443. raiseSslError("SSLv3 is no longer secure and has been deprecated, use protSSLv23")
  444. of protTLSv1:
  445. newCTX = SSL_CTX_new(TLSv1_method())
  446. if newCTX.SSLCTXSetCipherList(cipherList) != 1:
  447. raiseSSLError()
  448. case verifyMode
  449. of CVerifyPeer:
  450. newCTX.SSLCTXSetVerify(SSLVerifyPeer, nil)
  451. of CVerifyNone:
  452. newCTX.SSLCTXSetVerify(SSLVerifyNone, nil)
  453. if newCTX == nil:
  454. raiseSSLError()
  455. discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
  456. newCTX.loadCertificates(certFile, keyFile)
  457. result = SSLContext(context: newCTX, referencedData: initSet[int](),
  458. extraInternal: new(SslContextExtraInternal))
  459. proc getExtraInternal(ctx: SSLContext): SslContextExtraInternal =
  460. return ctx.extraInternal
  461. proc destroyContext*(ctx: SSLContext) =
  462. ## Free memory referenced by SSLContext.
  463. # We assume here that OpenSSL's internal indexes increase by 1 each time.
  464. # That means we can assume that the next internal index is the length of
  465. # extra data indexes.
  466. for i in ctx.referencedData:
  467. GC_unref(getExtraData(ctx, i).RootRef)
  468. ctx.context.SSL_CTX_free()
  469. proc `pskIdentityHint=`*(ctx: SSLContext, hint: string) =
  470. ## Sets the identity hint passed to server.
  471. ##
  472. ## Only used in PSK ciphersuites.
  473. if ctx.context.SSL_CTX_use_psk_identity_hint(hint) <= 0:
  474. raiseSSLError()
  475. proc clientGetPskFunc*(ctx: SSLContext): SslClientGetPskFunc =
  476. return ctx.getExtraInternal().clientGetPskFunc
  477. proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar;
  478. max_psk_len: cuint): cuint {.cdecl.} =
  479. let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX)
  480. let hintString = if hint == nil: nil else: $hint
  481. let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString)
  482. if psk.len.cuint > max_psk_len:
  483. return 0
  484. if identityString.len.cuint >= max_identity_len:
  485. return 0
  486. copyMem(identity, identityString.cstring, pskString.len + 1) # with the last zero byte
  487. copyMem(psk, pskString.cstring, pskString.len)
  488. return pskString.len.cuint
  489. proc `clientGetPskFunc=`*(ctx: SSLContext, fun: SslClientGetPskFunc) =
  490. ## Sets function that returns the client identity and the PSK based on identity
  491. ## hint from the server.
  492. ##
  493. ## Only used in PSK ciphersuites.
  494. ctx.getExtraInternal().clientGetPskFunc = fun
  495. ctx.context.SSL_CTX_set_psk_client_callback(
  496. if fun == nil: nil else: pskClientCallback)
  497. proc serverGetPskFunc*(ctx: SSLContext): SslServerGetPskFunc =
  498. return ctx.getExtraInternal().serverGetPskFunc
  499. proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} =
  500. let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX)
  501. let pskString = (ctx.serverGetPskFunc)($identity)
  502. if psk.len.cint > max_psk_len:
  503. return 0
  504. copyMem(psk, pskString.cstring, pskString.len)
  505. return pskString.len.cuint
  506. proc `serverGetPskFunc=`*(ctx: SSLContext, fun: SslServerGetPskFunc) =
  507. ## Sets function that returns PSK based on the client identity.
  508. ##
  509. ## Only used in PSK ciphersuites.
  510. ctx.getExtraInternal().serverGetPskFunc = fun
  511. ctx.context.SSL_CTX_set_psk_server_callback(if fun == nil: nil
  512. else: pskServerCallback)
  513. proc getPskIdentity*(socket: Socket): string =
  514. ## Gets the PSK identity provided by the client.
  515. assert socket.isSSL
  516. return $(socket.sslHandle.SSL_get_psk_identity)
  517. proc wrapSocket*(ctx: SSLContext, socket: Socket) =
  518. ## Wraps a socket in an SSL context. This function effectively turns
  519. ## ``socket`` into an SSL socket.
  520. ##
  521. ## This must be called on an unconnected socket; an SSL session will
  522. ## be started when the socket is connected.
  523. ##
  524. ## **Disclaimer**: This code is not well tested, may be very unsafe and
  525. ## prone to security vulnerabilities.
  526. assert(not socket.isSSL)
  527. socket.isSSL = true
  528. socket.sslContext = ctx
  529. socket.sslHandle = SSLNew(socket.sslContext.context)
  530. socket.sslNoHandshake = false
  531. socket.sslHasPeekChar = false
  532. if socket.sslHandle == nil:
  533. raiseSSLError()
  534. if SSLSetFd(socket.sslHandle, socket.fd) != 1:
  535. raiseSSLError()
  536. proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket,
  537. handshake: SslHandshakeType,
  538. hostname: string = nil) =
  539. ## Wraps a connected socket in an SSL context. This function effectively
  540. ## turns ``socket`` into an SSL socket.
  541. ## ``hostname`` should be specified so that the client knows which hostname
  542. ## the server certificate should be validated against.
  543. ##
  544. ## This should be called on a connected socket, and will perform
  545. ## an SSL handshake immediately.
  546. ##
  547. ## **Disclaimer**: This code is not well tested, may be very unsafe and
  548. ## prone to security vulnerabilities.
  549. wrapSocket(ctx, socket)
  550. case handshake
  551. of handshakeAsClient:
  552. if not hostname.isNil and not isIpAddress(hostname):
  553. # Discard result in case OpenSSL version doesn't support SNI, or we're
  554. # not using TLSv1+
  555. discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
  556. let ret = SSLConnect(socket.sslHandle)
  557. socketError(socket, ret)
  558. of handshakeAsServer:
  559. let ret = SSLAccept(socket.sslHandle)
  560. socketError(socket, ret)
  561. proc getSocketError*(socket: Socket): OSErrorCode =
  562. ## Checks ``osLastError`` for a valid error. If it has been reset it uses
  563. ## the last error stored in the socket object.
  564. result = osLastError()
  565. if result == 0.OSErrorCode:
  566. result = socket.lastError
  567. if result == 0.OSErrorCode:
  568. raiseOSError(result, "No valid socket error code available")
  569. proc socketError*(socket: Socket, err: int = -1, async = false,
  570. lastError = (-1).OSErrorCode) =
  571. ## Raises an OSError based on the error code returned by ``SSLGetError``
  572. ## (for SSL sockets) and ``osLastError`` otherwise.
  573. ##
  574. ## If ``async`` is ``true`` no error will be thrown in the case when the
  575. ## error was caused by no data being available to be read.
  576. ##
  577. ## If ``err`` is not lower than 0 no exception will be raised.
  578. when defineSsl:
  579. if socket.isSSL:
  580. if err <= 0:
  581. var ret = SSLGetError(socket.sslHandle, err.cint)
  582. case ret
  583. of SSL_ERROR_ZERO_RETURN:
  584. raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  585. of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  586. if async:
  587. return
  588. else: raiseSSLError("Not enough data on socket.")
  589. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
  590. if async:
  591. return
  592. else: raiseSSLError("Not enough data on socket.")
  593. of SSL_ERROR_WANT_X509_LOOKUP:
  594. raiseSSLError("Function for x509 lookup has been called.")
  595. of SSL_ERROR_SYSCALL:
  596. var errStr = "IO error has occurred "
  597. let sslErr = ErrPeekLastError()
  598. if sslErr == 0 and err == 0:
  599. errStr.add "because an EOF was observed that violates the protocol"
  600. elif sslErr == 0 and err == -1:
  601. errStr.add "in the BIO layer"
  602. else:
  603. let errStr = $ErrErrorString(sslErr, nil)
  604. raiseSSLError(errStr & ": " & errStr)
  605. let osErr = osLastError()
  606. raiseOSError(osErr, errStr)
  607. of SSL_ERROR_SSL:
  608. raiseSSLError()
  609. else: raiseSSLError("Unknown Error")
  610. if err == -1 and not (when defineSsl: socket.isSSL else: false):
  611. var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
  612. if async:
  613. when useWinVersion:
  614. if lastE.int32 == WSAEWOULDBLOCK:
  615. return
  616. else: raiseOSError(lastE)
  617. else:
  618. if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK:
  619. return
  620. else: raiseOSError(lastE)
  621. else: raiseOSError(lastE)
  622. proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
  623. ## Marks ``socket`` as accepting connections.
  624. ## ``Backlog`` specifies the maximum length of the
  625. ## queue of pending connections.
  626. ##
  627. ## Raises an EOS error upon failure.
  628. if nativesockets.listen(socket.fd, backlog) < 0'i32:
  629. raiseOSError(osLastError())
  630. proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
  631. tags: [ReadIOEffect].} =
  632. ## Binds ``address``:``port`` to the socket.
  633. ##
  634. ## If ``address`` is "" then ADDR_ANY will be bound.
  635. if address == "":
  636. var name: Sockaddr_in
  637. when useWinVersion:
  638. name.sin_family = toInt(AF_INET).int16
  639. else:
  640. name.sin_family = toInt(AF_INET)
  641. name.sin_port = htons(port.uint16)
  642. name.sin_addr.s_addr = htonl(INADDR_ANY)
  643. if bindAddr(socket.fd, cast[ptr SockAddr](addr(name)),
  644. sizeof(name).SockLen) < 0'i32:
  645. raiseOSError(osLastError())
  646. else:
  647. var aiList = getAddrInfo(address, port, socket.domain)
  648. if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
  649. freeAddrInfo(aiList)
  650. raiseOSError(osLastError())
  651. freeAddrInfo(aiList)
  652. proc acceptAddr*(server: Socket, client: var Socket, address: var string,
  653. flags = {SocketFlag.SafeDisconn}) {.
  654. tags: [ReadIOEffect], gcsafe, locks: 0.} =
  655. ## Blocks until a connection is being made from a client. When a connection
  656. ## is made sets ``client`` to the client socket and ``address`` to the address
  657. ## of the connecting client.
  658. ## This function will raise EOS if an error occurs.
  659. ##
  660. ## The resulting client will inherit any properties of the server socket. For
  661. ## example: whether the socket is buffered or not.
  662. ##
  663. ## **Note**: ``client`` must be initialised (with ``new``), this function
  664. ## makes no effort to initialise the ``client`` variable.
  665. ##
  666. ## The ``accept`` call may result in an error if the connecting socket
  667. ## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
  668. ## flag is specified then this error will not be raised and instead
  669. ## accept will be called again.
  670. assert(client != nil)
  671. var sockAddress: Sockaddr_in
  672. var addrLen = sizeof(sockAddress).SockLen
  673. var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)),
  674. addr(addrLen))
  675. if sock == osInvalidSocket:
  676. let err = osLastError()
  677. if flags.isDisconnectionError(err):
  678. acceptAddr(server, client, address, flags)
  679. raiseOSError(err)
  680. else:
  681. client.fd = sock
  682. client.isBuffered = server.isBuffered
  683. # Handle SSL.
  684. when defineSsl:
  685. if server.isSSL:
  686. # We must wrap the client sock in a ssl context.
  687. server.sslContext.wrapSocket(client)
  688. let ret = SSLAccept(client.sslHandle)
  689. socketError(client, ret, false)
  690. # Client socket is set above.
  691. address = $inet_ntoa(sockAddress.sin_addr)
  692. when false: #defineSsl:
  693. proc acceptAddrSSL*(server: Socket, client: var Socket,
  694. address: var string): SSLAcceptResult {.
  695. tags: [ReadIOEffect].} =
  696. ## This procedure should only be used for non-blocking **SSL** sockets.
  697. ## It will immediately return with one of the following values:
  698. ##
  699. ## ``AcceptSuccess`` will be returned when a client has been successfully
  700. ## accepted and the handshake has been successfully performed between
  701. ## ``server`` and the newly connected client.
  702. ##
  703. ## ``AcceptNoHandshake`` will be returned when a client has been accepted
  704. ## but no handshake could be performed. This can happen when the client
  705. ## connects but does not yet initiate a handshake. In this case
  706. ## ``acceptAddrSSL`` should be called again with the same parameters.
  707. ##
  708. ## ``AcceptNoClient`` will be returned when no client is currently attempting
  709. ## to connect.
  710. template doHandshake(): untyped =
  711. when defineSsl:
  712. if server.isSSL:
  713. client.setBlocking(false)
  714. # We must wrap the client sock in a ssl context.
  715. if not client.isSSL or client.sslHandle == nil:
  716. server.sslContext.wrapSocket(client)
  717. let ret = SSLAccept(client.sslHandle)
  718. while ret <= 0:
  719. let err = SSLGetError(client.sslHandle, ret)
  720. if err != SSL_ERROR_WANT_ACCEPT:
  721. case err
  722. of SSL_ERROR_ZERO_RETURN:
  723. raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  724. of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
  725. SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  726. client.sslNoHandshake = true
  727. return AcceptNoHandshake
  728. of SSL_ERROR_WANT_X509_LOOKUP:
  729. raiseSSLError("Function for x509 lookup has been called.")
  730. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  731. raiseSSLError()
  732. else:
  733. raiseSSLError("Unknown error")
  734. client.sslNoHandshake = false
  735. if client.isSSL and client.sslNoHandshake:
  736. doHandshake()
  737. return AcceptSuccess
  738. else:
  739. acceptAddrPlain(AcceptNoClient, AcceptSuccess):
  740. doHandshake()
  741. proc accept*(server: Socket, client: var Socket,
  742. flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} =
  743. ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
  744. ## socket.
  745. ##
  746. ## **Note**: ``client`` must be initialised (with ``new``), this function
  747. ## makes no effort to initialise the ``client`` variable.
  748. ##
  749. ## The ``accept`` call may result in an error if the connecting socket
  750. ## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
  751. ## flag is specified then this error will not be raised and instead
  752. ## accept will be called again.
  753. var addrDummy = ""
  754. acceptAddr(server, client, addrDummy, flags)
  755. proc close*(socket: Socket) =
  756. ## Closes a socket.
  757. try:
  758. when defineSsl:
  759. if socket.isSSL and socket.sslHandle != nil:
  760. ErrClearError()
  761. # As we are closing the underlying socket immediately afterwards,
  762. # it is valid, under the TLS standard, to perform a unidirectional
  763. # shutdown i.e not wait for the peers "close notify" alert with a second
  764. # call to SSLShutdown
  765. let res = SSLShutdown(socket.sslHandle)
  766. SSLFree(socket.sslHandle)
  767. socket.sslHandle = nil
  768. if res == 0:
  769. discard
  770. elif res != 1:
  771. socketError(socket, res)
  772. finally:
  773. socket.fd.close()
  774. proc toCInt*(opt: SOBool): cint =
  775. ## Converts a ``SOBool`` into its Socket Option cint representation.
  776. case opt
  777. of OptAcceptConn: SO_ACCEPTCONN
  778. of OptBroadcast: SO_BROADCAST
  779. of OptDebug: SO_DEBUG
  780. of OptDontRoute: SO_DONTROUTE
  781. of OptKeepAlive: SO_KEEPALIVE
  782. of OptOOBInline: SO_OOBINLINE
  783. of OptReuseAddr: SO_REUSEADDR
  784. of OptReusePort: SO_REUSEPORT
  785. proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {.
  786. tags: [ReadIOEffect].} =
  787. ## Retrieves option ``opt`` as a boolean value.
  788. var res = getSockOptInt(socket.fd, cint(level), toCInt(opt))
  789. result = res != 0
  790. proc getLocalAddr*(socket: Socket): (string, Port) =
  791. ## Get the socket's local address and port number.
  792. ##
  793. ## This is high-level interface for `getsockname`:idx:.
  794. getLocalAddr(socket.fd, socket.domain)
  795. proc getPeerAddr*(socket: Socket): (string, Port) =
  796. ## Get the socket's peer address and port number.
  797. ##
  798. ## This is high-level interface for `getpeername`:idx:.
  799. getPeerAddr(socket.fd, socket.domain)
  800. proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {.
  801. tags: [WriteIOEffect].} =
  802. ## Sets option ``opt`` to a boolean value specified by ``value``.
  803. var valuei = cint(if value: 1 else: 0)
  804. setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
  805. when defined(posix) and not defined(nimdoc):
  806. proc makeUnixAddr(path: string): Sockaddr_un =
  807. result.sun_family = AF_UNIX.toInt
  808. if path.len >= Sockaddr_un_path_length:
  809. raise newException(ValueError, "socket path too long")
  810. copyMem(addr result.sun_path, path.cstring, path.len + 1)
  811. when defined(posix):
  812. proc connectUnix*(socket: Socket, path: string) =
  813. ## Connects to Unix socket on `path`.
  814. ## This only works on Unix-style systems: Mac OS X, BSD and Linux
  815. when not defined(nimdoc):
  816. var socketAddr = makeUnixAddr(path)
  817. if socket.fd.connect(cast[ptr SockAddr](addr socketAddr),
  818. sizeof(socketAddr).Socklen) != 0'i32:
  819. raiseOSError(osLastError())
  820. proc bindUnix*(socket: Socket, path: string) =
  821. ## Binds Unix socket to `path`.
  822. ## This only works on Unix-style systems: Mac OS X, BSD and Linux
  823. when not defined(nimdoc):
  824. var socketAddr = makeUnixAddr(path)
  825. if socket.fd.bindAddr(cast[ptr SockAddr](addr socketAddr),
  826. sizeof(socketAddr).Socklen) != 0'i32:
  827. raiseOSError(osLastError())
  828. when defined(ssl):
  829. proc handshake*(socket: Socket): bool
  830. {.tags: [ReadIOEffect, WriteIOEffect], deprecated.} =
  831. ## This proc needs to be called on a socket after it connects. This is
  832. ## only applicable when using ``connectAsync``.
  833. ## This proc performs the SSL handshake.
  834. ##
  835. ## Returns ``False`` whenever the socket is not yet ready for a handshake,
  836. ## ``True`` whenever handshake completed successfully.
  837. ##
  838. ## A ESSL error is raised on any other errors.
  839. ##
  840. ## **Note:** This procedure is deprecated since version 0.14.0.
  841. result = true
  842. if socket.isSSL:
  843. var ret = SSLConnect(socket.sslHandle)
  844. if ret <= 0:
  845. var errret = SSLGetError(socket.sslHandle, ret)
  846. case errret
  847. of SSL_ERROR_ZERO_RETURN:
  848. raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  849. of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
  850. SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE:
  851. return false
  852. of SSL_ERROR_WANT_X509_LOOKUP:
  853. raiseSSLError("Function for x509 lookup has been called.")
  854. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  855. raiseSSLError()
  856. else:
  857. raiseSSLError("Unknown Error")
  858. socket.sslNoHandshake = false
  859. else:
  860. raiseSSLError("Socket is not an SSL socket.")
  861. proc gotHandshake*(socket: Socket): bool =
  862. ## Determines whether a handshake has occurred between a client (``socket``)
  863. ## and the server that ``socket`` is connected to.
  864. ##
  865. ## Throws ESSL if ``socket`` is not an SSL socket.
  866. if socket.isSSL:
  867. return not socket.sslNoHandshake
  868. else:
  869. raiseSSLError("Socket is not an SSL socket.")
  870. proc hasDataBuffered*(s: Socket): bool =
  871. ## Determines whether a socket has data buffered.
  872. result = false
  873. if s.isBuffered:
  874. result = s.bufLen > 0 and s.currPos != s.bufLen
  875. when defineSsl:
  876. if s.isSSL and not result:
  877. result = s.sslHasPeekChar
  878. proc select(readfd: Socket, timeout = 500): int =
  879. ## Used for socket operation timeouts.
  880. if readfd.hasDataBuffered:
  881. return 1
  882. var fds = @[readfd.fd]
  883. result = select(fds, timeout)
  884. proc readIntoBuf(socket: Socket, flags: int32): int =
  885. result = 0
  886. when defineSsl:
  887. if socket.isSSL:
  888. result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
  889. else:
  890. result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
  891. else:
  892. result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
  893. if result < 0:
  894. # Save it in case it gets reset (the Nim codegen occasionally may call
  895. # Win API functions which reset it).
  896. socket.lastError = osLastError()
  897. if result <= 0:
  898. socket.bufLen = 0
  899. socket.currPos = 0
  900. return result
  901. socket.bufLen = result
  902. socket.currPos = 0
  903. template retRead(flags, readBytes: int) {.dirty.} =
  904. let res = socket.readIntoBuf(flags.int32)
  905. if res <= 0:
  906. if readBytes > 0:
  907. return readBytes
  908. else:
  909. return res
  910. proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect].} =
  911. ## Receives data from a socket.
  912. ##
  913. ## **Note**: This is a low-level function, you may be interested in the higher
  914. ## level versions of this function which are also named ``recv``.
  915. if size == 0: return
  916. if socket.isBuffered:
  917. if socket.bufLen == 0:
  918. retRead(0'i32, 0)
  919. var read = 0
  920. while read < size:
  921. if socket.currPos >= socket.bufLen:
  922. retRead(0'i32, read)
  923. let chunk = min(socket.bufLen-socket.currPos, size-read)
  924. var d = cast[cstring](data)
  925. assert size-read >= chunk
  926. copyMem(addr(d[read]), addr(socket.buffer[socket.currPos]), chunk)
  927. read.inc(chunk)
  928. socket.currPos.inc(chunk)
  929. result = read
  930. else:
  931. when defineSsl:
  932. if socket.isSSL:
  933. if socket.sslHasPeekChar:
  934. copyMem(data, addr(socket.sslPeekChar), 1)
  935. socket.sslHasPeekChar = false
  936. if size-1 > 0:
  937. var d = cast[cstring](data)
  938. result = SSLRead(socket.sslHandle, addr(d[1]), size-1) + 1
  939. else:
  940. result = 1
  941. else:
  942. result = SSLRead(socket.sslHandle, data, size)
  943. else:
  944. result = recv(socket.fd, data, size.cint, 0'i32)
  945. else:
  946. result = recv(socket.fd, data, size.cint, 0'i32)
  947. if result < 0:
  948. # Save the error in case it gets reset.
  949. socket.lastError = osLastError()
  950. proc waitFor(socket: Socket, waited: var float, timeout, size: int,
  951. funcName: string): int {.tags: [TimeEffect].} =
  952. ## determines the amount of characters that can be read. Result will never
  953. ## be larger than ``size``. For unbuffered sockets this will be ``1``.
  954. ## For buffered sockets it can be as big as ``BufferSize``.
  955. ##
  956. ## If this function does not determine that there is data on the socket
  957. ## within ``timeout`` ms, an ETimeout error will be raised.
  958. result = 1
  959. if size <= 0: assert false
  960. if timeout == -1: return size
  961. if socket.isBuffered and socket.bufLen != 0 and socket.bufLen != socket.currPos:
  962. result = socket.bufLen - socket.currPos
  963. result = min(result, size)
  964. else:
  965. if timeout - int(waited * 1000.0) < 1:
  966. raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
  967. when defineSsl:
  968. if socket.isSSL:
  969. if socket.hasDataBuffered:
  970. # sslPeekChar is present.
  971. return 1
  972. let sslPending = SSLPending(socket.sslHandle)
  973. if sslPending != 0:
  974. return sslPending
  975. var startTime = epochTime()
  976. let selRet = select(socket, timeout - int(waited * 1000.0))
  977. if selRet < 0: raiseOSError(osLastError())
  978. if selRet != 1:
  979. raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
  980. waited += (epochTime() - startTime)
  981. proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
  982. tags: [ReadIOEffect, TimeEffect].} =
  983. ## overload with a ``timeout`` parameter in milliseconds.
  984. var waited = 0.0 # number of seconds already waited
  985. var read = 0
  986. while read < size:
  987. let avail = waitFor(socket, waited, timeout, size-read, "recv")
  988. var d = cast[cstring](data)
  989. assert avail <= size-read
  990. result = recv(socket, addr(d[read]), avail)
  991. if result == 0: break
  992. if result < 0:
  993. return result
  994. inc(read, result)
  995. result = read
  996. proc recv*(socket: Socket, data: var string, size: int, timeout = -1,
  997. flags = {SocketFlag.SafeDisconn}): int =
  998. ## Higher-level version of ``recv``.
  999. ##
  1000. ## When 0 is returned the socket's connection has been closed.
  1001. ##
  1002. ## This function will throw an EOS exception when an error occurs. A value
  1003. ## lower than 0 is never returned.
  1004. ##
  1005. ## A timeout may be specified in milliseconds, if enough data is not received
  1006. ## within the time specified an ETimeout exception will be raised.
  1007. ##
  1008. ## **Note**: ``data`` must be initialised.
  1009. ##
  1010. ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
  1011. data.setLen(size)
  1012. result = recv(socket, cstring(data), size, timeout)
  1013. if result < 0:
  1014. data.setLen(0)
  1015. let lastError = getSocketError(socket)
  1016. if flags.isDisconnectionError(lastError): return
  1017. socket.socketError(result, lastError = lastError)
  1018. data.setLen(result)
  1019. proc recv*(socket: Socket, size: int, timeout = -1,
  1020. flags = {SocketFlag.SafeDisconn}): string {.inline.} =
  1021. ## Higher-level version of ``recv`` which returns a string.
  1022. ##
  1023. ## When ``""`` is returned the socket's connection has been closed.
  1024. ##
  1025. ## This function will throw an EOS exception when an error occurs.
  1026. ##
  1027. ## A timeout may be specified in milliseconds, if enough data is not received
  1028. ## within the time specified an ETimeout exception will be raised.
  1029. ##
  1030. ##
  1031. ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
  1032. result = newString(size)
  1033. discard recv(socket, result, size, timeout, flags)
  1034. proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
  1035. if socket.isBuffered:
  1036. result = 1
  1037. if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
  1038. var res = socket.readIntoBuf(0'i32)
  1039. if res <= 0:
  1040. result = res
  1041. c = socket.buffer[socket.currPos]
  1042. else:
  1043. when defineSsl:
  1044. if socket.isSSL:
  1045. if not socket.sslHasPeekChar:
  1046. result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
  1047. socket.sslHasPeekChar = true
  1048. c = socket.sslPeekChar
  1049. return
  1050. result = recv(socket.fd, addr(c), 1, MSG_PEEK)
  1051. proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
  1052. flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {.
  1053. tags: [ReadIOEffect, TimeEffect].} =
  1054. ## Reads a line of data from ``socket``.
  1055. ##
  1056. ## If a full line is read ``\r\L`` is not
  1057. ## added to ``line``, however if solely ``\r\L`` is read then ``line``
  1058. ## will be set to it.
  1059. ##
  1060. ## If the socket is disconnected, ``line`` will be set to ``""``.
  1061. ##
  1062. ## An EOS exception will be raised in the case of a socket error.
  1063. ##
  1064. ## A timeout can be specified in milliseconds, if data is not received within
  1065. ## the specified time an ETimeout exception will be raised.
  1066. ##
  1067. ## The ``maxLength`` parameter determines the maximum amount of characters
  1068. ## that can be read. The result is truncated after that.
  1069. ##
  1070. ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
  1071. template addNLIfEmpty() =
  1072. if line.len == 0:
  1073. line.string.add("\c\L")
  1074. template raiseSockError() {.dirty.} =
  1075. let lastError = getSocketError(socket)
  1076. if flags.isDisconnectionError(lastError): setLen(line.string, 0); return
  1077. socket.socketError(n, lastError = lastError)
  1078. var waited = 0.0
  1079. setLen(line.string, 0)
  1080. while true:
  1081. var c: char
  1082. discard waitFor(socket, waited, timeout, 1, "readLine")
  1083. var n = recv(socket, addr(c), 1)
  1084. if n < 0: raiseSockError()
  1085. elif n == 0: setLen(line.string, 0); return
  1086. if c == '\r':
  1087. discard waitFor(socket, waited, timeout, 1, "readLine")
  1088. n = peekChar(socket, c)
  1089. if n > 0 and c == '\L':
  1090. discard recv(socket, addr(c), 1)
  1091. elif n <= 0: raiseSockError()
  1092. addNLIfEmpty()
  1093. return
  1094. elif c == '\L':
  1095. addNLIfEmpty()
  1096. return
  1097. add(line.string, c)
  1098. # Verify that this isn't a DOS attack: #3847.
  1099. if line.string.len > maxLength: break
  1100. proc recvLine*(socket: Socket, timeout = -1,
  1101. flags = {SocketFlag.SafeDisconn},
  1102. maxLength = MaxLineLength): TaintedString =
  1103. ## Reads a line of data from ``socket``.
  1104. ##
  1105. ## If a full line is read ``\r\L`` is not
  1106. ## added to the result, however if solely ``\r\L`` is read then the result
  1107. ## will be set to it.
  1108. ##
  1109. ## If the socket is disconnected, the result will be set to ``""``.
  1110. ##
  1111. ## An EOS exception will be raised in the case of a socket error.
  1112. ##
  1113. ## A timeout can be specified in milliseconds, if data is not received within
  1114. ## the specified time an ETimeout exception will be raised.
  1115. ##
  1116. ## The ``maxLength`` parameter determines the maximum amount of characters
  1117. ## that can be read. The result is truncated after that.
  1118. ##
  1119. ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
  1120. result = ""
  1121. readLine(socket, result, timeout, flags, maxLength)
  1122. proc recvFrom*(socket: Socket, data: var string, length: int,
  1123. address: var string, port: var Port, flags = 0'i32): int {.
  1124. tags: [ReadIOEffect].} =
  1125. ## Receives data from ``socket``. This function should normally be used with
  1126. ## connection-less sockets (UDP sockets).
  1127. ##
  1128. ## If an error occurs an EOS exception will be raised. Otherwise the return
  1129. ## value will be the length of data received.
  1130. ##
  1131. ## **Warning:** This function does not yet have a buffered implementation,
  1132. ## so when ``socket`` is buffered the non-buffered implementation will be
  1133. ## used. Therefore if ``socket`` contains something in its buffer this
  1134. ## function will make no effort to return it.
  1135. # TODO: Buffered sockets
  1136. data.setLen(length)
  1137. var sockAddress: Sockaddr_in
  1138. var addrLen = sizeof(sockAddress).SockLen
  1139. result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
  1140. cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
  1141. if result != -1:
  1142. data.setLen(result)
  1143. address = $inet_ntoa(sockAddress.sin_addr)
  1144. port = ntohs(sockAddress.sin_port).Port
  1145. else:
  1146. raiseOSError(osLastError())
  1147. proc skip*(socket: Socket, size: int, timeout = -1) =
  1148. ## Skips ``size`` amount of bytes.
  1149. ##
  1150. ## An optional timeout can be specified in milliseconds, if skipping the
  1151. ## bytes takes longer than specified an ETimeout exception will be raised.
  1152. ##
  1153. ## Returns the number of skipped bytes.
  1154. var waited = 0.0
  1155. var dummy = alloc(size)
  1156. var bytesSkipped = 0
  1157. while bytesSkipped != size:
  1158. let avail = waitFor(socket, waited, timeout, size-bytesSkipped, "skip")
  1159. bytesSkipped += recv(socket, dummy, avail)
  1160. dealloc(dummy)
  1161. proc send*(socket: Socket, data: pointer, size: int): int {.
  1162. tags: [WriteIOEffect].} =
  1163. ## Sends data to a socket.
  1164. ##
  1165. ## **Note**: This is a low-level version of ``send``. You likely should use
  1166. ## the version below.
  1167. when defineSsl:
  1168. if socket.isSSL:
  1169. return SSLWrite(socket.sslHandle, cast[cstring](data), size)
  1170. when useWinVersion or defined(macosx):
  1171. result = send(socket.fd, data, size.cint, 0'i32)
  1172. else:
  1173. when defined(solaris):
  1174. const MSG_NOSIGNAL = 0
  1175. result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
  1176. proc send*(socket: Socket, data: string,
  1177. flags = {SocketFlag.SafeDisconn}) {.tags: [WriteIOEffect].} =
  1178. ## sends data to a socket.
  1179. let sent = send(socket, cstring(data), data.len)
  1180. if sent < 0:
  1181. let lastError = osLastError()
  1182. if flags.isDisconnectionError(lastError): return
  1183. socketError(socket, lastError = lastError)
  1184. if sent != data.len:
  1185. raiseOSError(osLastError(), "Could not send all data.")
  1186. template `&=`*(socket: Socket; data: typed) =
  1187. ## an alias for 'send'.
  1188. send(socket, data)
  1189. proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
  1190. ## Safe alternative to ``send``. Does not raise an EOS when an error occurs,
  1191. ## and instead returns ``false`` on failure.
  1192. result = send(socket, cstring(data), data.len) == data.len
  1193. proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
  1194. size: int, af: Domain = AF_INET, flags = 0'i32): int {.
  1195. tags: [WriteIOEffect].} =
  1196. ## This proc sends ``data`` to the specified ``address``,
  1197. ## which may be an IP address or a hostname, if a hostname is specified
  1198. ## this function will try each IP of that hostname.
  1199. ##
  1200. ##
  1201. ## **Note:** You may wish to use the high-level version of this function
  1202. ## which is defined below.
  1203. ##
  1204. ## **Note:** This proc is not available for SSL sockets.
  1205. var aiList = getAddrInfo(address, port, af)
  1206. # try all possibilities:
  1207. var success = false
  1208. var it = aiList
  1209. while it != nil:
  1210. result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
  1211. it.ai_addrlen.SockLen)
  1212. if result != -1'i32:
  1213. success = true
  1214. break
  1215. it = it.ai_next
  1216. freeAddrInfo(aiList)
  1217. proc sendTo*(socket: Socket, address: string, port: Port,
  1218. data: string): int {.tags: [WriteIOEffect].} =
  1219. ## This proc sends ``data`` to the specified ``address``,
  1220. ## which may be an IP address or a hostname, if a hostname is specified
  1221. ## this function will try each IP of that hostname.
  1222. ##
  1223. ## This is the high-level version of the above ``sendTo`` function.
  1224. result = socket.sendTo(address, port, cstring(data), data.len)
  1225. proc isSsl*(socket: Socket): bool =
  1226. ## Determines whether ``socket`` is a SSL socket.
  1227. when defineSsl:
  1228. result = socket.isSSL
  1229. else:
  1230. result = false
  1231. proc getFd*(socket: Socket): SocketHandle = return socket.fd
  1232. ## Returns the socket's file descriptor
  1233. proc IPv4_any*(): IpAddress =
  1234. ## Returns the IPv4 any address, which can be used to listen on all available
  1235. ## network adapters
  1236. result = IpAddress(
  1237. family: IpAddressFamily.IPv4,
  1238. address_v4: [0'u8, 0, 0, 0])
  1239. proc IPv4_loopback*(): IpAddress =
  1240. ## Returns the IPv4 loopback address (127.0.0.1)
  1241. result = IpAddress(
  1242. family: IpAddressFamily.IPv4,
  1243. address_v4: [127'u8, 0, 0, 1])
  1244. proc IPv4_broadcast*(): IpAddress =
  1245. ## Returns the IPv4 broadcast address (255.255.255.255)
  1246. result = IpAddress(
  1247. family: IpAddressFamily.IPv4,
  1248. address_v4: [255'u8, 255, 255, 255])
  1249. proc IPv6_any*(): IpAddress =
  1250. ## Returns the IPv6 any address (::0), which can be used
  1251. ## to listen on all available network adapters
  1252. result = IpAddress(
  1253. family: IpAddressFamily.IPv6,
  1254. address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
  1255. proc IPv6_loopback*(): IpAddress =
  1256. ## Returns the IPv6 loopback address (::1)
  1257. result = IpAddress(
  1258. family: IpAddressFamily.IPv6,
  1259. address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
  1260. proc `==`*(lhs, rhs: IpAddress): bool =
  1261. ## Compares two IpAddresses for Equality. Returns true if the addresses are equal
  1262. if lhs.family != rhs.family: return false
  1263. if lhs.family == IpAddressFamily.IPv4:
  1264. for i in low(lhs.address_v4) .. high(lhs.address_v4):
  1265. if lhs.address_v4[i] != rhs.address_v4[i]: return false
  1266. else: # IPv6
  1267. for i in low(lhs.address_v6) .. high(lhs.address_v6):
  1268. if lhs.address_v6[i] != rhs.address_v6[i]: return false
  1269. return true
  1270. proc `$`*(address: IpAddress): string =
  1271. ## Converts an IpAddress into the textual representation
  1272. result = ""
  1273. case address.family
  1274. of IpAddressFamily.IPv4:
  1275. for i in 0 .. 3:
  1276. if i != 0:
  1277. result.add('.')
  1278. result.add($address.address_v4[i])
  1279. of IpAddressFamily.IPv6:
  1280. var
  1281. currentZeroStart = -1
  1282. currentZeroCount = 0
  1283. biggestZeroStart = -1
  1284. biggestZeroCount = 0
  1285. # Look for the largest block of zeros
  1286. for i in 0..7:
  1287. var isZero = address.address_v6[i*2] == 0 and address.address_v6[i*2+1] == 0
  1288. if isZero:
  1289. if currentZeroStart == -1:
  1290. currentZeroStart = i
  1291. currentZeroCount = 1
  1292. else:
  1293. currentZeroCount.inc()
  1294. if currentZeroCount > biggestZeroCount:
  1295. biggestZeroCount = currentZeroCount
  1296. biggestZeroStart = currentZeroStart
  1297. else:
  1298. currentZeroStart = -1
  1299. if biggestZeroCount == 8: # Special case ::0
  1300. result.add("::")
  1301. else: # Print address
  1302. var printedLastGroup = false
  1303. for i in 0..7:
  1304. var word:uint16 = (cast[uint16](address.address_v6[i*2])) shl 8
  1305. word = word or cast[uint16](address.address_v6[i*2+1])
  1306. if biggestZeroCount != 0 and # Check if group is in skip group
  1307. (i >= biggestZeroStart and i < (biggestZeroStart + biggestZeroCount)):
  1308. if i == biggestZeroStart: # skip start
  1309. result.add("::")
  1310. printedLastGroup = false
  1311. else:
  1312. if printedLastGroup:
  1313. result.add(':')
  1314. var
  1315. afterLeadingZeros = false
  1316. mask = 0xF000'u16
  1317. for j in 0'u16..3'u16:
  1318. var val = (mask and word) shr (4'u16*(3'u16-j))
  1319. if val != 0 or afterLeadingZeros:
  1320. if val < 0xA:
  1321. result.add(chr(uint16(ord('0'))+val))
  1322. else: # val >= 0xA
  1323. result.add(chr(uint16(ord('a'))+val-0xA))
  1324. afterLeadingZeros = true
  1325. mask = mask shr 4
  1326. printedLastGroup = true
  1327. proc dial*(address: string, port: Port,
  1328. protocol = IPPROTO_TCP, buffered = true): Socket
  1329. {.tags: [ReadIOEffect, WriteIOEffect].} =
  1330. ## Establishes connection to the specified ``address``:``port`` pair via the
  1331. ## specified protocol. The procedure iterates through possible
  1332. ## resolutions of the ``address`` until it succeeds, meaning that it
  1333. ## seamlessly works with both IPv4 and IPv6.
  1334. ## Returns Socket ready to send or receive data.
  1335. let sockType = protocol.toSockType()
  1336. let aiList = getAddrInfo(address, port, AF_UNSPEC, sockType, protocol)
  1337. var fdPerDomain: array[low(Domain).ord..high(Domain).ord, SocketHandle]
  1338. for i in low(fdPerDomain)..high(fdPerDomain):
  1339. fdPerDomain[i] = osInvalidSocket
  1340. template closeUnusedFds(domainToKeep = -1) {.dirty.} =
  1341. for i, fd in fdPerDomain:
  1342. if fd != osInvalidSocket and i != domainToKeep:
  1343. fd.close()
  1344. var success = false
  1345. var lastError: OSErrorCode
  1346. var it = aiList
  1347. var domain: Domain
  1348. var lastFd: SocketHandle
  1349. while it != nil:
  1350. let domainOpt = it.ai_family.toKnownDomain()
  1351. if domainOpt.isNone:
  1352. it = it.ai_next
  1353. continue
  1354. domain = domainOpt.unsafeGet()
  1355. lastFd = fdPerDomain[ord(domain)]
  1356. if lastFd == osInvalidSocket:
  1357. lastFd = newNativeSocket(domain, sockType, protocol)
  1358. if lastFd == osInvalidSocket:
  1359. # we always raise if socket creation failed, because it means a
  1360. # network system problem (e.g. not enough FDs), and not an unreachable
  1361. # address.
  1362. let err = osLastError()
  1363. freeAddrInfo(aiList)
  1364. closeUnusedFds()
  1365. raiseOSError(err)
  1366. fdPerDomain[ord(domain)] = lastFd
  1367. if connect(lastFd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
  1368. success = true
  1369. break
  1370. lastError = osLastError()
  1371. it = it.ai_next
  1372. freeAddrInfo(aiList)
  1373. closeUnusedFds(ord(domain))
  1374. if success:
  1375. result = newSocket(lastFd, domain, sockType, protocol)
  1376. elif lastError != 0.OSErrorCode:
  1377. raiseOSError(lastError)
  1378. else:
  1379. raise newException(IOError, "Couldn't resolve address: " & address)
  1380. proc connect*(socket: Socket, address: string,
  1381. port = Port(0)) {.tags: [ReadIOEffect].} =
  1382. ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
  1383. ## host name. If ``address`` is a host name, this function will try each IP
  1384. ## of that host name. ``htons`` is already performed on ``port`` so you must
  1385. ## not do it.
  1386. ##
  1387. ## If ``socket`` is an SSL socket a handshake will be automatically performed.
  1388. var aiList = getAddrInfo(address, port, socket.domain)
  1389. # try all possibilities:
  1390. var success = false
  1391. var lastError: OSErrorCode
  1392. var it = aiList
  1393. while it != nil:
  1394. if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
  1395. success = true
  1396. break
  1397. else: lastError = osLastError()
  1398. it = it.ai_next
  1399. freeAddrInfo(aiList)
  1400. if not success: raiseOSError(lastError)
  1401. when defineSsl:
  1402. if socket.isSSL:
  1403. # RFC3546 for SNI specifies that IP addresses are not allowed.
  1404. if not isIpAddress(address):
  1405. # Discard result in case OpenSSL version doesn't support SNI, or we're
  1406. # not using TLSv1+
  1407. discard SSL_set_tlsext_host_name(socket.sslHandle, address)
  1408. let ret = SSLConnect(socket.sslHandle)
  1409. socketError(socket, ret)
  1410. proc connectAsync(socket: Socket, name: string, port = Port(0),
  1411. af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
  1412. ## A variant of ``connect`` for non-blocking sockets.
  1413. ##
  1414. ## This procedure will immediately return, it will not block until a connection
  1415. ## is made. It is up to the caller to make sure the connection has been established
  1416. ## by checking (using ``select``) whether the socket is writeable.
  1417. ##
  1418. ## **Note**: For SSL sockets, the ``handshake`` procedure must be called
  1419. ## whenever the socket successfully connects to a server.
  1420. var aiList = getAddrInfo(name, port, af)
  1421. # try all possibilities:
  1422. var success = false
  1423. var lastError: OSErrorCode
  1424. var it = aiList
  1425. while it != nil:
  1426. var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen)
  1427. if ret == 0'i32:
  1428. success = true
  1429. break
  1430. else:
  1431. lastError = osLastError()
  1432. when useWinVersion:
  1433. # Windows EINTR doesn't behave same as POSIX.
  1434. if lastError.int32 == WSAEWOULDBLOCK:
  1435. success = true
  1436. break
  1437. else:
  1438. if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
  1439. success = true
  1440. break
  1441. it = it.ai_next
  1442. freeAddrInfo(aiList)
  1443. if not success: raiseOSError(lastError)
  1444. proc connect*(socket: Socket, address: string, port = Port(0),
  1445. timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} =
  1446. ## Connects to server as specified by ``address`` on port specified by ``port``.
  1447. ##
  1448. ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
  1449. ## the connection to the server to be made.
  1450. socket.fd.setBlocking(false)
  1451. socket.connectAsync(address, port, socket.domain)
  1452. var s = @[socket.fd]
  1453. if selectWrite(s, timeout) != 1:
  1454. raise newException(TimeoutError, "Call to 'connect' timed out.")
  1455. else:
  1456. when defineSsl and not defined(nimdoc):
  1457. if socket.isSSL:
  1458. socket.fd.setBlocking(true)
  1459. {.warning[Deprecated]: off.}
  1460. doAssert socket.handshake()
  1461. {.warning[Deprecated]: on.}
  1462. socket.fd.setBlocking(true)