net.nim 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173
  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. See the
  23. ## `newContext<net.html#newContext%2Cstring%2Cstring%2Cstring%2Cstring>`_
  24. ## procedure for additional details.
  25. ##
  26. ##
  27. ## SSL on Windows
  28. ## ==============
  29. ##
  30. ## On Windows the SSL library checks for valid certificates.
  31. ## It uses the `cacert.pem` file for this purpose which was extracted
  32. ## from `https://curl.se/ca/cacert.pem`. Besides
  33. ## the OpenSSL DLLs (e.g. libssl-1_1-x64.dll, libcrypto-1_1-x64.dll) you
  34. ## also need to ship `cacert.pem` with your `.exe` file.
  35. ##
  36. ##
  37. ## Examples
  38. ## ========
  39. ##
  40. ## Connecting to a server
  41. ## ----------------------
  42. ##
  43. ## After you create a socket with the `newSocket` procedure, you can easily
  44. ## connect it to a server running at a known hostname (or IP address) and port.
  45. ## To do so over TCP, use the example below.
  46. runnableExamples("-r:off"):
  47. let socket = newSocket()
  48. socket.connect("google.com", Port(80))
  49. ## For SSL, use the following example:
  50. runnableExamples("-r:off -d:ssl"):
  51. let socket = newSocket()
  52. let ctx = newContext()
  53. wrapSocket(ctx, socket)
  54. socket.connect("google.com", Port(443))
  55. ## UDP is a connectionless protocol, so UDP sockets don't have to explicitly
  56. ## call the `connect <net.html#connect%2CSocket%2Cstring>`_ procedure. They can
  57. ## simply start sending data immediately.
  58. runnableExamples("-r:off"):
  59. let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
  60. socket.sendTo("192.168.0.1", Port(27960), "status\n")
  61. when defined(zephyr):
  62. runnableExamples("-r:off"):
  63. let socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
  64. let ip = parseIpAddress("192.168.0.1")
  65. doAssert socket.sendTo(ip, Port(27960), "status\c\l") == 8
  66. ## Creating a server
  67. ## -----------------
  68. ##
  69. ## After you create a socket with the `newSocket` procedure, you can create a
  70. ## TCP server by calling the `bindAddr` and `listen` procedures.
  71. runnableExamples("-r:off"):
  72. let socket = newSocket()
  73. socket.bindAddr(Port(1234))
  74. socket.listen()
  75. # You can then begin accepting connections using the `accept` procedure.
  76. var client: Socket
  77. var address = ""
  78. while true:
  79. socket.acceptAddr(client, address)
  80. echo "Client connected from: ", address
  81. import std/private/since
  82. import nativesockets
  83. import os, strutils, times, sets, options, std/monotimes
  84. import ssl_config
  85. export nativesockets.Port, nativesockets.`$`, nativesockets.`==`
  86. export Domain, SockType, Protocol
  87. const useWinVersion = defined(windows) or defined(nimdoc)
  88. const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr)
  89. const defineSsl = defined(ssl) or defined(nimdoc)
  90. when useWinVersion:
  91. from winlean import WSAESHUTDOWN
  92. when defineSsl:
  93. import openssl
  94. when not defined(nimDisableCertificateValidation):
  95. from ssl_certs import scanSSLCertificates
  96. # Note: The enumerations are mapped to Window's constants.
  97. when defineSsl:
  98. type
  99. Certificate* = string ## DER encoded certificate
  100. SslError* = object of CatchableError
  101. SslCVerifyMode* = enum
  102. CVerifyNone, CVerifyPeer, CVerifyPeerUseEnvVars
  103. SslProtVersion* = enum
  104. protSSLv2, protSSLv3, protTLSv1, protSSLv23
  105. SslContext* = ref object
  106. context*: SslCtx
  107. referencedData: HashSet[int]
  108. extraInternal: SslContextExtraInternal
  109. SslAcceptResult* = enum
  110. AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
  111. SslHandshakeType* = enum
  112. handshakeAsClient, handshakeAsServer
  113. SslClientGetPskFunc* = proc(hint: string): tuple[identity: string, psk: string]
  114. SslServerGetPskFunc* = proc(identity: string): string
  115. SslContextExtraInternal = ref object of RootRef
  116. serverGetPskFunc: SslServerGetPskFunc
  117. clientGetPskFunc: SslClientGetPskFunc
  118. else:
  119. type
  120. SslContext* = ref object # TODO: Workaround #4797.
  121. const
  122. BufferSize*: int = 4000 ## size of a buffered socket's buffer
  123. MaxLineLength* = 1_000_000
  124. type
  125. SocketImpl* = object ## socket type
  126. fd: SocketHandle
  127. isBuffered: bool # determines whether this socket is buffered.
  128. buffer: array[0..BufferSize, char]
  129. currPos: int # current index in buffer
  130. bufLen: int # current length of buffer
  131. when defineSsl:
  132. isSsl: bool
  133. sslHandle: SslPtr
  134. sslContext: SslContext
  135. sslNoHandshake: bool # True if needs handshake.
  136. sslHasPeekChar: bool
  137. sslPeekChar: char
  138. sslNoShutdown: bool # True if shutdown shouldn't be done.
  139. lastError: OSErrorCode ## stores the last error on this socket
  140. domain: Domain
  141. sockType: SockType
  142. protocol: Protocol
  143. Socket* = ref SocketImpl
  144. SOBool* = enum ## Boolean socket options.
  145. OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
  146. OptOOBInline, OptReuseAddr, OptReusePort, OptNoDelay
  147. ReadLineResult* = enum ## result for readLineAsync
  148. ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone
  149. TimeoutError* = object of CatchableError
  150. SocketFlag* {.pure.} = enum
  151. Peek,
  152. SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown.
  153. when defined(nimHasStyleChecks):
  154. {.push styleChecks: off.}
  155. type
  156. IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
  157. IPv6, ## IPv6 address
  158. IPv4 ## IPv4 address
  159. IpAddress* = object ## stores an arbitrary IP address
  160. case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
  161. of IpAddressFamily.IPv6:
  162. address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
  163. ## case of IPv6
  164. of IpAddressFamily.IPv4:
  165. address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
  166. ## case of IPv4
  167. when defined(nimHasStyleChecks):
  168. {.pop.}
  169. when defined(posix) and not defined(lwip):
  170. from posix import TPollfd, POLLIN, POLLPRI, POLLOUT, POLLWRBAND, Tnfds
  171. template monitorPollEvent(x: var SocketHandle, y: cint, timeout: int): int =
  172. var tpollfd: TPollfd
  173. tpollfd.fd = cast[cint](x)
  174. tpollfd.events = y
  175. posix.poll(addr(tpollfd), Tnfds(1), timeout)
  176. proc timeoutRead(fd: var SocketHandle, timeout = 500): int =
  177. when defined(windows) or defined(lwip):
  178. var fds = @[fd]
  179. selectRead(fds, timeout)
  180. else:
  181. monitorPollEvent(fd, POLLIN or POLLPRI, timeout)
  182. proc timeoutWrite(fd: var SocketHandle, timeout = 500): int =
  183. when defined(windows) or defined(lwip):
  184. var fds = @[fd]
  185. selectWrite(fds, timeout)
  186. else:
  187. monitorPollEvent(fd, POLLOUT or POLLWRBAND, timeout)
  188. proc socketError*(socket: Socket, err: int = -1, async = false,
  189. lastError = (-1).OSErrorCode,
  190. flags: set[SocketFlag] = {}) {.gcsafe.}
  191. proc isDisconnectionError*(flags: set[SocketFlag],
  192. lastError: OSErrorCode): bool =
  193. ## Determines whether `lastError` is a disconnection error. Only does this
  194. ## if flags contains `SafeDisconn`.
  195. when useWinVersion:
  196. SocketFlag.SafeDisconn in flags and
  197. (lastError.int32 == WSAECONNRESET or
  198. lastError.int32 == WSAECONNABORTED or
  199. lastError.int32 == WSAENETRESET or
  200. lastError.int32 == WSAEDISCON or
  201. lastError.int32 == WSAESHUTDOWN or
  202. lastError.int32 == ERROR_NETNAME_DELETED)
  203. else:
  204. SocketFlag.SafeDisconn in flags and
  205. (lastError.int32 == ECONNRESET or
  206. lastError.int32 == EPIPE or
  207. lastError.int32 == ENETRESET)
  208. proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
  209. ## Converts the flags into the underlying OS representation.
  210. for f in socketFlags:
  211. case f
  212. of SocketFlag.Peek:
  213. result = result or MSG_PEEK
  214. of SocketFlag.SafeDisconn: continue
  215. proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET,
  216. sockType: SockType = SOCK_STREAM,
  217. protocol: Protocol = IPPROTO_TCP, buffered = true): owned(Socket) =
  218. ## Creates a new socket as specified by the params.
  219. assert fd != osInvalidSocket
  220. result = Socket(
  221. fd: fd,
  222. isBuffered: buffered,
  223. domain: domain,
  224. sockType: sockType,
  225. protocol: protocol)
  226. if buffered:
  227. result.currPos = 0
  228. # Set SO_NOSIGPIPE on OS X.
  229. when defined(macosx) and not defined(nimdoc):
  230. setSockOptInt(fd, SOL_SOCKET, SO_NOSIGPIPE, 1)
  231. proc newSocket*(domain, sockType, protocol: cint, buffered = true,
  232. inheritable = defined(nimInheritHandles)): owned(Socket) =
  233. ## Creates a new socket.
  234. ##
  235. ## The SocketHandle associated with the resulting Socket will not be
  236. ## inheritable by child processes by default. This can be changed via
  237. ## the `inheritable` parameter.
  238. ##
  239. ## If an error occurs OSError will be raised.
  240. let fd = createNativeSocket(domain, sockType, protocol, inheritable)
  241. if fd == osInvalidSocket:
  242. raiseOSError(osLastError())
  243. result = newSocket(fd, domain.Domain, sockType.SockType, protocol.Protocol,
  244. buffered)
  245. proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
  246. protocol: Protocol = IPPROTO_TCP, buffered = true,
  247. inheritable = defined(nimInheritHandles)): owned(Socket) =
  248. ## Creates a new socket.
  249. ##
  250. ## The SocketHandle associated with the resulting Socket will not be
  251. ## inheritable by child processes by default. This can be changed via
  252. ## the `inheritable` parameter.
  253. ##
  254. ## If an error occurs OSError will be raised.
  255. let fd = createNativeSocket(domain, sockType, protocol, inheritable)
  256. if fd == osInvalidSocket:
  257. raiseOSError(osLastError())
  258. result = newSocket(fd, domain, sockType, protocol, buffered)
  259. proc parseIPv4Address(addressStr: string): IpAddress =
  260. ## Parses IPv4 addresses
  261. ## Raises ValueError on errors
  262. var
  263. byteCount = 0
  264. currentByte: uint16 = 0
  265. separatorValid = false
  266. leadingZero = false
  267. result = IpAddress(family: IpAddressFamily.IPv4)
  268. for i in 0 .. high(addressStr):
  269. if addressStr[i] in strutils.Digits: # Character is a number
  270. if leadingZero:
  271. raise newException(ValueError,
  272. "Invalid IP address. Octal numbers are not allowed")
  273. currentByte = currentByte * 10 +
  274. cast[uint16](ord(addressStr[i]) - ord('0'))
  275. if currentByte == 0'u16:
  276. leadingZero = true
  277. elif currentByte > 255'u16:
  278. raise newException(ValueError,
  279. "Invalid IP Address. Value is out of range")
  280. separatorValid = true
  281. elif addressStr[i] == '.': # IPv4 address separator
  282. if not separatorValid or byteCount >= 3:
  283. raise newException(ValueError,
  284. "Invalid IP Address. The address consists of too many groups")
  285. result.address_v4[byteCount] = cast[uint8](currentByte)
  286. currentByte = 0
  287. byteCount.inc
  288. separatorValid = false
  289. leadingZero = false
  290. else:
  291. raise newException(ValueError,
  292. "Invalid IP Address. Address contains an invalid character")
  293. if byteCount != 3 or not separatorValid:
  294. raise newException(ValueError, "Invalid IP Address")
  295. result.address_v4[byteCount] = cast[uint8](currentByte)
  296. proc parseIPv6Address(addressStr: string): IpAddress =
  297. ## Parses IPv6 addresses
  298. ## Raises ValueError on errors
  299. result = IpAddress(family: IpAddressFamily.IPv6)
  300. if addressStr.len < 2:
  301. raise newException(ValueError, "Invalid IP Address")
  302. var
  303. groupCount = 0
  304. currentGroupStart = 0
  305. currentShort: uint32 = 0
  306. separatorValid = true
  307. dualColonGroup = -1
  308. lastWasColon = false
  309. v4StartPos = -1
  310. byteCount = 0
  311. for i, c in addressStr:
  312. if c == ':':
  313. if not separatorValid:
  314. raise newException(ValueError,
  315. "Invalid IP Address. Address contains an invalid separator")
  316. if lastWasColon:
  317. if dualColonGroup != -1:
  318. raise newException(ValueError,
  319. "Invalid IP Address. Address contains more than one \"::\" separator")
  320. dualColonGroup = groupCount
  321. separatorValid = false
  322. elif i != 0 and i != high(addressStr):
  323. if groupCount >= 8:
  324. raise newException(ValueError,
  325. "Invalid IP Address. The address consists of too many groups")
  326. result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
  327. result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
  328. currentShort = 0
  329. groupCount.inc()
  330. if dualColonGroup != -1: separatorValid = false
  331. elif i == 0: # only valid if address starts with ::
  332. if addressStr[1] != ':':
  333. raise newException(ValueError,
  334. "Invalid IP Address. Address may not start with \":\"")
  335. else: # i == high(addressStr) - only valid if address ends with ::
  336. if addressStr[high(addressStr)-1] != ':':
  337. raise newException(ValueError,
  338. "Invalid IP Address. Address may not end with \":\"")
  339. lastWasColon = true
  340. currentGroupStart = i + 1
  341. elif c == '.': # Switch to parse IPv4 mode
  342. if i < 3 or not separatorValid or groupCount >= 7:
  343. raise newException(ValueError, "Invalid IP Address")
  344. v4StartPos = currentGroupStart
  345. currentShort = 0
  346. separatorValid = false
  347. break
  348. elif c in strutils.HexDigits:
  349. if c in strutils.Digits: # Normal digit
  350. currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('0'))
  351. elif c >= 'a' and c <= 'f': # Lower case hex
  352. currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('a')) + 10
  353. else: # Upper case hex
  354. currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('A')) + 10
  355. if currentShort > 65535'u32:
  356. raise newException(ValueError,
  357. "Invalid IP Address. Value is out of range")
  358. lastWasColon = false
  359. separatorValid = true
  360. else:
  361. raise newException(ValueError,
  362. "Invalid IP Address. Address contains an invalid character")
  363. if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff
  364. if separatorValid: # Copy remaining data
  365. if groupCount >= 8:
  366. raise newException(ValueError,
  367. "Invalid IP Address. The address consists of too many groups")
  368. result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
  369. result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
  370. groupCount.inc()
  371. else: # Must parse IPv4 address
  372. var leadingZero = false
  373. for i, c in addressStr[v4StartPos..high(addressStr)]:
  374. if c in strutils.Digits: # Character is a number
  375. if leadingZero:
  376. raise newException(ValueError,
  377. "Invalid IP address. Octal numbers not allowed")
  378. currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
  379. if currentShort == 0'u32:
  380. leadingZero = true
  381. elif currentShort > 255'u32:
  382. raise newException(ValueError,
  383. "Invalid IP Address. Value is out of range")
  384. separatorValid = true
  385. elif c == '.': # IPv4 address separator
  386. if not separatorValid or byteCount >= 3:
  387. raise newException(ValueError, "Invalid IP Address")
  388. result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
  389. currentShort = 0
  390. byteCount.inc()
  391. separatorValid = false
  392. leadingZero = false
  393. else: # Invalid character
  394. raise newException(ValueError,
  395. "Invalid IP Address. Address contains an invalid character")
  396. if byteCount != 3 or not separatorValid:
  397. raise newException(ValueError, "Invalid IP Address")
  398. result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
  399. groupCount += 2
  400. # Shift and fill zeros in case of ::
  401. if groupCount > 8:
  402. raise newException(ValueError,
  403. "Invalid IP Address. The address consists of too many groups")
  404. elif groupCount < 8: # must fill
  405. if dualColonGroup == -1:
  406. raise newException(ValueError,
  407. "Invalid IP Address. The address consists of too few groups")
  408. var toFill = 8 - groupCount # The number of groups to fill
  409. var toShift = groupCount - dualColonGroup # Nr of known groups after ::
  410. for i in 0..2*toShift-1: # shift
  411. result.address_v6[15-i] = result.address_v6[groupCount*2-i-1]
  412. for i in 0..2*toFill-1: # fill with 0s
  413. result.address_v6[dualColonGroup*2+i] = 0
  414. elif dualColonGroup != -1:
  415. raise newException(ValueError,
  416. "Invalid IP Address. The address consists of too many groups")
  417. proc parseIpAddress*(addressStr: string): IpAddress =
  418. ## Parses an IP address
  419. ##
  420. ## Raises ValueError on error.
  421. ##
  422. ## For IPv4 addresses, only the strict form as
  423. ## defined in RFC 6943 is considered valid, see
  424. ## https://datatracker.ietf.org/doc/html/rfc6943#section-3.1.1.
  425. if addressStr.len == 0:
  426. raise newException(ValueError, "IP Address string is empty")
  427. if addressStr.contains(':'):
  428. return parseIPv6Address(addressStr)
  429. else:
  430. return parseIPv4Address(addressStr)
  431. proc isIpAddress*(addressStr: string): bool {.tags: [].} =
  432. ## Checks if a string is an IP address
  433. ## Returns true if it is, false otherwise
  434. try:
  435. discard parseIpAddress(addressStr)
  436. except ValueError:
  437. return false
  438. return true
  439. proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage,
  440. sl: var SockLen) =
  441. ## Converts `IpAddress` and `Port` to `SockAddr` and `SockLen`
  442. let port = htons(uint16(port))
  443. case address.family
  444. of IpAddressFamily.IPv4:
  445. sl = sizeof(Sockaddr_in).SockLen
  446. let s = cast[ptr Sockaddr_in](addr sa)
  447. s.sin_family = typeof(s.sin_family)(toInt(AF_INET))
  448. s.sin_port = port
  449. copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0],
  450. sizeof(s.sin_addr))
  451. of IpAddressFamily.IPv6:
  452. sl = sizeof(Sockaddr_in6).SockLen
  453. let s = cast[ptr Sockaddr_in6](addr sa)
  454. s.sin6_family = typeof(s.sin6_family)(toInt(AF_INET6))
  455. s.sin6_port = port
  456. copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0],
  457. sizeof(s.sin6_addr))
  458. proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: SockLen,
  459. address: var IpAddress, port: var Port) =
  460. if sa.ss_family.cint == toInt(AF_INET) and sl == sizeof(Sockaddr_in).SockLen:
  461. address = IpAddress(family: IpAddressFamily.IPv4)
  462. let s = cast[ptr Sockaddr_in](sa)
  463. copyMem(addr address.address_v4[0], addr s.sin_addr,
  464. sizeof(address.address_v4))
  465. port = ntohs(s.sin_port).Port
  466. elif sa.ss_family.cint == toInt(AF_INET6) and
  467. sl == sizeof(Sockaddr_in6).SockLen:
  468. address = IpAddress(family: IpAddressFamily.IPv6)
  469. let s = cast[ptr Sockaddr_in6](sa)
  470. copyMem(addr address.address_v6[0], addr s.sin6_addr,
  471. sizeof(address.address_v6))
  472. port = ntohs(s.sin6_port).Port
  473. else:
  474. raise newException(ValueError, "Neither IPv4 nor IPv6")
  475. proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6,
  476. sl: SockLen, address: var IpAddress, port: var Port) {.inline.} =
  477. ## Converts `SockAddr` and `SockLen` to `IpAddress` and `Port`. Raises
  478. ## `ObjectConversionDefect` in case of invalid `sa` and `sl` arguments.
  479. fromSockAddrAux(cast[ptr Sockaddr_storage](unsafeAddr sa), sl, address, port)
  480. when defineSsl:
  481. CRYPTO_malloc_init()
  482. doAssert SslLibraryInit() == 1
  483. SSL_load_error_strings()
  484. ERR_load_BIO_strings()
  485. OpenSSL_add_all_algorithms()
  486. proc sslHandle*(self: Socket): SslPtr =
  487. ## Retrieve the ssl pointer of `socket`.
  488. ## Useful for interfacing with `openssl`.
  489. self.sslHandle
  490. proc raiseSSLError*(s = "") =
  491. ## Raises a new SSL error.
  492. if s != "":
  493. raise newException(SslError, s)
  494. let err = ERR_peek_last_error()
  495. if err == 0:
  496. raise newException(SslError, "No error reported.")
  497. var errStr = $ERR_error_string(err, nil)
  498. case err
  499. of 336032814, 336032784:
  500. errStr = "Please upgrade your OpenSSL library, it does not support the " &
  501. "necessary protocols. OpenSSL error is: " & errStr
  502. else:
  503. discard
  504. raise newException(SslError, errStr)
  505. proc getExtraData*(ctx: SslContext, index: int): RootRef =
  506. ## Retrieves arbitrary data stored inside SslContext.
  507. if index notin ctx.referencedData:
  508. raise newException(IndexDefect, "No data with that index.")
  509. let res = ctx.context.SSL_CTX_get_ex_data(index.cint)
  510. if cast[int](res) == 0:
  511. raiseSSLError()
  512. return cast[RootRef](res)
  513. proc setExtraData*(ctx: SslContext, index: int, data: RootRef) =
  514. ## Stores arbitrary data inside SslContext. The unique `index`
  515. ## should be retrieved using getSslContextExtraDataIndex.
  516. if index in ctx.referencedData:
  517. GC_unref(getExtraData(ctx, index))
  518. if ctx.context.SSL_CTX_set_ex_data(index.cint, cast[pointer](data)) == -1:
  519. raiseSSLError()
  520. if index notin ctx.referencedData:
  521. ctx.referencedData.incl(index)
  522. GC_ref(data)
  523. # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
  524. proc loadCertificates(ctx: SslCtx, certFile, keyFile: string) =
  525. if certFile != "" and not fileExists(certFile):
  526. raise newException(system.IOError,
  527. "Certificate file could not be found: " & certFile)
  528. if keyFile != "" and not fileExists(keyFile):
  529. raise newException(system.IOError, "Key file could not be found: " & keyFile)
  530. if certFile != "":
  531. var ret = SSL_CTX_use_certificate_chain_file(ctx, certFile)
  532. if ret != 1:
  533. raiseSSLError()
  534. # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf
  535. if keyFile != "":
  536. if SSL_CTX_use_PrivateKey_file(ctx, keyFile,
  537. SSL_FILETYPE_PEM) != 1:
  538. raiseSSLError()
  539. if SSL_CTX_check_private_key(ctx) != 1:
  540. raiseSSLError("Verification of private key file failed.")
  541. proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
  542. certFile = "", keyFile = "", cipherList = CiphersIntermediate,
  543. caDir = "", caFile = ""): SslContext =
  544. ## Creates an SSL context.
  545. ##
  546. ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1
  547. ## are available with the addition of `protSSLv23` which allows for
  548. ## compatibility with all of them.
  549. ##
  550. ## There are three options for verify mode:
  551. ## `CVerifyNone`: certificates are not verified;
  552. ## `CVerifyPeer`: certificates are verified;
  553. ## `CVerifyPeerUseEnvVars`: certificates are verified and the optional
  554. ## environment variables SSL_CERT_FILE and SSL_CERT_DIR are also used to
  555. ## locate certificates
  556. ##
  557. ## The `nimDisableCertificateValidation` define overrides verifyMode and
  558. ## disables certificate verification globally!
  559. ##
  560. ## CA certificates will be loaded, in the following order, from:
  561. ##
  562. ## - caFile, caDir, parameters, if set
  563. ## - if `verifyMode` is set to `CVerifyPeerUseEnvVars`,
  564. ## the SSL_CERT_FILE and SSL_CERT_DIR environment variables are used
  565. ## - a set of files and directories from the `ssl_certs <ssl_certs.html>`_ file.
  566. ##
  567. ## The last two parameters specify the certificate file path and the key file
  568. ## path, a server socket will most likely not work without these.
  569. ##
  570. ## Certificates can be generated using the following command:
  571. ## - `openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout mykey.pem -out mycert.pem`
  572. ## or using ECDSA:
  573. ## - `openssl ecparam -out mykey.pem -name secp256k1 -genkey`
  574. ## - `openssl req -new -key mykey.pem -x509 -nodes -days 365 -out mycert.pem`
  575. var newCTX: SslCtx
  576. case protVersion
  577. of protSSLv23:
  578. newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
  579. of protSSLv2:
  580. raiseSSLError("SSLv2 is no longer secure and has been deprecated, use protSSLv23")
  581. of protSSLv3:
  582. raiseSSLError("SSLv3 is no longer secure and has been deprecated, use protSSLv23")
  583. of protTLSv1:
  584. newCTX = SSL_CTX_new(TLSv1_method())
  585. if newCTX.SSL_CTX_set_cipher_list(cipherList) != 1:
  586. raiseSSLError()
  587. when not defined(openssl10) and not defined(libressl):
  588. let sslVersion = getOpenSSLVersion()
  589. if sslVersion >= 0x010101000 and not sslVersion == 0x020000000:
  590. # In OpenSSL >= 1.1.1, TLSv1.3 cipher suites can only be configured via
  591. # this API.
  592. if newCTX.SSL_CTX_set_ciphersuites(cipherList) != 1:
  593. raiseSSLError()
  594. # Automatically the best ECDH curve for client exchange. Without this, ECDH
  595. # ciphers will be ignored by the server.
  596. #
  597. # From OpenSSL >= 1.1.0, this setting is set by default and can't be
  598. # overriden.
  599. if newCTX.SSL_CTX_set_ecdh_auto(1) != 1:
  600. raiseSSLError()
  601. when defined(nimDisableCertificateValidation):
  602. newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil)
  603. else:
  604. case verifyMode
  605. of CVerifyPeer, CVerifyPeerUseEnvVars:
  606. newCTX.SSL_CTX_set_verify(SSL_VERIFY_PEER, nil)
  607. of CVerifyNone:
  608. newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil)
  609. if newCTX == nil:
  610. raiseSSLError()
  611. discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
  612. newCTX.loadCertificates(certFile, keyFile)
  613. const VerifySuccess = 1 # SSL_CTX_load_verify_locations returns 1 on success.
  614. when not defined(nimDisableCertificateValidation):
  615. if verifyMode != CVerifyNone:
  616. # Use the caDir and caFile parameters if set
  617. if caDir != "" or caFile != "":
  618. if newCTX.SSL_CTX_load_verify_locations(if caFile == "": nil else: caFile.cstring, if caDir == "": nil else: caDir.cstring) != VerifySuccess:
  619. raise newException(IOError, "Failed to load SSL/TLS CA certificate(s).")
  620. else:
  621. # Scan for certs in known locations. For CVerifyPeerUseEnvVars also scan
  622. # the SSL_CERT_FILE and SSL_CERT_DIR env vars
  623. var found = false
  624. for fn in scanSSLCertificates():
  625. if newCTX.SSL_CTX_load_verify_locations(fn, nil) == VerifySuccess:
  626. found = true
  627. break
  628. if not found:
  629. raise newException(IOError, "No SSL/TLS CA certificates found.")
  630. result = SslContext(context: newCTX, referencedData: initHashSet[int](),
  631. extraInternal: new(SslContextExtraInternal))
  632. proc getExtraInternal(ctx: SslContext): SslContextExtraInternal =
  633. return ctx.extraInternal
  634. proc destroyContext*(ctx: SslContext) =
  635. ## Free memory referenced by SslContext.
  636. # We assume here that OpenSSL's internal indexes increase by 1 each time.
  637. # That means we can assume that the next internal index is the length of
  638. # extra data indexes.
  639. for i in ctx.referencedData:
  640. GC_unref(getExtraData(ctx, i))
  641. ctx.context.SSL_CTX_free()
  642. proc `pskIdentityHint=`*(ctx: SslContext, hint: string) =
  643. ## Sets the identity hint passed to server.
  644. ##
  645. ## Only used in PSK ciphersuites.
  646. if ctx.context.SSL_CTX_use_psk_identity_hint(hint) <= 0:
  647. raiseSSLError()
  648. proc clientGetPskFunc*(ctx: SslContext): SslClientGetPskFunc =
  649. return ctx.getExtraInternal().clientGetPskFunc
  650. proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring;
  651. max_identity_len: cuint; psk: ptr uint8;
  652. max_psk_len: cuint): cuint {.cdecl.} =
  653. let ctx = SslContext(context: ssl.SSL_get_SSL_CTX)
  654. let hintString = if hint == nil: "" else: $hint
  655. let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString)
  656. if pskString.len.cuint > max_psk_len:
  657. return 0
  658. if identityString.len.cuint >= max_identity_len:
  659. return 0
  660. copyMem(identity, identityString.cstring, identityString.len + 1) # with the last zero byte
  661. copyMem(psk, pskString.cstring, pskString.len)
  662. return pskString.len.cuint
  663. proc `clientGetPskFunc=`*(ctx: SslContext, fun: SslClientGetPskFunc) =
  664. ## Sets function that returns the client identity and the PSK based on identity
  665. ## hint from the server.
  666. ##
  667. ## Only used in PSK ciphersuites.
  668. ctx.getExtraInternal().clientGetPskFunc = fun
  669. ctx.context.SSL_CTX_set_psk_client_callback(
  670. if fun == nil: nil else: pskClientCallback)
  671. proc serverGetPskFunc*(ctx: SslContext): SslServerGetPskFunc =
  672. return ctx.getExtraInternal().serverGetPskFunc
  673. proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr uint8;
  674. max_psk_len: cint): cuint {.cdecl.} =
  675. let ctx = SslContext(context: ssl.SSL_get_SSL_CTX)
  676. let pskString = (ctx.serverGetPskFunc)($identity)
  677. if pskString.len.cint > max_psk_len:
  678. return 0
  679. copyMem(psk, pskString.cstring, pskString.len)
  680. return pskString.len.cuint
  681. proc `serverGetPskFunc=`*(ctx: SslContext, fun: SslServerGetPskFunc) =
  682. ## Sets function that returns PSK based on the client identity.
  683. ##
  684. ## Only used in PSK ciphersuites.
  685. ctx.getExtraInternal().serverGetPskFunc = fun
  686. ctx.context.SSL_CTX_set_psk_server_callback(if fun == nil: nil
  687. else: pskServerCallback)
  688. proc getPskIdentity*(socket: Socket): string =
  689. ## Gets the PSK identity provided by the client.
  690. assert socket.isSsl
  691. return $(socket.sslHandle.SSL_get_psk_identity)
  692. proc wrapSocket*(ctx: SslContext, socket: Socket) =
  693. ## Wraps a socket in an SSL context. This function effectively turns
  694. ## `socket` into an SSL socket.
  695. ##
  696. ## This must be called on an unconnected socket; an SSL session will
  697. ## be started when the socket is connected.
  698. ##
  699. ## FIXME:
  700. ## **Disclaimer**: This code is not well tested, may be very unsafe and
  701. ## prone to security vulnerabilities.
  702. assert(not socket.isSsl)
  703. socket.isSsl = true
  704. socket.sslContext = ctx
  705. socket.sslHandle = SSL_new(socket.sslContext.context)
  706. socket.sslNoHandshake = false
  707. socket.sslHasPeekChar = false
  708. socket.sslNoShutdown = false
  709. if socket.sslHandle == nil:
  710. raiseSSLError()
  711. if SSL_set_fd(socket.sslHandle, socket.fd) != 1:
  712. raiseSSLError()
  713. proc checkCertName(socket: Socket, hostname: string) =
  714. ## Check if the certificate Subject Alternative Name (SAN) or Subject CommonName (CN) matches hostname.
  715. ## Wildcards match only in the left-most label.
  716. ## When name starts with a dot it will be matched by a certificate valid for any subdomain
  717. when not defined(nimDisableCertificateValidation) and not defined(windows):
  718. assert socket.isSsl
  719. let certificate = socket.sslHandle.SSL_get_peer_certificate()
  720. if certificate.isNil:
  721. raiseSSLError("No SSL certificate found.")
  722. const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0x1.cuint
  723. # https://www.openssl.org/docs/man1.1.1/man3/X509_check_host.html
  724. let match = certificate.X509_check_host(hostname.cstring, hostname.len.cint,
  725. X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, nil)
  726. # https://www.openssl.org/docs/man1.1.1/man3/SSL_get_peer_certificate.html
  727. X509_free(certificate)
  728. if match != 1:
  729. raiseSSLError("SSL Certificate check failed.")
  730. proc wrapConnectedSocket*(ctx: SslContext, socket: Socket,
  731. handshake: SslHandshakeType,
  732. hostname: string = "") =
  733. ## Wraps a connected socket in an SSL context. This function effectively
  734. ## turns `socket` into an SSL socket.
  735. ## `hostname` should be specified so that the client knows which hostname
  736. ## the server certificate should be validated against.
  737. ##
  738. ## This should be called on a connected socket, and will perform
  739. ## an SSL handshake immediately.
  740. ##
  741. ## FIXME:
  742. ## **Disclaimer**: This code is not well tested, may be very unsafe and
  743. ## prone to security vulnerabilities.
  744. wrapSocket(ctx, socket)
  745. case handshake
  746. of handshakeAsClient:
  747. if hostname.len > 0 and not isIpAddress(hostname):
  748. # Discard result in case OpenSSL version doesn't support SNI, or we're
  749. # not using TLSv1+
  750. discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
  751. ErrClearError()
  752. let ret = SSL_connect(socket.sslHandle)
  753. socketError(socket, ret)
  754. when not defined(nimDisableCertificateValidation) and not defined(windows):
  755. if hostname.len > 0 and not isIpAddress(hostname):
  756. socket.checkCertName(hostname)
  757. of handshakeAsServer:
  758. ErrClearError()
  759. let ret = SSL_accept(socket.sslHandle)
  760. socketError(socket, ret)
  761. proc getPeerCertificates*(sslHandle: SslPtr): seq[Certificate] {.since: (1, 1).} =
  762. ## Returns the certificate chain received by the peer we are connected to
  763. ## through the OpenSSL connection represented by `sslHandle`.
  764. ## The handshake must have been completed and the certificate chain must
  765. ## have been verified successfully or else an empty sequence is returned.
  766. ## The chain is ordered from leaf certificate to root certificate.
  767. result = newSeq[Certificate]()
  768. if SSL_get_verify_result(sslHandle) != X509_V_OK:
  769. return
  770. let stack = SSL_get0_verified_chain(sslHandle)
  771. if stack == nil:
  772. return
  773. let length = OPENSSL_sk_num(stack)
  774. if length == 0:
  775. return
  776. for i in 0 .. length - 1:
  777. let x509 = cast[PX509](OPENSSL_sk_value(stack, i))
  778. result.add(i2d_X509(x509))
  779. proc getPeerCertificates*(socket: Socket): seq[Certificate] {.since: (1, 1).} =
  780. ## Returns the certificate chain received by the peer we are connected to
  781. ## through the given socket.
  782. ## The handshake must have been completed and the certificate chain must
  783. ## have been verified successfully or else an empty sequence is returned.
  784. ## The chain is ordered from leaf certificate to root certificate.
  785. if not socket.isSsl:
  786. result = newSeq[Certificate]()
  787. else:
  788. result = getPeerCertificates(socket.sslHandle)
  789. proc `sessionIdContext=`*(ctx: SslContext, sidCtx: string) =
  790. ## Sets the session id context in which a session can be reused.
  791. ## Used for permitting clients to reuse a session id instead of
  792. ## doing a new handshake.
  793. ##
  794. ## TLS clients might attempt to resume a session using the session id context,
  795. ## thus it must be set if verifyMode is set to CVerifyPeer or CVerifyPeerUseEnvVars,
  796. ## otherwise the connection will fail and SslError will be raised if resumption occurs.
  797. ##
  798. ## - Only useful if set server-side.
  799. ## - Should be unique per-application to prevent clients from malfunctioning.
  800. ## - sidCtx must be at most 32 characters in length.
  801. if sidCtx.len > 32:
  802. raiseSSLError("sessionIdContext must be shorter than 32 characters")
  803. SSL_CTX_set_session_id_context(ctx.context, sidCtx, sidCtx.len)
  804. proc getSocketError*(socket: Socket): OSErrorCode =
  805. ## Checks `osLastError` for a valid error. If it has been reset it uses
  806. ## the last error stored in the socket object.
  807. result = osLastError()
  808. if result == 0.OSErrorCode:
  809. result = socket.lastError
  810. if result == 0.OSErrorCode:
  811. raiseOSError(result, "No valid socket error code available")
  812. proc socketError*(socket: Socket, err: int = -1, async = false,
  813. lastError = (-1).OSErrorCode,
  814. flags: set[SocketFlag] = {}) =
  815. ## Raises an OSError based on the error code returned by `SSL_get_error`
  816. ## (for SSL sockets) and `osLastError` otherwise.
  817. ##
  818. ## If `async` is `true` no error will be thrown in the case when the
  819. ## error was caused by no data being available to be read.
  820. ##
  821. ## If `err` is not lower than 0 no exception will be raised.
  822. ##
  823. ## If `flags` contains `SafeDisconn`, no exception will be raised
  824. ## when the error was caused by a peer disconnection.
  825. when defineSsl:
  826. if socket.isSsl:
  827. if err <= 0:
  828. var ret = SSL_get_error(socket.sslHandle, err.cint)
  829. case ret
  830. of SSL_ERROR_ZERO_RETURN:
  831. raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  832. of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  833. if async:
  834. return
  835. else: raiseSSLError("Not enough data on socket.")
  836. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
  837. if async:
  838. return
  839. else: raiseSSLError("Not enough data on socket.")
  840. of SSL_ERROR_WANT_X509_LOOKUP:
  841. raiseSSLError("Function for x509 lookup has been called.")
  842. of SSL_ERROR_SYSCALL:
  843. # SSL shutdown must not be done if a fatal error occurred.
  844. socket.sslNoShutdown = true
  845. let osErr = osLastError()
  846. if not flags.isDisconnectionError(osErr):
  847. var errStr = "IO error has occurred "
  848. let sslErr = ERR_peek_last_error()
  849. if sslErr == 0 and err == 0:
  850. errStr.add "because an EOF was observed that violates the protocol"
  851. elif sslErr == 0 and err == -1:
  852. errStr.add "in the BIO layer"
  853. else:
  854. let errStr = $ERR_error_string(sslErr, nil)
  855. raiseSSLError(errStr & ": " & errStr)
  856. raiseOSError(osErr, errStr)
  857. of SSL_ERROR_SSL:
  858. # SSL shutdown must not be done if a fatal error occurred.
  859. socket.sslNoShutdown = true
  860. raiseSSLError()
  861. else: raiseSSLError("Unknown Error")
  862. if err == -1 and not (when defineSsl: socket.isSsl else: false):
  863. var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
  864. if not flags.isDisconnectionError(lastE):
  865. if async:
  866. when useWinVersion:
  867. if lastE.int32 == WSAEWOULDBLOCK:
  868. return
  869. else: raiseOSError(lastE)
  870. else:
  871. if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK:
  872. return
  873. else: raiseOSError(lastE)
  874. else: raiseOSError(lastE)
  875. proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
  876. ## Marks `socket` as accepting connections.
  877. ## `Backlog` specifies the maximum length of the
  878. ## queue of pending connections.
  879. ##
  880. ## Raises an OSError error upon failure.
  881. if nativesockets.listen(socket.fd, backlog) < 0'i32:
  882. raiseOSError(osLastError())
  883. proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
  884. tags: [ReadIOEffect].} =
  885. ## Binds `address`:`port` to the socket.
  886. ##
  887. ## If `address` is "" then ADDR_ANY will be bound.
  888. var realaddr = address
  889. if realaddr == "":
  890. case socket.domain
  891. of AF_INET6: realaddr = "::"
  892. of AF_INET: realaddr = "0.0.0.0"
  893. else:
  894. raise newException(ValueError,
  895. "Unknown socket address family and no address specified to bindAddr")
  896. var aiList = getAddrInfo(realaddr, port, socket.domain)
  897. if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
  898. freeAddrInfo(aiList)
  899. var address2: string
  900. address2.addQuoted address
  901. raiseOSError(osLastError(), "address: $# port: $#" % [address2, $port])
  902. freeAddrInfo(aiList)
  903. proc acceptAddr*(server: Socket, client: var owned(Socket), address: var string,
  904. flags = {SocketFlag.SafeDisconn},
  905. inheritable = defined(nimInheritHandles)) {.
  906. tags: [ReadIOEffect], gcsafe, locks: 0.} =
  907. ## Blocks until a connection is being made from a client. When a connection
  908. ## is made sets `client` to the client socket and `address` to the address
  909. ## of the connecting client.
  910. ## This function will raise OSError if an error occurs.
  911. ##
  912. ## The resulting client will inherit any properties of the server socket. For
  913. ## example: whether the socket is buffered or not.
  914. ##
  915. ## The SocketHandle associated with the resulting client will not be
  916. ## inheritable by child processes by default. This can be changed via
  917. ## the `inheritable` parameter.
  918. ##
  919. ## The `accept` call may result in an error if the connecting socket
  920. ## disconnects during the duration of the `accept`. If the `SafeDisconn`
  921. ## flag is specified then this error will not be raised and instead
  922. ## accept will be called again.
  923. if client.isNil:
  924. new(client)
  925. let ret = accept(server.fd, inheritable)
  926. let sock = ret[0]
  927. if sock == osInvalidSocket:
  928. let err = osLastError()
  929. if flags.isDisconnectionError(err):
  930. acceptAddr(server, client, address, flags, inheritable)
  931. raiseOSError(err)
  932. else:
  933. address = ret[1]
  934. client.fd = sock
  935. client.domain = getSockDomain(sock)
  936. client.isBuffered = server.isBuffered
  937. # Handle SSL.
  938. when defineSsl:
  939. if server.isSsl:
  940. # We must wrap the client sock in a ssl context.
  941. server.sslContext.wrapSocket(client)
  942. ErrClearError()
  943. let ret = SSL_accept(client.sslHandle)
  944. socketError(client, ret, false)
  945. when false: #defineSsl:
  946. proc acceptAddrSSL*(server: Socket, client: var Socket,
  947. address: var string): SSL_acceptResult {.
  948. tags: [ReadIOEffect].} =
  949. ## This procedure should only be used for non-blocking **SSL** sockets.
  950. ## It will immediately return with one of the following values:
  951. ##
  952. ## `AcceptSuccess` will be returned when a client has been successfully
  953. ## accepted and the handshake has been successfully performed between
  954. ## `server` and the newly connected client.
  955. ##
  956. ## `AcceptNoHandshake` will be returned when a client has been accepted
  957. ## but no handshake could be performed. This can happen when the client
  958. ## connects but does not yet initiate a handshake. In this case
  959. ## `acceptAddrSSL` should be called again with the same parameters.
  960. ##
  961. ## `AcceptNoClient` will be returned when no client is currently attempting
  962. ## to connect.
  963. template doHandshake(): untyped =
  964. when defineSsl:
  965. if server.isSsl:
  966. client.setBlocking(false)
  967. # We must wrap the client sock in a ssl context.
  968. if not client.isSsl or client.sslHandle == nil:
  969. server.sslContext.wrapSocket(client)
  970. ErrClearError()
  971. let ret = SSL_accept(client.sslHandle)
  972. while ret <= 0:
  973. let err = SSL_get_error(client.sslHandle, ret)
  974. if err != SSL_ERROR_WANT_ACCEPT:
  975. case err
  976. of SSL_ERROR_ZERO_RETURN:
  977. raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  978. of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
  979. SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  980. client.sslNoHandshake = true
  981. return AcceptNoHandshake
  982. of SSL_ERROR_WANT_X509_LOOKUP:
  983. raiseSSLError("Function for x509 lookup has been called.")
  984. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  985. raiseSSLError()
  986. else:
  987. raiseSSLError("Unknown error")
  988. client.sslNoHandshake = false
  989. if client.isSsl and client.sslNoHandshake:
  990. doHandshake()
  991. return AcceptSuccess
  992. else:
  993. acceptAddrPlain(AcceptNoClient, AcceptSuccess):
  994. doHandshake()
  995. proc accept*(server: Socket, client: var owned(Socket),
  996. flags = {SocketFlag.SafeDisconn},
  997. inheritable = defined(nimInheritHandles))
  998. {.tags: [ReadIOEffect].} =
  999. ## Equivalent to `acceptAddr` but doesn't return the address, only the
  1000. ## socket.
  1001. ##
  1002. ## The SocketHandle associated with the resulting client will not be
  1003. ## inheritable by child processes by default. This can be changed via
  1004. ## the `inheritable` parameter.
  1005. ##
  1006. ## The `accept` call may result in an error if the connecting socket
  1007. ## disconnects during the duration of the `accept`. If the `SafeDisconn`
  1008. ## flag is specified then this error will not be raised and instead
  1009. ## accept will be called again.
  1010. var addrDummy = ""
  1011. acceptAddr(server, client, addrDummy, flags)
  1012. when defined(posix) and not defined(lwip):
  1013. from posix import Sigset, sigwait, sigismember, sigemptyset, sigaddset,
  1014. sigprocmask, pthread_sigmask, SIGPIPE, SIG_BLOCK, SIG_UNBLOCK
  1015. template blockSigpipe(body: untyped): untyped =
  1016. ## Temporary block SIGPIPE within the provided code block. If SIGPIPE is
  1017. ## raised for the duration of the code block, it will be queued and will be
  1018. ## raised once the block ends.
  1019. ##
  1020. ## Within the block a `selectSigpipe()` template is provided which can be
  1021. ## used to remove SIGPIPE from the queue. Note that if SIGPIPE is **not**
  1022. ## raised at the time of call, it will block until SIGPIPE is raised.
  1023. ##
  1024. ## If SIGPIPE has already been blocked at the time of execution, the
  1025. ## signal mask is left as-is and `selectSigpipe()` will become a no-op.
  1026. ##
  1027. ## For convenience, this template is also available for non-POSIX system,
  1028. ## where `body` will be executed as-is.
  1029. when not defined(posix) or defined(lwip):
  1030. body
  1031. else:
  1032. template sigmask(how: cint, set, oset: var Sigset): untyped {.gensym.} =
  1033. ## Alias for pthread_sigmask or sigprocmask depending on the status
  1034. ## of --threads
  1035. when compileOption("threads"):
  1036. pthread_sigmask(how, set, oset)
  1037. else:
  1038. sigprocmask(how, set, oset)
  1039. var oldSet, watchSet: Sigset
  1040. if sigemptyset(oldSet) == -1:
  1041. raiseOSError(osLastError())
  1042. if sigemptyset(watchSet) == -1:
  1043. raiseOSError(osLastError())
  1044. if sigaddset(watchSet, SIGPIPE) == -1:
  1045. raiseOSError(osLastError(), "Couldn't add SIGPIPE to Sigset")
  1046. if sigmask(SIG_BLOCK, watchSet, oldSet) == -1:
  1047. raiseOSError(osLastError(), "Couldn't block SIGPIPE")
  1048. let alreadyBlocked = sigismember(oldSet, SIGPIPE) == 1
  1049. template selectSigpipe(): untyped {.used.} =
  1050. if not alreadyBlocked:
  1051. var signal: cint
  1052. let err = sigwait(watchSet, signal)
  1053. if err != 0:
  1054. raiseOSError(err.OSErrorCode, "Couldn't select SIGPIPE")
  1055. assert signal == SIGPIPE
  1056. try:
  1057. body
  1058. finally:
  1059. if not alreadyBlocked:
  1060. if sigmask(SIG_UNBLOCK, watchSet, oldSet) == -1:
  1061. raiseOSError(osLastError(), "Couldn't unblock SIGPIPE")
  1062. proc close*(socket: Socket, flags = {SocketFlag.SafeDisconn}) =
  1063. ## Closes a socket.
  1064. ##
  1065. ## If `socket` is an SSL/TLS socket, this proc will also send a closure
  1066. ## notification to the peer. If `SafeDisconn` is in `flags`, failure to do so
  1067. ## due to disconnections will be ignored. This is generally safe in
  1068. ## practice. See
  1069. ## `here <https://security.stackexchange.com/a/82044>`_ for more details.
  1070. try:
  1071. when defineSsl:
  1072. if socket.isSsl and socket.sslHandle != nil:
  1073. # Don't call SSL_shutdown if the connection has not been fully
  1074. # established, see:
  1075. # https://github.com/openssl/openssl/issues/710#issuecomment-253897666
  1076. if not socket.sslNoShutdown and SSL_in_init(socket.sslHandle) == 0:
  1077. # As we are closing the underlying socket immediately afterwards,
  1078. # it is valid, under the TLS standard, to perform a unidirectional
  1079. # shutdown i.e not wait for the peers "close notify" alert with a second
  1080. # call to SSL_shutdown
  1081. blockSigpipe:
  1082. ErrClearError()
  1083. let res = SSL_shutdown(socket.sslHandle)
  1084. if res == 0:
  1085. discard
  1086. elif res != 1:
  1087. let
  1088. err = osLastError()
  1089. sslError = SSL_get_error(socket.sslHandle, res)
  1090. # If a close notification is received, failures outside of the
  1091. # protocol will be returned as SSL_ERROR_ZERO_RETURN instead
  1092. # of SSL_ERROR_SYSCALL. This fact is deduced by digging into
  1093. # SSL_get_error() source code.
  1094. if sslError == SSL_ERROR_ZERO_RETURN or
  1095. sslError == SSL_ERROR_SYSCALL:
  1096. when defined(posix) and not defined(macosx) and
  1097. not defined(nimdoc):
  1098. if err == EPIPE.OSErrorCode:
  1099. # Clear the SIGPIPE that's been raised due to
  1100. # the disconnection.
  1101. selectSigpipe()
  1102. else:
  1103. discard
  1104. if not flags.isDisconnectionError(err):
  1105. socketError(socket, res, lastError = err, flags = flags)
  1106. else:
  1107. socketError(socket, res, lastError = err, flags = flags)
  1108. finally:
  1109. when defineSsl:
  1110. if socket.isSsl and socket.sslHandle != nil:
  1111. SSL_free(socket.sslHandle)
  1112. socket.sslHandle = nil
  1113. socket.fd.close()
  1114. socket.fd = osInvalidSocket
  1115. when defined(posix):
  1116. from posix import TCP_NODELAY
  1117. else:
  1118. from winlean import TCP_NODELAY
  1119. proc toCInt*(opt: SOBool): cint =
  1120. ## Converts a `SOBool` into its Socket Option cint representation.
  1121. case opt
  1122. of OptAcceptConn: SO_ACCEPTCONN
  1123. of OptBroadcast: SO_BROADCAST
  1124. of OptDebug: SO_DEBUG
  1125. of OptDontRoute: SO_DONTROUTE
  1126. of OptKeepAlive: SO_KEEPALIVE
  1127. of OptOOBInline: SO_OOBINLINE
  1128. of OptReuseAddr: SO_REUSEADDR
  1129. of OptReusePort: SO_REUSEPORT
  1130. of OptNoDelay: TCP_NODELAY
  1131. proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {.
  1132. tags: [ReadIOEffect].} =
  1133. ## Retrieves option `opt` as a boolean value.
  1134. var res = getSockOptInt(socket.fd, cint(level), toCInt(opt))
  1135. result = res != 0
  1136. proc getLocalAddr*(socket: Socket): (string, Port) =
  1137. ## Get the socket's local address and port number.
  1138. ##
  1139. ## This is high-level interface for `getsockname`:idx:.
  1140. getLocalAddr(socket.fd, socket.domain)
  1141. when not useNimNetLite:
  1142. proc getPeerAddr*(socket: Socket): (string, Port) =
  1143. ## Get the socket's peer address and port number.
  1144. ##
  1145. ## This is high-level interface for `getpeername`:idx:.
  1146. getPeerAddr(socket.fd, socket.domain)
  1147. proc setSockOpt*(socket: Socket, opt: SOBool, value: bool,
  1148. level = SOL_SOCKET) {.tags: [WriteIOEffect].} =
  1149. ## Sets option `opt` to a boolean value specified by `value`.
  1150. runnableExamples("-r:off"):
  1151. let socket = newSocket()
  1152. socket.setSockOpt(OptReusePort, true)
  1153. socket.setSockOpt(OptNoDelay, true, level = IPPROTO_TCP.cint)
  1154. var valuei = cint(if value: 1 else: 0)
  1155. setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
  1156. when defined(nimdoc) or (defined(posix) and not useNimNetLite):
  1157. proc connectUnix*(socket: Socket, path: string) =
  1158. ## Connects to Unix socket on `path`.
  1159. ## This only works on Unix-style systems: Mac OS X, BSD and Linux
  1160. when not defined(nimdoc):
  1161. var socketAddr = makeUnixAddr(path)
  1162. if socket.fd.connect(cast[ptr SockAddr](addr socketAddr),
  1163. (sizeof(socketAddr.sun_family) + path.len).SockLen) != 0'i32:
  1164. raiseOSError(osLastError())
  1165. proc bindUnix*(socket: Socket, path: string) =
  1166. ## Binds Unix socket to `path`.
  1167. ## This only works on Unix-style systems: Mac OS X, BSD and Linux
  1168. when not defined(nimdoc):
  1169. var socketAddr = makeUnixAddr(path)
  1170. if socket.fd.bindAddr(cast[ptr SockAddr](addr socketAddr),
  1171. (sizeof(socketAddr.sun_family) + path.len).SockLen) != 0'i32:
  1172. raiseOSError(osLastError())
  1173. when defined(ssl):
  1174. proc gotHandshake*(socket: Socket): bool =
  1175. ## Determines whether a handshake has occurred between a client (`socket`)
  1176. ## and the server that `socket` is connected to.
  1177. ##
  1178. ## Throws SslError if `socket` is not an SSL socket.
  1179. if socket.isSsl:
  1180. return not socket.sslNoHandshake
  1181. else:
  1182. raiseSSLError("Socket is not an SSL socket.")
  1183. proc hasDataBuffered*(s: Socket): bool =
  1184. ## Determines whether a socket has data buffered.
  1185. result = false
  1186. if s.isBuffered:
  1187. result = s.bufLen > 0 and s.currPos != s.bufLen
  1188. when defineSsl:
  1189. if s.isSsl and not result:
  1190. result = s.sslHasPeekChar
  1191. proc isClosed(socket: Socket): bool =
  1192. socket.fd == osInvalidSocket
  1193. proc uniRecv(socket: Socket, buffer: pointer, size, flags: cint): int =
  1194. ## Handles SSL and non-ssl recv in a nice package.
  1195. ##
  1196. ## In particular handles the case where socket has been closed properly
  1197. ## for both SSL and non-ssl.
  1198. result = 0
  1199. assert(not socket.isClosed, "Cannot `recv` on a closed socket")
  1200. when defineSsl:
  1201. if socket.isSsl:
  1202. ErrClearError()
  1203. return SSL_read(socket.sslHandle, buffer, size)
  1204. return recv(socket.fd, buffer, size, flags)
  1205. proc readIntoBuf(socket: Socket, flags: int32): int =
  1206. result = 0
  1207. result = uniRecv(socket, addr(socket.buffer), socket.buffer.high, flags)
  1208. if result < 0:
  1209. # Save it in case it gets reset (the Nim codegen occasionally may call
  1210. # Win API functions which reset it).
  1211. socket.lastError = osLastError()
  1212. if result <= 0:
  1213. socket.bufLen = 0
  1214. socket.currPos = 0
  1215. return result
  1216. socket.bufLen = result
  1217. socket.currPos = 0
  1218. template retRead(flags, readBytes: int) {.dirty.} =
  1219. let res = socket.readIntoBuf(flags.int32)
  1220. if res <= 0:
  1221. if readBytes > 0:
  1222. return readBytes
  1223. else:
  1224. return res
  1225. proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [
  1226. ReadIOEffect].} =
  1227. ## Receives data from a socket.
  1228. ##
  1229. ## **Note**: This is a low-level function, you may be interested in the higher
  1230. ## level versions of this function which are also named `recv`.
  1231. if size == 0: return
  1232. if socket.isBuffered:
  1233. if socket.bufLen == 0:
  1234. retRead(0'i32, 0)
  1235. var read = 0
  1236. while read < size:
  1237. if socket.currPos >= socket.bufLen:
  1238. retRead(0'i32, read)
  1239. let chunk = min(socket.bufLen-socket.currPos, size-read)
  1240. var d = cast[cstring](data)
  1241. assert size-read >= chunk
  1242. copyMem(addr(d[read]), addr(socket.buffer[socket.currPos]), chunk)
  1243. read.inc(chunk)
  1244. socket.currPos.inc(chunk)
  1245. result = read
  1246. else:
  1247. when defineSsl:
  1248. if socket.isSsl:
  1249. if socket.sslHasPeekChar: # TODO: Merge this peek char mess into uniRecv
  1250. copyMem(data, addr(socket.sslPeekChar), 1)
  1251. socket.sslHasPeekChar = false
  1252. if size-1 > 0:
  1253. var d = cast[cstring](data)
  1254. result = uniRecv(socket, addr(d[1]), cint(size-1), 0'i32) + 1
  1255. else:
  1256. result = 1
  1257. else:
  1258. result = uniRecv(socket, data, size.cint, 0'i32)
  1259. else:
  1260. result = recv(socket.fd, data, size.cint, 0'i32)
  1261. else:
  1262. result = recv(socket.fd, data, size.cint, 0'i32)
  1263. if result < 0:
  1264. # Save the error in case it gets reset.
  1265. socket.lastError = osLastError()
  1266. proc waitFor(socket: Socket, waited: var Duration, timeout, size: int,
  1267. funcName: string): int {.tags: [TimeEffect].} =
  1268. ## determines the amount of characters that can be read. Result will never
  1269. ## be larger than `size`. For unbuffered sockets this will be `1`.
  1270. ## For buffered sockets it can be as big as `BufferSize`.
  1271. ##
  1272. ## If this function does not determine that there is data on the socket
  1273. ## within `timeout` ms, a TimeoutError error will be raised.
  1274. result = 1
  1275. if size <= 0: assert false
  1276. if timeout == -1: return size
  1277. if socket.isBuffered and socket.bufLen != 0 and
  1278. socket.bufLen != socket.currPos:
  1279. result = socket.bufLen - socket.currPos
  1280. result = min(result, size)
  1281. else:
  1282. if timeout - waited.inMilliseconds < 1:
  1283. raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
  1284. when defineSsl:
  1285. if socket.isSsl:
  1286. if socket.hasDataBuffered:
  1287. # sslPeekChar is present.
  1288. return 1
  1289. let sslPending = SSL_pending(socket.sslHandle)
  1290. if sslPending != 0:
  1291. return min(sslPending, size)
  1292. var startTime = getMonoTime()
  1293. let selRet = if socket.hasDataBuffered: 1
  1294. else:
  1295. timeoutRead(socket.fd, (timeout - waited.inMilliseconds).int)
  1296. if selRet < 0: raiseOSError(osLastError())
  1297. if selRet != 1:
  1298. raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
  1299. waited += (getMonoTime() - startTime)
  1300. proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
  1301. tags: [ReadIOEffect, TimeEffect].} =
  1302. ## overload with a `timeout` parameter in milliseconds.
  1303. var waited: Duration # duration already waited
  1304. var read = 0
  1305. while read < size:
  1306. let avail = waitFor(socket, waited, timeout, size-read, "recv")
  1307. var d = cast[cstring](data)
  1308. assert avail <= size-read
  1309. result = recv(socket, addr(d[read]), avail)
  1310. if result == 0: break
  1311. if result < 0:
  1312. return result
  1313. inc(read, result)
  1314. result = read
  1315. proc recv*(socket: Socket, data: var string, size: int, timeout = -1,
  1316. flags = {SocketFlag.SafeDisconn}): int =
  1317. ## Higher-level version of `recv`.
  1318. ##
  1319. ## Reads **up to** `size` bytes from `socket` into `data`.
  1320. ##
  1321. ## For buffered sockets this function will attempt to read all the requested
  1322. ## data. It will read this data in `BufferSize` chunks.
  1323. ##
  1324. ## For unbuffered sockets this function makes no effort to read
  1325. ## all the data requested. It will return as much data as the operating system
  1326. ## gives it.
  1327. ##
  1328. ## When 0 is returned the socket's connection has been closed.
  1329. ##
  1330. ## This function will throw an OSError exception when an error occurs. A value
  1331. ## lower than 0 is never returned.
  1332. ##
  1333. ## A timeout may be specified in milliseconds, if enough data is not received
  1334. ## within the time specified a TimeoutError exception will be raised.
  1335. ##
  1336. ## .. warning:: Only the `SafeDisconn` flag is currently supported.
  1337. data.setLen(size)
  1338. result =
  1339. if timeout == -1:
  1340. recv(socket, cstring(data), size)
  1341. else:
  1342. recv(socket, cstring(data), size, timeout)
  1343. if result < 0:
  1344. data.setLen(0)
  1345. let lastError = getSocketError(socket)
  1346. socket.socketError(result, lastError = lastError, flags = flags)
  1347. else:
  1348. data.setLen(result)
  1349. proc recv*(socket: Socket, size: int, timeout = -1,
  1350. flags = {SocketFlag.SafeDisconn}): string {.inline.} =
  1351. ## Higher-level version of `recv` which returns a string.
  1352. ##
  1353. ## Reads **up to** `size` bytes from `socket` into the result.
  1354. ##
  1355. ## For buffered sockets this function will attempt to read all the requested
  1356. ## data. It will read this data in `BufferSize` chunks.
  1357. ##
  1358. ## For unbuffered sockets this function makes no effort to read
  1359. ## all the data requested. It will return as much data as the operating system
  1360. ## gives it.
  1361. ##
  1362. ## When `""` is returned the socket's connection has been closed.
  1363. ##
  1364. ## This function will throw an OSError exception when an error occurs.
  1365. ##
  1366. ## A timeout may be specified in milliseconds, if enough data is not received
  1367. ## within the time specified a TimeoutError exception will be raised.
  1368. ##
  1369. ##
  1370. ## .. warning:: Only the `SafeDisconn` flag is currently supported.
  1371. result = newString(size)
  1372. discard recv(socket, result, size, timeout, flags)
  1373. proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
  1374. if socket.isBuffered:
  1375. result = 1
  1376. if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
  1377. var res = socket.readIntoBuf(0'i32)
  1378. if res <= 0:
  1379. result = res
  1380. c = socket.buffer[socket.currPos]
  1381. else:
  1382. when defineSsl:
  1383. if socket.isSsl:
  1384. if not socket.sslHasPeekChar:
  1385. result = uniRecv(socket, addr(socket.sslPeekChar), 1, 0'i32)
  1386. socket.sslHasPeekChar = true
  1387. c = socket.sslPeekChar
  1388. return
  1389. result = recv(socket.fd, addr(c), 1, MSG_PEEK)
  1390. proc readLine*(socket: Socket, line: var string, timeout = -1,
  1391. flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {.
  1392. tags: [ReadIOEffect, TimeEffect].} =
  1393. ## Reads a line of data from `socket`.
  1394. ##
  1395. ## If a full line is read `\r\L` is not
  1396. ## added to `line`, however if solely `\r\L` is read then `line`
  1397. ## will be set to it.
  1398. ##
  1399. ## If the socket is disconnected, `line` will be set to `""`.
  1400. ##
  1401. ## An OSError exception will be raised in the case of a socket error.
  1402. ##
  1403. ## A timeout can be specified in milliseconds, if data is not received within
  1404. ## the specified time a TimeoutError exception will be raised.
  1405. ##
  1406. ## The `maxLength` parameter determines the maximum amount of characters
  1407. ## that can be read. The result is truncated after that.
  1408. ##
  1409. ## .. warning:: Only the `SafeDisconn` flag is currently supported.
  1410. template addNLIfEmpty() =
  1411. if line.len == 0:
  1412. line.add("\c\L")
  1413. template raiseSockError() {.dirty.} =
  1414. let lastError = getSocketError(socket)
  1415. if flags.isDisconnectionError(lastError):
  1416. setLen(line, 0)
  1417. socket.socketError(n, lastError = lastError, flags = flags)
  1418. return
  1419. var waited: Duration
  1420. setLen(line, 0)
  1421. while true:
  1422. var c: char
  1423. discard waitFor(socket, waited, timeout, 1, "readLine")
  1424. var n = recv(socket, addr(c), 1)
  1425. if n < 0: raiseSockError()
  1426. elif n == 0: setLen(line, 0); return
  1427. if c == '\r':
  1428. discard waitFor(socket, waited, timeout, 1, "readLine")
  1429. n = peekChar(socket, c)
  1430. if n > 0 and c == '\L':
  1431. discard recv(socket, addr(c), 1)
  1432. elif n <= 0: raiseSockError()
  1433. addNLIfEmpty()
  1434. return
  1435. elif c == '\L':
  1436. addNLIfEmpty()
  1437. return
  1438. add(line, c)
  1439. # Verify that this isn't a DOS attack: #3847.
  1440. if line.len > maxLength: break
  1441. proc recvLine*(socket: Socket, timeout = -1,
  1442. flags = {SocketFlag.SafeDisconn},
  1443. maxLength = MaxLineLength): string =
  1444. ## Reads a line of data from `socket`.
  1445. ##
  1446. ## If a full line is read `\r\L` is not
  1447. ## added to the result, however if solely `\r\L` is read then the result
  1448. ## will be set to it.
  1449. ##
  1450. ## If the socket is disconnected, the result will be set to `""`.
  1451. ##
  1452. ## An OSError exception will be raised in the case of a socket error.
  1453. ##
  1454. ## A timeout can be specified in milliseconds, if data is not received within
  1455. ## the specified time a TimeoutError exception will be raised.
  1456. ##
  1457. ## The `maxLength` parameter determines the maximum amount of characters
  1458. ## that can be read. The result is truncated after that.
  1459. ##
  1460. ## .. warning:: Only the `SafeDisconn` flag is currently supported.
  1461. result = ""
  1462. readLine(socket, result, timeout, flags, maxLength)
  1463. when defined(zephyr): # this switch is done to keep Nim 1.6 API backward compatible
  1464. proc recvFrom*[T: string | IpAddress](socket: Socket, data: var string, length: int,
  1465. address: var T, port: var Port, flags = 0'i32): int {.
  1466. tags: [ReadIOEffect].} =
  1467. ## Receives data from `socket`. This function should normally be used with
  1468. ## connection-less sockets (UDP sockets). The source address of the data
  1469. ## packet is stored in the `address` argument as either a string or an IpAddress.
  1470. ##
  1471. ## If an error occurs an OSError exception will be raised. Otherwise the return
  1472. ## value will be the length of data received.
  1473. ##
  1474. ## .. warning:: This function does not yet have a buffered implementation,
  1475. ## so when `socket` is buffered the non-buffered implementation will be
  1476. ## used. Therefore if `socket` contains something in its buffer this
  1477. ## function will make no effort to return it.
  1478. template adaptRecvFromToDomain(sockAddress: untyped, domain: Domain) =
  1479. var addrLen = sizeof(sockAddress).SockLen
  1480. result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
  1481. cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
  1482. if result != -1:
  1483. data.setLen(result)
  1484. when typeof(address) is string:
  1485. address = getAddrString(cast[ptr SockAddr](addr(sockAddress)))
  1486. when domain == AF_INET6:
  1487. port = ntohs(sockAddress.sin6_port).Port
  1488. else:
  1489. port = ntohs(sockAddress.sin_port).Port
  1490. else:
  1491. data.setLen(result)
  1492. sockAddress.fromSockAddr(addrLen, address, port)
  1493. else:
  1494. raiseOSError(osLastError())
  1495. assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket")
  1496. # TODO: Buffered sockets
  1497. data.setLen(length)
  1498. case socket.domain
  1499. of AF_INET6:
  1500. var sockAddress: Sockaddr_in6
  1501. adaptRecvFromToDomain(sockAddress, AF_INET6)
  1502. of AF_INET:
  1503. var sockAddress: Sockaddr_in
  1504. adaptRecvFromToDomain(sockAddress, AF_INET)
  1505. else:
  1506. raise newException(ValueError, "Unknown socket address family")
  1507. else:
  1508. proc recvFrom*(socket: Socket, data: var string, length: int,
  1509. address: var string, port: var Port, flags = 0'i32): int {.
  1510. tags: [ReadIOEffect].} =
  1511. ## Receives data from `socket`. This function should normally be used with
  1512. ## connection-less sockets (UDP sockets).
  1513. ##
  1514. ## If an error occurs an OSError exception will be raised. Otherwise the return
  1515. ## value will be the length of data received.
  1516. ##
  1517. ## .. warning:: This function does not yet have a buffered implementation,
  1518. ## so when `socket` is buffered the non-buffered implementation will be
  1519. ## used. Therefore if `socket` contains something in its buffer this
  1520. ## function will make no effort to return it.
  1521. template adaptRecvFromToDomain(domain: Domain) =
  1522. var addrLen = SockLen(sizeof(sockAddress))
  1523. result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
  1524. cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
  1525. if result != -1:
  1526. data.setLen(result)
  1527. address = getAddrString(cast[ptr SockAddr](addr(sockAddress)))
  1528. when domain == AF_INET6:
  1529. port = ntohs(sockAddress.sin6_port).Port
  1530. else:
  1531. port = ntohs(sockAddress.sin_port).Port
  1532. else:
  1533. raiseOSError(osLastError())
  1534. assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket")
  1535. # TODO: Buffered sockets
  1536. data.setLen(length)
  1537. case socket.domain
  1538. of AF_INET6:
  1539. var sockAddress: Sockaddr_in6
  1540. adaptRecvFromToDomain(AF_INET6)
  1541. of AF_INET:
  1542. var sockAddress: Sockaddr_in
  1543. adaptRecvFromToDomain(AF_INET)
  1544. else:
  1545. raise newException(ValueError, "Unknown socket address family")
  1546. proc skip*(socket: Socket, size: int, timeout = -1) =
  1547. ## Skips `size` amount of bytes.
  1548. ##
  1549. ## An optional timeout can be specified in milliseconds, if skipping the
  1550. ## bytes takes longer than specified a TimeoutError exception will be raised.
  1551. ##
  1552. ## Returns the number of skipped bytes.
  1553. var waited: Duration
  1554. var dummy = alloc(size)
  1555. var bytesSkipped = 0
  1556. while bytesSkipped != size:
  1557. let avail = waitFor(socket, waited, timeout, size-bytesSkipped, "skip")
  1558. bytesSkipped += recv(socket, dummy, avail)
  1559. dealloc(dummy)
  1560. proc send*(socket: Socket, data: pointer, size: int): int {.
  1561. tags: [WriteIOEffect].} =
  1562. ## Sends data to a socket.
  1563. ##
  1564. ## **Note**: This is a low-level version of `send`. You likely should use
  1565. ## the version below.
  1566. assert(not socket.isClosed, "Cannot `send` on a closed socket")
  1567. when defineSsl:
  1568. if socket.isSsl:
  1569. ErrClearError()
  1570. return SSL_write(socket.sslHandle, cast[cstring](data), size)
  1571. when useWinVersion or defined(macosx):
  1572. result = send(socket.fd, data, size.cint, 0'i32)
  1573. else:
  1574. when defined(solaris):
  1575. const MSG_NOSIGNAL = 0
  1576. result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
  1577. proc send*(socket: Socket, data: string,
  1578. flags = {SocketFlag.SafeDisconn}) {.tags: [WriteIOEffect].} =
  1579. ## sends data to a socket.
  1580. let sent = send(socket, cstring(data), data.len)
  1581. if sent < 0:
  1582. let lastError = osLastError()
  1583. socketError(socket, lastError = lastError, flags = flags)
  1584. if sent != data.len:
  1585. raiseOSError(osLastError(), "Could not send all data.")
  1586. template `&=`*(socket: Socket; data: typed) =
  1587. ## an alias for 'send'.
  1588. send(socket, data)
  1589. proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
  1590. ## Safe alternative to `send`. Does not raise an OSError when an error occurs,
  1591. ## and instead returns `false` on failure.
  1592. result = send(socket, cstring(data), data.len) == data.len
  1593. proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
  1594. size: int, af: Domain = AF_INET, flags = 0'i32) {.
  1595. tags: [WriteIOEffect].} =
  1596. ## This proc sends `data` to the specified `address`,
  1597. ## which may be an IP address or a hostname, if a hostname is specified
  1598. ## this function will try each IP of that hostname. This function
  1599. ## should normally be used with connection-less sockets (UDP sockets).
  1600. ##
  1601. ## If an error occurs an OSError exception will be raised.
  1602. ##
  1603. ## **Note:** You may wish to use the high-level version of this function
  1604. ## which is defined below.
  1605. ##
  1606. ## **Note:** This proc is not available for SSL sockets.
  1607. assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket")
  1608. assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
  1609. var aiList = getAddrInfo(address, port, af, socket.sockType, socket.protocol)
  1610. # try all possibilities:
  1611. var success = false
  1612. var it = aiList
  1613. var result = 0
  1614. while it != nil:
  1615. result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
  1616. it.ai_addrlen.SockLen)
  1617. if result != -1'i32:
  1618. success = true
  1619. break
  1620. it = it.ai_next
  1621. let osError = osLastError()
  1622. freeAddrInfo(aiList)
  1623. if not success:
  1624. raiseOSError(osError)
  1625. proc sendTo*(socket: Socket, address: string, port: Port,
  1626. data: string) {.tags: [WriteIOEffect].} =
  1627. ## This proc sends `data` to the specified `address`,
  1628. ## which may be an IP address or a hostname, if a hostname is specified
  1629. ## this function will try each IP of that hostname.
  1630. ##
  1631. ## Generally for use with connection-less (UDP) sockets.
  1632. ##
  1633. ## If an error occurs an OSError exception will be raised.
  1634. ##
  1635. ## This is the high-level version of the above `sendTo` function.
  1636. socket.sendTo(address, port, cstring(data), data.len, socket.domain)
  1637. when defined(zephyr):
  1638. proc sendTo*(socket: Socket, address: IpAddress, port: Port,
  1639. data: string, flags = 0'i32): int {.
  1640. discardable, tags: [WriteIOEffect].} =
  1641. ## This proc sends `data` to the specified `IpAddress` and returns
  1642. ## the number of bytes written.
  1643. ##
  1644. ## Generally for use with connection-less (UDP) sockets.
  1645. ##
  1646. ## If an error occurs an OSError exception will be raised.
  1647. ##
  1648. ## This is the high-level version of the above `sendTo` function.
  1649. assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket")
  1650. assert(not socket.isClosed, "Cannot `sendTo` on a closed socket")
  1651. var sa: Sockaddr_storage
  1652. var sl: SockLen
  1653. toSockAddr(address, port, sa, sl)
  1654. result = sendto(socket.fd, cstring(data), data.len().cint, flags.cint,
  1655. cast[ptr SockAddr](addr sa), sl)
  1656. if result == -1'i32:
  1657. let osError = osLastError()
  1658. raiseOSError(osError)
  1659. proc isSsl*(socket: Socket): bool =
  1660. ## Determines whether `socket` is a SSL socket.
  1661. when defineSsl:
  1662. result = socket.isSsl
  1663. else:
  1664. result = false
  1665. proc getFd*(socket: Socket): SocketHandle = return socket.fd
  1666. ## Returns the socket's file descriptor
  1667. when defined(zephyr) or defined(nimNetSocketExtras): # Remove in future
  1668. proc getDomain*(socket: Socket): Domain = return socket.domain
  1669. ## Returns the socket's domain
  1670. proc getType*(socket: Socket): SockType = return socket.sockType
  1671. ## Returns the socket's type
  1672. proc getProtocol*(socket: Socket): Protocol = return socket.protocol
  1673. ## Returns the socket's protocol
  1674. when defined(nimHasStyleChecks):
  1675. {.push styleChecks: off.}
  1676. proc IPv4_any*(): IpAddress =
  1677. ## Returns the IPv4 any address, which can be used to listen on all available
  1678. ## network adapters
  1679. result = IpAddress(
  1680. family: IpAddressFamily.IPv4,
  1681. address_v4: [0'u8, 0, 0, 0])
  1682. proc IPv4_loopback*(): IpAddress =
  1683. ## Returns the IPv4 loopback address (127.0.0.1)
  1684. result = IpAddress(
  1685. family: IpAddressFamily.IPv4,
  1686. address_v4: [127'u8, 0, 0, 1])
  1687. proc IPv4_broadcast*(): IpAddress =
  1688. ## Returns the IPv4 broadcast address (255.255.255.255)
  1689. result = IpAddress(
  1690. family: IpAddressFamily.IPv4,
  1691. address_v4: [255'u8, 255, 255, 255])
  1692. proc IPv6_any*(): IpAddress =
  1693. ## Returns the IPv6 any address (::0), which can be used
  1694. ## to listen on all available network adapters
  1695. result = IpAddress(
  1696. family: IpAddressFamily.IPv6,
  1697. address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
  1698. proc IPv6_loopback*(): IpAddress =
  1699. ## Returns the IPv6 loopback address (::1)
  1700. result = IpAddress(
  1701. family: IpAddressFamily.IPv6,
  1702. address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
  1703. when defined(nimHasStyleChecks):
  1704. {.pop.}
  1705. proc `==`*(lhs, rhs: IpAddress): bool =
  1706. ## Compares two IpAddresses for Equality. Returns true if the addresses are equal
  1707. if lhs.family != rhs.family: return false
  1708. if lhs.family == IpAddressFamily.IPv4:
  1709. for i in low(lhs.address_v4) .. high(lhs.address_v4):
  1710. if lhs.address_v4[i] != rhs.address_v4[i]: return false
  1711. else: # IPv6
  1712. for i in low(lhs.address_v6) .. high(lhs.address_v6):
  1713. if lhs.address_v6[i] != rhs.address_v6[i]: return false
  1714. return true
  1715. proc `$`*(address: IpAddress): string =
  1716. ## Converts an IpAddress into the textual representation
  1717. result = ""
  1718. case address.family
  1719. of IpAddressFamily.IPv4:
  1720. for i in 0 .. 3:
  1721. if i != 0:
  1722. result.add('.')
  1723. result.add($address.address_v4[i])
  1724. of IpAddressFamily.IPv6:
  1725. var
  1726. currentZeroStart = -1
  1727. currentZeroCount = 0
  1728. biggestZeroStart = -1
  1729. biggestZeroCount = 0
  1730. # Look for the largest block of zeros
  1731. for i in 0..7:
  1732. var isZero = address.address_v6[i*2] == 0 and address.address_v6[i*2+1] == 0
  1733. if isZero:
  1734. if currentZeroStart == -1:
  1735. currentZeroStart = i
  1736. currentZeroCount = 1
  1737. else:
  1738. currentZeroCount.inc()
  1739. if currentZeroCount > biggestZeroCount:
  1740. biggestZeroCount = currentZeroCount
  1741. biggestZeroStart = currentZeroStart
  1742. else:
  1743. currentZeroStart = -1
  1744. if biggestZeroCount == 8: # Special case ::0
  1745. result.add("::")
  1746. else: # Print address
  1747. var printedLastGroup = false
  1748. for i in 0..7:
  1749. var word: uint16 = (cast[uint16](address.address_v6[i*2])) shl 8
  1750. word = word or cast[uint16](address.address_v6[i*2+1])
  1751. if biggestZeroCount != 0 and # Check if group is in skip group
  1752. (i >= biggestZeroStart and i < (biggestZeroStart + biggestZeroCount)):
  1753. if i == biggestZeroStart: # skip start
  1754. result.add("::")
  1755. printedLastGroup = false
  1756. else:
  1757. if printedLastGroup:
  1758. result.add(':')
  1759. var
  1760. afterLeadingZeros = false
  1761. mask = 0xF000'u16
  1762. for j in 0'u16..3'u16:
  1763. var val = (mask and word) shr (4'u16*(3'u16-j))
  1764. if val != 0 or afterLeadingZeros:
  1765. if val < 0xA:
  1766. result.add(chr(uint16(ord('0'))+val))
  1767. else: # val >= 0xA
  1768. result.add(chr(uint16(ord('a'))+val-0xA))
  1769. afterLeadingZeros = true
  1770. mask = mask shr 4
  1771. if not afterLeadingZeros:
  1772. result.add '0'
  1773. printedLastGroup = true
  1774. proc dial*(address: string, port: Port,
  1775. protocol = IPPROTO_TCP, buffered = true): owned(Socket)
  1776. {.tags: [ReadIOEffect, WriteIOEffect].} =
  1777. ## Establishes connection to the specified `address`:`port` pair via the
  1778. ## specified protocol. The procedure iterates through possible
  1779. ## resolutions of the `address` until it succeeds, meaning that it
  1780. ## seamlessly works with both IPv4 and IPv6.
  1781. ## Returns Socket ready to send or receive data.
  1782. let sockType = protocol.toSockType()
  1783. let aiList = getAddrInfo(address, port, AF_UNSPEC, sockType, protocol)
  1784. var fdPerDomain: array[low(Domain).ord..high(Domain).ord, SocketHandle]
  1785. for i in low(fdPerDomain)..high(fdPerDomain):
  1786. fdPerDomain[i] = osInvalidSocket
  1787. template closeUnusedFds(domainToKeep = -1) {.dirty.} =
  1788. for i, fd in fdPerDomain:
  1789. if fd != osInvalidSocket and i != domainToKeep:
  1790. fd.close()
  1791. var success = false
  1792. var lastError: OSErrorCode
  1793. var it = aiList
  1794. var domain: Domain
  1795. var lastFd: SocketHandle
  1796. while it != nil:
  1797. let domainOpt = it.ai_family.toKnownDomain()
  1798. if domainOpt.isNone:
  1799. it = it.ai_next
  1800. continue
  1801. domain = domainOpt.unsafeGet()
  1802. lastFd = fdPerDomain[ord(domain)]
  1803. if lastFd == osInvalidSocket:
  1804. lastFd = createNativeSocket(domain, sockType, protocol)
  1805. if lastFd == osInvalidSocket:
  1806. # we always raise if socket creation failed, because it means a
  1807. # network system problem (e.g. not enough FDs), and not an unreachable
  1808. # address.
  1809. let err = osLastError()
  1810. freeAddrInfo(aiList)
  1811. closeUnusedFds()
  1812. raiseOSError(err)
  1813. fdPerDomain[ord(domain)] = lastFd
  1814. if connect(lastFd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
  1815. success = true
  1816. break
  1817. lastError = osLastError()
  1818. it = it.ai_next
  1819. freeAddrInfo(aiList)
  1820. closeUnusedFds(ord(domain))
  1821. if success:
  1822. result = newSocket(lastFd, domain, sockType, protocol, buffered)
  1823. elif lastError != 0.OSErrorCode:
  1824. raiseOSError(lastError)
  1825. else:
  1826. raise newException(IOError, "Couldn't resolve address: " & address)
  1827. proc connect*(socket: Socket, address: string,
  1828. port = Port(0)) {.tags: [ReadIOEffect].} =
  1829. ## Connects socket to `address`:`port`. `Address` can be an IP address or a
  1830. ## host name. If `address` is a host name, this function will try each IP
  1831. ## of that host name. `htons` is already performed on `port` so you must
  1832. ## not do it.
  1833. ##
  1834. ## If `socket` is an SSL socket a handshake will be automatically performed.
  1835. var aiList = getAddrInfo(address, port, socket.domain)
  1836. # try all possibilities:
  1837. var success = false
  1838. var lastError: OSErrorCode
  1839. var it = aiList
  1840. while it != nil:
  1841. if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
  1842. success = true
  1843. break
  1844. else: lastError = osLastError()
  1845. it = it.ai_next
  1846. freeAddrInfo(aiList)
  1847. if not success: raiseOSError(lastError)
  1848. when defineSsl:
  1849. if socket.isSsl:
  1850. # RFC3546 for SNI specifies that IP addresses are not allowed.
  1851. if not isIpAddress(address):
  1852. # Discard result in case OpenSSL version doesn't support SNI, or we're
  1853. # not using TLSv1+
  1854. discard SSL_set_tlsext_host_name(socket.sslHandle, address)
  1855. ErrClearError()
  1856. let ret = SSL_connect(socket.sslHandle)
  1857. socketError(socket, ret)
  1858. when not defined(nimDisableCertificateValidation) and not defined(windows):
  1859. if not isIpAddress(address):
  1860. socket.checkCertName(address)
  1861. proc connectAsync(socket: Socket, name: string, port = Port(0),
  1862. af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
  1863. ## A variant of `connect` for non-blocking sockets.
  1864. ##
  1865. ## This procedure will immediately return, it will not block until a connection
  1866. ## is made. It is up to the caller to make sure the connection has been established
  1867. ## by checking (using `select`) whether the socket is writeable.
  1868. ##
  1869. ## **Note**: For SSL sockets, the `handshake` procedure must be called
  1870. ## whenever the socket successfully connects to a server.
  1871. var aiList = getAddrInfo(name, port, af)
  1872. # try all possibilities:
  1873. var success = false
  1874. var lastError: OSErrorCode
  1875. var it = aiList
  1876. while it != nil:
  1877. var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen)
  1878. if ret == 0'i32:
  1879. success = true
  1880. break
  1881. else:
  1882. lastError = osLastError()
  1883. when useWinVersion:
  1884. # Windows EINTR doesn't behave same as POSIX.
  1885. if lastError.int32 == WSAEWOULDBLOCK:
  1886. success = true
  1887. break
  1888. else:
  1889. if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
  1890. success = true
  1891. break
  1892. it = it.ai_next
  1893. freeAddrInfo(aiList)
  1894. if not success: raiseOSError(lastError)
  1895. proc connect*(socket: Socket, address: string, port = Port(0),
  1896. timeout: int) {.tags: [ReadIOEffect, WriteIOEffect].} =
  1897. ## Connects to server as specified by `address` on port specified by `port`.
  1898. ##
  1899. ## The `timeout` parameter specifies the time in milliseconds to allow for
  1900. ## the connection to the server to be made.
  1901. socket.fd.setBlocking(false)
  1902. socket.connectAsync(address, port, socket.domain)
  1903. if timeoutWrite(socket.fd, timeout) != 1:
  1904. raise newException(TimeoutError, "Call to 'connect' timed out.")
  1905. else:
  1906. let res = getSockOptInt(socket.fd, SOL_SOCKET, SO_ERROR)
  1907. if res != 0:
  1908. raiseOSError(OSErrorCode(res))
  1909. when defineSsl and not defined(nimdoc):
  1910. if socket.isSsl:
  1911. socket.fd.setBlocking(true)
  1912. # RFC3546 for SNI specifies that IP addresses are not allowed.
  1913. if not isIpAddress(address):
  1914. # Discard result in case OpenSSL version doesn't support SNI, or we're
  1915. # not using TLSv1+
  1916. discard SSL_set_tlsext_host_name(socket.sslHandle, address)
  1917. ErrClearError()
  1918. let ret = SSL_connect(socket.sslHandle)
  1919. socketError(socket, ret)
  1920. when not defined(nimDisableCertificateValidation):
  1921. if not isIpAddress(address):
  1922. socket.checkCertName(address)
  1923. socket.fd.setBlocking(true)
  1924. proc getPrimaryIPAddr*(dest = parseIpAddress("8.8.8.8")): IpAddress =
  1925. ## Finds the local IP address, usually assigned to eth0 on LAN or wlan0 on WiFi,
  1926. ## used to reach an external address. Useful to run local services.
  1927. ##
  1928. ## No traffic is sent.
  1929. ##
  1930. ## Supports IPv4 and v6.
  1931. ## Raises OSError if external networking is not set up.
  1932. runnableExamples("-r:off"):
  1933. echo getPrimaryIPAddr() # "192.168.1.2"
  1934. let socket =
  1935. if dest.family == IpAddressFamily.IPv4:
  1936. newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
  1937. else:
  1938. newSocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
  1939. try:
  1940. socket.connect($dest, 80.Port)
  1941. result = socket.getLocalAddr()[0].parseIpAddress()
  1942. finally:
  1943. socket.close()