net.nim 80 KB

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