sockets.nim 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2013 Andreas Rumpf, Dominik Picheta
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## **Warning:** Since version 0.10.2 this module is deprecated.
  10. ## Use the `net <net.html>`_ or the
  11. ## `nativesockets <nativesockets.html>`_ module instead.
  12. ##
  13. ## This module implements portable sockets, it supports a mix of different types
  14. ## of sockets. Sockets are buffered by default meaning that data will be
  15. ## received in ``BufferSize`` (4000) sized chunks, buffering
  16. ## behaviour can be disabled by setting the ``buffered`` parameter when calling
  17. ## the ``socket`` function to `false`. Be aware that some functions may not yet
  18. ## support buffered sockets (mainly the recvFrom function).
  19. ##
  20. ## Most procedures raise OSError on error, but some may return ``-1`` or a
  21. ## boolean ``false``.
  22. ##
  23. ## SSL is supported through the OpenSSL library. This support can be activated
  24. ## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will
  25. ## raise SslError exceptions when SSL errors occur.
  26. ##
  27. ## Asynchronous sockets are supported, however a better alternative is to use
  28. ## the `asyncio <asyncio.html>`_ module.
  29. {.deprecated.}
  30. include "system/inclrtl"
  31. {.deadCodeElim: on.} # dce option deprecated
  32. when hostOS == "solaris":
  33. {.passl: "-lsocket -lnsl".}
  34. elif hostOS == "haiku":
  35. {.passl: "-lnetwork".}
  36. import os, parseutils
  37. from times import epochTime
  38. when defined(ssl):
  39. import openssl
  40. else:
  41. type SSLAcceptResult = int
  42. when defined(Windows):
  43. import winlean
  44. else:
  45. import posix
  46. # Note: The enumerations are mapped to Window's constants.
  47. when defined(ssl):
  48. type
  49. SSLError* = object of Exception
  50. SSLCVerifyMode* = enum
  51. CVerifyNone, CVerifyPeer
  52. SSLProtVersion* = enum
  53. protSSLv2, protSSLv3, protTLSv1, protSSLv23
  54. SSLContext* = distinct SSLCTX
  55. SSLAcceptResult* = enum
  56. AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
  57. const
  58. BufferSize*: int = 4000 ## size of a buffered socket's buffer
  59. type
  60. SocketImpl = object ## socket type
  61. fd: SocketHandle
  62. case isBuffered: bool # determines whether this socket is buffered.
  63. of true:
  64. buffer: array[0..BufferSize, char]
  65. currPos: int # current index in buffer
  66. bufLen: int # current length of buffer
  67. of false: nil
  68. when defined(ssl):
  69. case isSsl: bool
  70. of true:
  71. sslHandle: SSLPtr
  72. sslContext: SSLContext
  73. sslNoHandshake: bool # True if needs handshake.
  74. sslHasPeekChar: bool
  75. sslPeekChar: char
  76. of false: nil
  77. nonblocking: bool
  78. Socket* = ref SocketImpl
  79. Port* = distinct uint16 ## port type
  80. Domain* = enum ## domain, which specifies the protocol family of the
  81. ## created socket. Other domains than those that are listed
  82. ## here are unsupported.
  83. AF_UNIX, ## for local socket (using a file). Unsupported on Windows.
  84. AF_INET = 2, ## for network protocol IPv4 or
  85. AF_INET6 = 23 ## for network protocol IPv6.
  86. SockType* = enum ## second argument to `socket` proc
  87. SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets
  88. SOCK_DGRAM = 2, ## datagram service or Datagram Sockets
  89. SOCK_RAW = 3, ## raw protocols atop the network layer.
  90. SOCK_SEQPACKET = 5 ## reliable sequenced packet service
  91. Protocol* = enum ## third argument to `socket` proc
  92. IPPROTO_TCP = 6, ## Transmission control protocol.
  93. IPPROTO_UDP = 17, ## User datagram protocol.
  94. IPPROTO_IP, ## Internet protocol. Unsupported on Windows.
  95. IPPROTO_IPV6, ## Internet Protocol Version 6. Unsupported on Windows.
  96. IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows.
  97. IPPROTO_ICMP ## Control message protocol. Unsupported on Windows.
  98. Servent* = object ## information about a service
  99. name*: string
  100. aliases*: seq[string]
  101. port*: Port
  102. proto*: string
  103. Hostent* = object ## information about a given host
  104. name*: string
  105. aliases*: seq[string]
  106. addrtype*: Domain
  107. length*: int
  108. addrList*: seq[string]
  109. SOBool* = enum ## Boolean socket options.
  110. OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
  111. OptOOBInline, OptReuseAddr
  112. RecvLineResult* = enum ## result for recvLineAsync
  113. RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
  114. ReadLineResult* = enum ## result for readLineAsync
  115. ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone
  116. TimeoutError* = object of Exception
  117. when defined(booting):
  118. let invalidSocket*: Socket = nil ## invalid socket
  119. else:
  120. const invalidSocket*: Socket = nil ## invalid socket
  121. when defined(windows):
  122. let
  123. osInvalidSocket = winlean.INVALID_SOCKET
  124. else:
  125. let
  126. osInvalidSocket = posix.INVALID_SOCKET
  127. proc newTSocket(fd: SocketHandle, isBuff: bool): Socket =
  128. if fd == osInvalidSocket:
  129. return nil
  130. new(result)
  131. result.fd = fd
  132. result.isBuffered = isBuff
  133. if isBuff:
  134. result.currPos = 0
  135. result.nonblocking = false
  136. proc `==`*(a, b: Port): bool {.borrow.}
  137. ## ``==`` for ports.
  138. proc `$`*(p: Port): string {.borrow.}
  139. ## returns the port number as a string
  140. proc ntohl*(x: int32): int32 =
  141. ## Converts 32-bit integers from network to host byte order.
  142. ## On machines where the host byte order is the same as network byte order,
  143. ## this is a no-op; otherwise, it performs a 4-byte swap operation.
  144. when cpuEndian == bigEndian: result = x
  145. else: result = (x shr 24'i32) or
  146. (x shr 8'i32 and 0xff00'i32) or
  147. (x shl 8'i32 and 0xff0000'i32) or
  148. (x shl 24'i32)
  149. proc ntohs*(x: int16): int16 =
  150. ## Converts 16-bit integers from network to host byte order. On machines
  151. ## where the host byte order is the same as network byte order, this is
  152. ## a no-op; otherwise, it performs a 2-byte swap operation.
  153. when cpuEndian == bigEndian: result = x
  154. else: result = (x shr 8'i16) or (x shl 8'i16)
  155. proc htonl*(x: int32): int32 =
  156. ## Converts 32-bit integers from host to network byte order. On machines
  157. ## where the host byte order is the same as network byte order, this is
  158. ## a no-op; otherwise, it performs a 4-byte swap operation.
  159. result = sockets.ntohl(x)
  160. proc htons*(x: int16): int16 =
  161. ## Converts 16-bit positive integers from host to network byte order.
  162. ## On machines where the host byte order is the same as network byte
  163. ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
  164. result = sockets.ntohs(x)
  165. template ntohl(x: uint32): uint32 =
  166. cast[uint32](sockets.ntohl(cast[int32](x)))
  167. template ntohs(x: uint16): uint16 =
  168. cast[uint16](sockets.ntohs(cast[int16](x)))
  169. template htonl(x: uint32): uint32 =
  170. sockets.ntohl(x)
  171. template htons(x: uint16): uint16 =
  172. sockets.ntohs(x)
  173. when defined(Posix):
  174. proc toInt(domain: Domain): cint =
  175. case domain
  176. of AF_UNIX: result = posix.AF_UNIX
  177. of AF_INET: result = posix.AF_INET
  178. of AF_INET6: result = posix.AF_INET6
  179. proc toInt(typ: SockType): cint =
  180. case typ
  181. of SOCK_STREAM: result = posix.SOCK_STREAM
  182. of SOCK_DGRAM: result = posix.SOCK_DGRAM
  183. of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
  184. of SOCK_RAW: result = posix.SOCK_RAW
  185. proc toInt(p: Protocol): cint =
  186. case p
  187. of IPPROTO_TCP: result = posix.IPPROTO_TCP
  188. of IPPROTO_UDP: result = posix.IPPROTO_UDP
  189. of IPPROTO_IP: result = posix.IPPROTO_IP
  190. of IPPROTO_IPV6: result = posix.IPPROTO_IPV6
  191. of IPPROTO_RAW: result = posix.IPPROTO_RAW
  192. of IPPROTO_ICMP: result = posix.IPPROTO_ICMP
  193. else:
  194. proc toInt(domain: Domain): cint =
  195. result = toU16(ord(domain))
  196. proc toInt(typ: SockType): cint =
  197. result = cint(ord(typ))
  198. proc toInt(p: Protocol): cint =
  199. result = cint(ord(p))
  200. proc socket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
  201. protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
  202. ## Creates a new socket; returns `InvalidSocket` if an error occurs.
  203. # TODO: Perhaps this should just raise OSError when an error occurs.
  204. when defined(Windows):
  205. result = newTSocket(winlean.socket(cint(domain), cint(typ), cint(protocol)), buffered)
  206. else:
  207. result = newTSocket(posix.socket(toInt(domain), toInt(typ), toInt(protocol)), buffered)
  208. when defined(ssl):
  209. CRYPTO_malloc_init()
  210. SslLibraryInit()
  211. SslLoadErrorStrings()
  212. ErrLoadBioStrings()
  213. OpenSSL_add_all_algorithms()
  214. proc raiseSSLError(s = "") =
  215. if s != "":
  216. raise newException(SSLError, s)
  217. let err = ErrPeekLastError()
  218. if err == 0:
  219. raise newException(SSLError, "No error reported.")
  220. if err == -1:
  221. raiseOSError(osLastError())
  222. var errStr = ErrErrorString(err, nil)
  223. raise newException(SSLError, $errStr)
  224. # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
  225. proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) =
  226. if certFile != "" and not existsFile(certFile):
  227. raise newException(system.IOError, "Certificate file could not be found: " & certFile)
  228. if keyFile != "" and not existsFile(keyFile):
  229. raise newException(system.IOError, "Key file could not be found: " & keyFile)
  230. if certFile != "":
  231. var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
  232. if ret != 1:
  233. raiseSslError()
  234. # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf
  235. if keyFile != "":
  236. if SSL_CTX_use_PrivateKey_file(ctx, keyFile,
  237. SSL_FILETYPE_PEM) != 1:
  238. raiseSslError()
  239. if SSL_CTX_check_private_key(ctx) != 1:
  240. raiseSslError("Verification of private key file failed.")
  241. proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
  242. certFile = "", keyFile = ""): SSLContext =
  243. ## Creates an SSL context.
  244. ##
  245. ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are
  246. ## are available with the addition of ``ProtSSLv23`` which allows for
  247. ## compatibility with all of them.
  248. ##
  249. ## There are currently only two options for verify mode;
  250. ## one is ``CVerifyNone`` and with it certificates will not be verified
  251. ## the other is ``CVerifyPeer`` and certificates will be verified for
  252. ## it, ``CVerifyPeer`` is the safest choice.
  253. ##
  254. ## The last two parameters specify the certificate file path and the key file
  255. ## path, a server socket will most likely not work without these.
  256. ## Certificates can be generated using the following command:
  257. ## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
  258. var newCTX: SSL_CTX
  259. case protVersion
  260. of protSSLv23:
  261. newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
  262. of protSSLv2:
  263. raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv3")
  264. of protSSLv3:
  265. newCTX = SSL_CTX_new(SSLv3_method())
  266. of protTLSv1:
  267. newCTX = SSL_CTX_new(TLSv1_method())
  268. if newCTX.SSLCTXSetCipherList("ALL") != 1:
  269. raiseSslError()
  270. case verifyMode
  271. of CVerifyPeer:
  272. newCTX.SSLCTXSetVerify(SSLVerifyPeer, nil)
  273. of CVerifyNone:
  274. newCTX.SSLCTXSetVerify(SSLVerifyNone, nil)
  275. if newCTX == nil:
  276. raiseSslError()
  277. discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
  278. newCTX.loadCertificates(certFile, keyFile)
  279. return SSLContext(newCTX)
  280. proc wrapSocket*(ctx: SSLContext, socket: Socket) =
  281. ## Wraps a socket in an SSL context. This function effectively turns
  282. ## ``socket`` into an SSL socket.
  283. ##
  284. ## **Disclaimer**: This code is not well tested, may be very unsafe and
  285. ## prone to security vulnerabilities.
  286. socket.isSSL = true
  287. socket.sslContext = ctx
  288. socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
  289. socket.sslNoHandshake = false
  290. socket.sslHasPeekChar = false
  291. if socket.sslHandle == nil:
  292. raiseSslError()
  293. if SSLSetFd(socket.sslHandle, socket.fd) != 1:
  294. raiseSslError()
  295. proc raiseSocketError*(socket: Socket, err: int = -1, async = false) =
  296. ## Raises proper errors based on return values of ``recv`` functions.
  297. ##
  298. ## If ``async`` is ``True`` no error will be thrown in the case when the
  299. ## error was caused by no data being available to be read.
  300. ##
  301. ## If ``err`` is not lower than 0 no exception will be raised.
  302. when defined(ssl):
  303. if socket.isSSL:
  304. if err <= 0:
  305. var ret = SSLGetError(socket.sslHandle, err.cint)
  306. case ret
  307. of SSL_ERROR_ZERO_RETURN:
  308. raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  309. of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  310. if async:
  311. return
  312. else: raiseSslError("Not enough data on socket.")
  313. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
  314. if async:
  315. return
  316. else: raiseSslError("Not enough data on socket.")
  317. of SSL_ERROR_WANT_X509_LOOKUP:
  318. raiseSslError("Function for x509 lookup has been called.")
  319. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  320. raiseSslError()
  321. else: raiseSslError("Unknown Error")
  322. if err == -1 and not (when defined(ssl): socket.isSSL else: false):
  323. let lastError = osLastError()
  324. if async:
  325. when defined(windows):
  326. if lastError.int32 == WSAEWOULDBLOCK:
  327. return
  328. else: raiseOSError(lastError)
  329. else:
  330. if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
  331. return
  332. else: raiseOSError(lastError)
  333. else: raiseOSError(lastError)
  334. proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
  335. ## Marks ``socket`` as accepting connections.
  336. ## ``Backlog`` specifies the maximum length of the
  337. ## queue of pending connections.
  338. if listen(socket.fd, cint(backlog)) < 0'i32: raiseOSError(osLastError())
  339. proc invalidIp4(s: string) {.noreturn, noinline.} =
  340. raise newException(ValueError, "invalid ip4 address: " & s)
  341. proc parseIp4*(s: string): BiggestInt =
  342. ## parses an IP version 4 in dotted decimal form like "a.b.c.d".
  343. ##
  344. ## This is equivalent to `inet_ntoa`:idx:.
  345. ##
  346. ## Raises ValueError in case of an error.
  347. var a, b, c, d: int
  348. var i = 0
  349. var j = parseInt(s, a, i)
  350. if j <= 0: invalidIp4(s)
  351. inc(i, j)
  352. if s[i] == '.': inc(i)
  353. else: invalidIp4(s)
  354. j = parseInt(s, b, i)
  355. if j <= 0: invalidIp4(s)
  356. inc(i, j)
  357. if s[i] == '.': inc(i)
  358. else: invalidIp4(s)
  359. j = parseInt(s, c, i)
  360. if j <= 0: invalidIp4(s)
  361. inc(i, j)
  362. if s[i] == '.': inc(i)
  363. else: invalidIp4(s)
  364. j = parseInt(s, d, i)
  365. if j <= 0: invalidIp4(s)
  366. inc(i, j)
  367. if s[i] != '\0': invalidIp4(s)
  368. result = BiggestInt(a shl 24 or b shl 16 or c shl 8 or d)
  369. template gaiNim(a, p, h, list: untyped): untyped =
  370. var gaiResult = getaddrinfo(a, $p, addr(h), list)
  371. if gaiResult != 0'i32:
  372. when defined(windows):
  373. raiseOSError(osLastError())
  374. else:
  375. raiseOSError(osLastError(), $gai_strerror(gaiResult))
  376. proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
  377. tags: [ReadIOEffect].} =
  378. ## binds an address/port number to a socket.
  379. ## Use address string in dotted decimal form like "a.b.c.d"
  380. ## or leave "" for any address.
  381. if address == "":
  382. var name: Sockaddr_in
  383. when defined(Windows):
  384. name.sin_family = uint16(ord(AF_INET))
  385. else:
  386. name.sin_family = uint16(posix.AF_INET)
  387. name.sin_port = sockets.htons(uint16(port))
  388. name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
  389. if bindSocket(socket.fd, cast[ptr SockAddr](addr(name)),
  390. sizeof(name).SockLen) < 0'i32:
  391. raiseOSError(osLastError())
  392. else:
  393. var hints: AddrInfo
  394. var aiList: ptr AddrInfo = nil
  395. hints.ai_family = toInt(AF_INET)
  396. hints.ai_socktype = toInt(SOCK_STREAM)
  397. hints.ai_protocol = toInt(IPPROTO_TCP)
  398. gaiNim(address, port, hints, aiList)
  399. if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
  400. raiseOSError(osLastError())
  401. proc getSockName*(socket: Socket): Port =
  402. ## returns the socket's associated port number.
  403. var name: Sockaddr_in
  404. when defined(Windows):
  405. name.sin_family = uint16(ord(AF_INET))
  406. else:
  407. name.sin_family = uint16(posix.AF_INET)
  408. #name.sin_port = htons(cint16(port))
  409. #name.sin_addr.s_addr = htonl(INADDR_ANY)
  410. var namelen = sizeof(name).SockLen
  411. if getsockname(socket.fd, cast[ptr SockAddr](addr(name)),
  412. addr(namelen)) == -1'i32:
  413. raiseOSError(osLastError())
  414. result = Port(sockets.ntohs(name.sin_port))
  415. template acceptAddrPlain(noClientRet, successRet: SSLAcceptResult or int,
  416. sslImplementation: untyped): untyped =
  417. assert(client != nil)
  418. var sockAddress: Sockaddr_in
  419. var addrLen = sizeof(sockAddress).SockLen
  420. var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)),
  421. addr(addrLen))
  422. if sock == osInvalidSocket:
  423. let err = osLastError()
  424. when defined(windows):
  425. if err.int32 == WSAEINPROGRESS:
  426. client = invalidSocket
  427. address = ""
  428. when noClientRet.int == -1:
  429. return
  430. else:
  431. return noClientRet
  432. else: raiseOSError(err)
  433. else:
  434. if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
  435. client = invalidSocket
  436. address = ""
  437. when noClientRet.int == -1:
  438. return
  439. else:
  440. return noClientRet
  441. else: raiseOSError(err)
  442. else:
  443. client.fd = sock
  444. client.isBuffered = server.isBuffered
  445. sslImplementation
  446. # Client socket is set above.
  447. address = $inet_ntoa(sockAddress.sin_addr)
  448. when successRet.int == -1:
  449. return
  450. else:
  451. return successRet
  452. proc acceptAddr*(server: Socket, client: var Socket, address: var string) {.
  453. tags: [ReadIOEffect].} =
  454. ## Blocks until a connection is being made from a client. When a connection
  455. ## is made sets ``client`` to the client socket and ``address`` to the address
  456. ## of the connecting client.
  457. ## If ``server`` is non-blocking then this function returns immediately, and
  458. ## if there are no connections queued the returned socket will be
  459. ## ``InvalidSocket``.
  460. ## This function will raise OSError if an error occurs.
  461. ##
  462. ## The resulting client will inherit any properties of the server socket. For
  463. ## example: whether the socket is buffered or not.
  464. ##
  465. ## **Note**: ``client`` must be initialised (with ``new``), this function
  466. ## makes no effort to initialise the ``client`` variable.
  467. ##
  468. ## **Warning:** When using SSL with non-blocking sockets, it is best to use
  469. ## the acceptAddrSSL procedure as this procedure will most likely block.
  470. acceptAddrPlain(SSLAcceptResult(-1), SSLAcceptResult(-1)):
  471. when defined(ssl):
  472. if server.isSSL:
  473. # We must wrap the client sock in a ssl context.
  474. server.sslContext.wrapSocket(client)
  475. let ret = SSLAccept(client.sslHandle)
  476. while ret <= 0:
  477. let err = SSLGetError(client.sslHandle, ret)
  478. if err != SSL_ERROR_WANT_ACCEPT:
  479. case err
  480. of SSL_ERROR_ZERO_RETURN:
  481. raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  482. of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
  483. SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  484. raiseSslError("acceptAddrSSL should be used for non-blocking SSL sockets.")
  485. of SSL_ERROR_WANT_X509_LOOKUP:
  486. raiseSslError("Function for x509 lookup has been called.")
  487. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  488. raiseSslError()
  489. else:
  490. raiseSslError("Unknown error")
  491. proc setBlocking*(s: Socket, blocking: bool) {.tags: [], gcsafe.}
  492. ## Sets blocking mode on socket
  493. when defined(ssl):
  494. proc acceptAddrSSL*(server: Socket, client: var Socket,
  495. address: var string): SSLAcceptResult {.
  496. tags: [ReadIOEffect].} =
  497. ## This procedure should only be used for non-blocking **SSL** sockets.
  498. ## It will immediately return with one of the following values:
  499. ##
  500. ## ``AcceptSuccess`` will be returned when a client has been successfully
  501. ## accepted and the handshake has been successfully performed between
  502. ## ``server`` and the newly connected client.
  503. ##
  504. ## ``AcceptNoHandshake`` will be returned when a client has been accepted
  505. ## but no handshake could be performed. This can happen when the client
  506. ## connects but does not yet initiate a handshake. In this case
  507. ## ``acceptAddrSSL`` should be called again with the same parameters.
  508. ##
  509. ## ``AcceptNoClient`` will be returned when no client is currently attempting
  510. ## to connect.
  511. template doHandshake(): untyped =
  512. when defined(ssl):
  513. if server.isSSL:
  514. client.setBlocking(false)
  515. # We must wrap the client sock in a ssl context.
  516. if not client.isSSL or client.sslHandle == nil:
  517. server.sslContext.wrapSocket(client)
  518. let ret = SSLAccept(client.sslHandle)
  519. while ret <= 0:
  520. let err = SSLGetError(client.sslHandle, ret)
  521. if err != SSL_ERROR_WANT_ACCEPT:
  522. case err
  523. of SSL_ERROR_ZERO_RETURN:
  524. raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  525. of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
  526. SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  527. client.sslNoHandshake = true
  528. return AcceptNoHandshake
  529. of SSL_ERROR_WANT_X509_LOOKUP:
  530. raiseSslError("Function for x509 lookup has been called.")
  531. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  532. raiseSslError()
  533. else:
  534. raiseSslError("Unknown error")
  535. client.sslNoHandshake = false
  536. if client.isSSL and client.sslNoHandshake:
  537. doHandshake()
  538. return AcceptSuccess
  539. else:
  540. acceptAddrPlain(AcceptNoClient, AcceptSuccess):
  541. doHandshake()
  542. proc accept*(server: Socket, client: var Socket) {.tags: [ReadIOEffect].} =
  543. ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
  544. ## socket.
  545. ##
  546. ## **Note**: ``client`` must be initialised (with ``new``), this function
  547. ## makes no effort to initialise the ``client`` variable.
  548. var addrDummy = ""
  549. acceptAddr(server, client, addrDummy)
  550. proc acceptAddr*(server: Socket): tuple[client: Socket, address: string] {.
  551. deprecated, tags: [ReadIOEffect].} =
  552. ## Slightly different version of ``acceptAddr``.
  553. ##
  554. ## **Deprecated since version 0.9.0:** Please use the function above.
  555. var client: Socket
  556. new(client)
  557. var address = ""
  558. acceptAddr(server, client, address)
  559. return (client, address)
  560. proc accept*(server: Socket): Socket {.deprecated, tags: [ReadIOEffect].} =
  561. ## **Deprecated since version 0.9.0:** Please use the function above.
  562. new(result)
  563. var address = ""
  564. acceptAddr(server, result, address)
  565. proc close*(socket: Socket) =
  566. ## closes a socket.
  567. when defined(windows):
  568. discard winlean.closesocket(socket.fd)
  569. else:
  570. discard posix.close(socket.fd)
  571. # TODO: These values should not be discarded. An OSError should be raised.
  572. # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
  573. when defined(ssl):
  574. if socket.isSSL:
  575. discard SSLShutdown(socket.sslHandle)
  576. SSLFree(socket.sslHandle)
  577. socket.sslHandle = nil
  578. proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
  579. ## Searches the database from the beginning and finds the first entry for
  580. ## which the service name specified by ``name`` matches the s_name member
  581. ## and the protocol name specified by ``proto`` matches the s_proto member.
  582. ##
  583. ## On posix this will search through the ``/etc/services`` file.
  584. when defined(Windows):
  585. var s = winlean.getservbyname(name, proto)
  586. else:
  587. var s = posix.getservbyname(name, proto)
  588. if s == nil: raiseOSError(osLastError(), "Service not found.")
  589. result.name = $s.s_name
  590. result.aliases = cstringArrayToSeq(s.s_aliases)
  591. result.port = Port(s.s_port)
  592. result.proto = $s.s_proto
  593. proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} =
  594. ## Searches the database from the beginning and finds the first entry for
  595. ## which the port specified by ``port`` matches the s_port member and the
  596. ## protocol name specified by ``proto`` matches the s_proto member.
  597. ##
  598. ## On posix this will search through the ``/etc/services`` file.
  599. when defined(Windows):
  600. var s = winlean.getservbyport(ze(int16(port)).cint, proto)
  601. else:
  602. var s = posix.getservbyport(ze(int16(port)).cint, proto)
  603. if s == nil: raiseOSError(osLastError(), "Service not found.")
  604. result.name = $s.s_name
  605. result.aliases = cstringArrayToSeq(s.s_aliases)
  606. result.port = Port(s.s_port)
  607. result.proto = $s.s_proto
  608. proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
  609. ## This function will lookup the hostname of an IP Address.
  610. var myaddr: InAddr
  611. myaddr.s_addr = inet_addr(ip)
  612. when defined(windows):
  613. var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
  614. cint(sockets.AF_INET))
  615. if s == nil: raiseOSError(osLastError())
  616. else:
  617. var s =
  618. when defined(android4):
  619. posix.gethostbyaddr(cast[cstring](addr(myaddr)), sizeof(myaddr).cint,
  620. cint(posix.AF_INET))
  621. else:
  622. posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen,
  623. cint(posix.AF_INET))
  624. if s == nil:
  625. raiseOSError(osLastError(), $hstrerror(h_errno))
  626. result.name = $s.h_name
  627. result.aliases = cstringArrayToSeq(s.h_aliases)
  628. when defined(windows):
  629. result.addrtype = Domain(s.h_addrtype)
  630. else:
  631. if s.h_addrtype.cint == posix.AF_INET:
  632. result.addrtype = AF_INET
  633. elif s.h_addrtype.cint == posix.AF_INET6:
  634. result.addrtype = AF_INET6
  635. else:
  636. raiseOSError(osLastError(), "unknown h_addrtype")
  637. result.addrList = cstringArrayToSeq(s.h_addr_list)
  638. result.length = int(s.h_length)
  639. proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
  640. ## This function will lookup the IP address of a hostname.
  641. when defined(Windows):
  642. var s = winlean.gethostbyname(name)
  643. else:
  644. var s = posix.gethostbyname(name)
  645. if s == nil: raiseOSError(osLastError())
  646. result.name = $s.h_name
  647. result.aliases = cstringArrayToSeq(s.h_aliases)
  648. when defined(windows):
  649. result.addrtype = Domain(s.h_addrtype)
  650. else:
  651. if s.h_addrtype.cint == posix.AF_INET:
  652. result.addrtype = AF_INET
  653. elif s.h_addrtype.cint == posix.AF_INET6:
  654. result.addrtype = AF_INET6
  655. else:
  656. raiseOSError(osLastError(), "unknown h_addrtype")
  657. result.addrList = cstringArrayToSeq(s.h_addr_list)
  658. result.length = int(s.h_length)
  659. proc getSockOptInt*(socket: Socket, level, optname: int): int {.
  660. tags: [ReadIOEffect].} =
  661. ## getsockopt for integer options.
  662. var res: cint
  663. var size = sizeof(res).SockLen
  664. if getsockopt(socket.fd, cint(level), cint(optname),
  665. addr(res), addr(size)) < 0'i32:
  666. raiseOSError(osLastError())
  667. result = int(res)
  668. proc setSockOptInt*(socket: Socket, level, optname, optval: int) {.
  669. tags: [WriteIOEffect].} =
  670. ## setsockopt for integer options.
  671. var value = cint(optval)
  672. if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
  673. sizeof(value).SockLen) < 0'i32:
  674. raiseOSError(osLastError())
  675. proc toCInt(opt: SOBool): cint =
  676. case opt
  677. of OptAcceptConn: SO_ACCEPTCONN
  678. of OptBroadcast: SO_BROADCAST
  679. of OptDebug: SO_DEBUG
  680. of OptDontRoute: SO_DONTROUTE
  681. of OptKeepAlive: SO_KEEPALIVE
  682. of OptOOBInline: SO_OOBINLINE
  683. of OptReuseAddr: SO_REUSEADDR
  684. proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {.
  685. tags: [ReadIOEffect].} =
  686. ## Retrieves option ``opt`` as a boolean value.
  687. var res: cint
  688. var size = sizeof(res).SockLen
  689. if getsockopt(socket.fd, cint(level), toCInt(opt),
  690. addr(res), addr(size)) < 0'i32:
  691. raiseOSError(osLastError())
  692. result = res != 0
  693. proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {.
  694. tags: [WriteIOEffect].} =
  695. ## Sets option ``opt`` to a boolean value specified by ``value``.
  696. var valuei = cint(if value: 1 else: 0)
  697. if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),
  698. sizeof(valuei).SockLen) < 0'i32:
  699. raiseOSError(osLastError())
  700. proc connect*(socket: Socket, address: string, port = Port(0),
  701. af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
  702. ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
  703. ## host name. If ``address`` is a host name, this function will try each IP
  704. ## of that host name. ``htons`` is already performed on ``port`` so you must
  705. ## not do it.
  706. ##
  707. ## If ``socket`` is an SSL socket a handshake will be automatically performed.
  708. var hints: AddrInfo
  709. var aiList: ptr AddrInfo = nil
  710. hints.ai_family = toInt(af)
  711. hints.ai_socktype = toInt(SOCK_STREAM)
  712. hints.ai_protocol = toInt(IPPROTO_TCP)
  713. gaiNim(address, port, hints, aiList)
  714. # try all possibilities:
  715. var success = false
  716. var lastError: OSErrorCode
  717. var it = aiList
  718. while it != nil:
  719. if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
  720. success = true
  721. break
  722. else: lastError = osLastError()
  723. it = it.ai_next
  724. freeaddrinfo(aiList)
  725. if not success: raiseOSError(lastError)
  726. when defined(ssl):
  727. if socket.isSSL:
  728. let ret = SSLConnect(socket.sslHandle)
  729. if ret <= 0:
  730. let err = SSLGetError(socket.sslHandle, ret)
  731. case err
  732. of SSL_ERROR_ZERO_RETURN:
  733. raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  734. of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT,
  735. SSL_ERROR_WANT_ACCEPT:
  736. raiseSslError("The operation did not complete. Perhaps you should use connectAsync?")
  737. of SSL_ERROR_WANT_X509_LOOKUP:
  738. raiseSslError("Function for x509 lookup has been called.")
  739. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  740. raiseSslError()
  741. else:
  742. raiseSslError("Unknown error")
  743. when false:
  744. var s: TSockAddrIn
  745. s.sin_addr.s_addr = inet_addr(address)
  746. s.sin_port = sockets.htons(uint16(port))
  747. when defined(windows):
  748. s.sin_family = toU16(ord(af))
  749. else:
  750. case af
  751. of AF_UNIX: s.sin_family = posix.AF_UNIX
  752. of AF_INET: s.sin_family = posix.AF_INET
  753. of AF_INET6: s.sin_family = posix.AF_INET6
  754. if connect(socket.fd, cast[ptr TSockAddr](addr(s)), sizeof(s).cint) < 0'i32:
  755. OSError()
  756. proc connectAsync*(socket: Socket, name: string, port = Port(0),
  757. af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
  758. ## A variant of ``connect`` for non-blocking sockets.
  759. ##
  760. ## This procedure will immediately return, it will not block until a connection
  761. ## is made. It is up to the caller to make sure the connection has been established
  762. ## by checking (using ``select``) whether the socket is writeable.
  763. ##
  764. ## **Note**: For SSL sockets, the ``handshake`` procedure must be called
  765. ## whenever the socket successfully connects to a server.
  766. var hints: AddrInfo
  767. var aiList: ptr AddrInfo = nil
  768. hints.ai_family = toInt(af)
  769. hints.ai_socktype = toInt(SOCK_STREAM)
  770. hints.ai_protocol = toInt(IPPROTO_TCP)
  771. gaiNim(name, port, hints, aiList)
  772. # try all possibilities:
  773. var success = false
  774. var lastError: OSErrorCode
  775. var it = aiList
  776. while it != nil:
  777. var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen)
  778. if ret == 0'i32:
  779. success = true
  780. break
  781. else:
  782. lastError = osLastError()
  783. when defined(windows):
  784. # Windows EINTR doesn't behave same as POSIX.
  785. if lastError.int32 == WSAEWOULDBLOCK:
  786. success = true
  787. break
  788. else:
  789. if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
  790. success = true
  791. break
  792. it = it.ai_next
  793. freeaddrinfo(aiList)
  794. if not success: raiseOSError(lastError)
  795. when defined(ssl):
  796. if socket.isSSL:
  797. socket.sslNoHandshake = true
  798. when defined(ssl):
  799. proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
  800. ## This proc needs to be called on a socket after it connects. This is
  801. ## only applicable when using ``connectAsync``.
  802. ## This proc performs the SSL handshake.
  803. ##
  804. ## Returns ``False`` whenever the socket is not yet ready for a handshake,
  805. ## ``True`` whenever handshake completed successfully.
  806. ##
  807. ## A SslError error is raised on any other errors.
  808. result = true
  809. if socket.isSSL:
  810. var ret = SSLConnect(socket.sslHandle)
  811. if ret <= 0:
  812. var errret = SSLGetError(socket.sslHandle, ret)
  813. case errret
  814. of SSL_ERROR_ZERO_RETURN:
  815. raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  816. of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
  817. SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE:
  818. return false
  819. of SSL_ERROR_WANT_X509_LOOKUP:
  820. raiseSslError("Function for x509 lookup has been called.")
  821. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  822. raiseSslError()
  823. else:
  824. raiseSslError("Unknown Error")
  825. socket.sslNoHandshake = false
  826. else:
  827. raiseSslError("Socket is not an SSL socket.")
  828. proc gotHandshake*(socket: Socket): bool =
  829. ## Determines whether a handshake has occurred between a client (``socket``)
  830. ## and the server that ``socket`` is connected to.
  831. ##
  832. ## Throws SslError if ``socket`` is not an SSL socket.
  833. if socket.isSSL:
  834. return not socket.sslNoHandshake
  835. else:
  836. raiseSslError("Socket is not an SSL socket.")
  837. proc timeValFromMilliseconds(timeout = 500): Timeval =
  838. if timeout != -1:
  839. var seconds = timeout div 1000
  840. when defined(posix):
  841. result.tv_sec = seconds.Time
  842. result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds
  843. else:
  844. result.tv_sec = seconds.int32
  845. result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
  846. proc createFdSet(fd: var TFdSet, s: seq[Socket], m: var int) =
  847. FD_ZERO(fd)
  848. for i in items(s):
  849. m = max(m, int(i.fd))
  850. FD_SET(i.fd, fd)
  851. proc pruneSocketSet(s: var seq[Socket], fd: var TFdSet) =
  852. var i = 0
  853. var L = s.len
  854. while i < L:
  855. if FD_ISSET(s[i].fd, fd) == 0'i32:
  856. # not set.
  857. s[i] = s[L-1]
  858. dec(L)
  859. else:
  860. inc(i)
  861. setLen(s, L)
  862. proc hasDataBuffered*(s: Socket): bool =
  863. ## Determines whether a socket has data buffered.
  864. result = false
  865. if s.isBuffered:
  866. result = s.bufLen > 0 and s.currPos != s.bufLen
  867. when defined(ssl):
  868. if s.isSSL and not result:
  869. result = s.sslHasPeekChar
  870. proc checkBuffer(readfds: var seq[Socket]): int =
  871. ## Checks the buffer of each socket in ``readfds`` to see whether there is data.
  872. ## Removes the sockets from ``readfds`` and returns the count of removed sockets.
  873. var res: seq[Socket] = @[]
  874. result = 0
  875. for s in readfds:
  876. if hasDataBuffered(s):
  877. inc(result)
  878. res.add(s)
  879. if result > 0:
  880. readfds = res
  881. proc select*(readfds, writefds, exceptfds: var seq[Socket],
  882. timeout = 500): int {.tags: [ReadIOEffect].} =
  883. ## Traditional select function. This function will return the number of
  884. ## sockets that are ready to be read from, written to, or which have errors.
  885. ## If there are none; 0 is returned.
  886. ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout.
  887. ##
  888. ## Sockets which are **not** ready for reading, writing or which don't have
  889. ## errors waiting on them are removed from the ``readfds``, ``writefds``,
  890. ## ``exceptfds`` sequences respectively.
  891. let buffersFilled = checkBuffer(readfds)
  892. if buffersFilled > 0:
  893. return buffersFilled
  894. var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
  895. var rd, wr, ex: TFdSet
  896. var m = 0
  897. createFdSet((rd), readfds, m)
  898. createFdSet((wr), writefds, m)
  899. createFdSet((ex), exceptfds, m)
  900. if timeout != -1:
  901. result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
  902. else:
  903. result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), nil))
  904. pruneSocketSet(readfds, (rd))
  905. pruneSocketSet(writefds, (wr))
  906. pruneSocketSet(exceptfds, (ex))
  907. proc select*(readfds, writefds: var seq[Socket],
  908. timeout = 500): int {.tags: [ReadIOEffect].} =
  909. ## Variant of select with only a read and write list.
  910. let buffersFilled = checkBuffer(readfds)
  911. if buffersFilled > 0:
  912. return buffersFilled
  913. var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
  914. var rd, wr: TFdSet
  915. var m = 0
  916. createFdSet((rd), readfds, m)
  917. createFdSet((wr), writefds, m)
  918. if timeout != -1:
  919. result = int(select(cint(m+1), addr(rd), addr(wr), nil, addr(tv)))
  920. else:
  921. result = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
  922. pruneSocketSet(readfds, (rd))
  923. pruneSocketSet(writefds, (wr))
  924. proc selectWrite*(writefds: var seq[Socket],
  925. timeout = 500): int {.tags: [ReadIOEffect].} =
  926. ## When a socket in ``writefds`` is ready to be written to then a non-zero
  927. ## value will be returned specifying the count of the sockets which can be
  928. ## written to. The sockets which **cannot** be written to will also be removed
  929. ## from ``writefds``.
  930. ##
  931. ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
  932. ## an unlimited time.
  933. var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
  934. var wr: TFdSet
  935. var m = 0
  936. createFdSet((wr), writefds, m)
  937. if timeout != -1:
  938. result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv)))
  939. else:
  940. result = int(select(cint(m+1), nil, addr(wr), nil, nil))
  941. pruneSocketSet(writefds, (wr))
  942. proc select*(readfds: var seq[Socket], timeout = 500): int =
  943. ## variant of select with a read list only
  944. let buffersFilled = checkBuffer(readfds)
  945. if buffersFilled > 0:
  946. return buffersFilled
  947. var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
  948. var rd: TFdSet
  949. var m = 0
  950. createFdSet((rd), readfds, m)
  951. if timeout != -1:
  952. result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
  953. else:
  954. result = int(select(cint(m+1), addr(rd), nil, nil, nil))
  955. pruneSocketSet(readfds, (rd))
  956. proc readIntoBuf(socket: Socket, flags: int32): int =
  957. result = 0
  958. when defined(ssl):
  959. if socket.isSSL:
  960. result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
  961. else:
  962. result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
  963. else:
  964. result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
  965. if result <= 0:
  966. socket.bufLen = 0
  967. socket.currPos = 0
  968. return result
  969. socket.bufLen = result
  970. socket.currPos = 0
  971. template retRead(flags, readBytes: int) {.dirty.} =
  972. let res = socket.readIntoBuf(flags.int32)
  973. if res <= 0:
  974. if readBytes > 0:
  975. return readBytes
  976. else:
  977. return res
  978. proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect].} =
  979. ## Receives data from a socket.
  980. ##
  981. ## **Note**: This is a low-level function, you may be interested in the higher
  982. ## level versions of this function which are also named ``recv``.
  983. if size == 0: return
  984. if socket.isBuffered:
  985. if socket.bufLen == 0:
  986. retRead(0'i32, 0)
  987. var read = 0
  988. while read < size:
  989. if socket.currPos >= socket.bufLen:
  990. retRead(0'i32, read)
  991. let chunk = min(socket.bufLen-socket.currPos, size-read)
  992. var d = cast[cstring](data)
  993. copyMem(addr(d[read]), addr(socket.buffer[socket.currPos]), chunk)
  994. read.inc(chunk)
  995. socket.currPos.inc(chunk)
  996. result = read
  997. else:
  998. when defined(ssl):
  999. if socket.isSSL:
  1000. if socket.sslHasPeekChar:
  1001. copyMem(data, addr(socket.sslPeekChar), 1)
  1002. socket.sslHasPeekChar = false
  1003. if size-1 > 0:
  1004. var d = cast[cstring](data)
  1005. result = SSLRead(socket.sslHandle, addr(d[1]), size-1) + 1
  1006. else:
  1007. result = 1
  1008. else:
  1009. result = SSLRead(socket.sslHandle, data, size)
  1010. else:
  1011. result = recv(socket.fd, data, size.cint, 0'i32)
  1012. else:
  1013. result = recv(socket.fd, data, size.cint, 0'i32)
  1014. proc waitFor(socket: Socket, waited: var float, timeout, size: int,
  1015. funcName: string): int {.tags: [TimeEffect].} =
  1016. ## determines the amount of characters that can be read. Result will never
  1017. ## be larger than ``size``. For unbuffered sockets this will be ``1``.
  1018. ## For buffered sockets it can be as big as ``BufferSize``.
  1019. ##
  1020. ## If this function does not determine that there is data on the socket
  1021. ## within ``timeout`` ms, an ETimeout error will be raised.
  1022. result = 1
  1023. if size <= 0: assert false
  1024. if timeout == -1: return size
  1025. if socket.isBuffered and socket.bufLen != 0 and socket.bufLen != socket.currPos:
  1026. result = socket.bufLen - socket.currPos
  1027. result = min(result, size)
  1028. else:
  1029. if timeout - int(waited * 1000.0) < 1:
  1030. raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
  1031. when defined(ssl):
  1032. if socket.isSSL:
  1033. if socket.hasDataBuffered:
  1034. # sslPeekChar is present.
  1035. return 1
  1036. let sslPending = SSLPending(socket.sslHandle)
  1037. if sslPending != 0:
  1038. return sslPending
  1039. var s = @[socket]
  1040. var startTime = epochTime()
  1041. let selRet = select(s, timeout - int(waited * 1000.0))
  1042. if selRet < 0: raiseOSError(osLastError())
  1043. if selRet != 1:
  1044. raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
  1045. waited += (epochTime() - startTime)
  1046. proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
  1047. tags: [ReadIOEffect, TimeEffect].} =
  1048. ## overload with a ``timeout`` parameter in milliseconds.
  1049. var waited = 0.0 # number of seconds already waited
  1050. var read = 0
  1051. while read < size:
  1052. let avail = waitFor(socket, waited, timeout, size-read, "recv")
  1053. var d = cast[cstring](data)
  1054. result = recv(socket, addr(d[read]), avail)
  1055. if result == 0: break
  1056. if result < 0:
  1057. return result
  1058. inc(read, result)
  1059. result = read
  1060. proc recv*(socket: Socket, data: var string, size: int, timeout = -1): int =
  1061. ## Higher-level version of ``recv``.
  1062. ##
  1063. ## When 0 is returned the socket's connection has been closed.
  1064. ##
  1065. ## This function will throw an OSError exception when an error occurs. A value
  1066. ## lower than 0 is never returned.
  1067. ##
  1068. ## A timeout may be specified in milliseconds, if enough data is not received
  1069. ## within the time specified an ETimeout exception will be raised.
  1070. ##
  1071. ## **Note**: ``data`` must be initialised.
  1072. data.setLen(size)
  1073. result = recv(socket, cstring(data), size, timeout)
  1074. if result < 0:
  1075. data.setLen(0)
  1076. socket.raiseSocketError(result)
  1077. data.setLen(result)
  1078. proc recvAsync*(socket: Socket, data: var string, size: int): int =
  1079. ## Async version of ``recv``.
  1080. ##
  1081. ## When socket is non-blocking and no data is available on the socket,
  1082. ## ``-1`` will be returned and ``data`` will be ``""``.
  1083. ##
  1084. ## **Note**: ``data`` must be initialised.
  1085. data.setLen(size)
  1086. result = recv(socket, cstring(data), size)
  1087. if result < 0:
  1088. data.setLen(0)
  1089. socket.raiseSocketError(async = true)
  1090. result = -1
  1091. data.setLen(result)
  1092. proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
  1093. if socket.isBuffered:
  1094. result = 1
  1095. if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
  1096. var res = socket.readIntoBuf(0'i32)
  1097. if res <= 0:
  1098. result = res
  1099. c = socket.buffer[socket.currPos]
  1100. else:
  1101. when defined(ssl):
  1102. if socket.isSSL:
  1103. if not socket.sslHasPeekChar:
  1104. result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
  1105. socket.sslHasPeekChar = true
  1106. c = socket.sslPeekChar
  1107. return
  1108. result = recv(socket.fd, addr(c), 1, MSG_PEEK)
  1109. proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {.
  1110. tags: [ReadIOEffect, TimeEffect], deprecated.} =
  1111. ## Receive a line of data from ``socket``.
  1112. ##
  1113. ## If a full line is received ``\r\L`` is not
  1114. ## added to ``line``, however if solely ``\r\L`` is received then ``line``
  1115. ## will be set to it.
  1116. ##
  1117. ## ``True`` is returned if data is available. ``False`` suggests an
  1118. ## error, OSError exceptions are not raised and ``False`` is simply returned
  1119. ## instead.
  1120. ##
  1121. ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
  1122. ## will be returned.
  1123. ##
  1124. ## A timeout can be specified in milliseconds, if data is not received within
  1125. ## the specified time an ETimeout exception will be raised.
  1126. ##
  1127. ## **Deprecated since version 0.9.2**: This function has been deprecated in
  1128. ## favour of readLine.
  1129. template addNLIfEmpty(): untyped =
  1130. if line.len == 0:
  1131. line.add("\c\L")
  1132. var waited = 0.0
  1133. setLen(line.string, 0)
  1134. while true:
  1135. var c: char
  1136. discard waitFor(socket, waited, timeout, 1, "recvLine")
  1137. var n = recv(socket, addr(c), 1)
  1138. if n < 0: return
  1139. elif n == 0: return true
  1140. if c == '\r':
  1141. discard waitFor(socket, waited, timeout, 1, "recvLine")
  1142. n = peekChar(socket, c)
  1143. if n > 0 and c == '\L':
  1144. discard recv(socket, addr(c), 1)
  1145. elif n <= 0: return false
  1146. addNLIfEmpty()
  1147. return true
  1148. elif c == '\L':
  1149. addNLIfEmpty()
  1150. return true
  1151. add(line.string, c)
  1152. proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {.
  1153. tags: [ReadIOEffect, TimeEffect].} =
  1154. ## Reads a line of data from ``socket``.
  1155. ##
  1156. ## If a full line is read ``\r\L`` is not
  1157. ## added to ``line``, however if solely ``\r\L`` is read then ``line``
  1158. ## will be set to it.
  1159. ##
  1160. ## If the socket is disconnected, ``line`` will be set to ``""``.
  1161. ##
  1162. ## An OSError exception will be raised in the case of a socket error.
  1163. ##
  1164. ## A timeout can be specified in milliseconds, if data is not received within
  1165. ## the specified time an ETimeout exception will be raised.
  1166. template addNLIfEmpty(): untyped =
  1167. if line.len == 0:
  1168. line.add("\c\L")
  1169. var waited = 0.0
  1170. setLen(line.string, 0)
  1171. while true:
  1172. var c: char
  1173. discard waitFor(socket, waited, timeout, 1, "readLine")
  1174. var n = recv(socket, addr(c), 1)
  1175. if n < 0: socket.raiseSocketError()
  1176. elif n == 0: return
  1177. if c == '\r':
  1178. discard waitFor(socket, waited, timeout, 1, "readLine")
  1179. n = peekChar(socket, c)
  1180. if n > 0 and c == '\L':
  1181. discard recv(socket, addr(c), 1)
  1182. elif n <= 0: socket.raiseSocketError()
  1183. addNLIfEmpty()
  1184. return
  1185. elif c == '\L':
  1186. addNLIfEmpty()
  1187. return
  1188. add(line.string, c)
  1189. proc recvLineAsync*(socket: Socket,
  1190. line: var TaintedString): RecvLineResult {.tags: [ReadIOEffect], deprecated.} =
  1191. ## Similar to ``recvLine`` but designed for non-blocking sockets.
  1192. ##
  1193. ## The values of the returned enum should be pretty self explanatory:
  1194. ##
  1195. ## * If a full line has been retrieved; ``RecvFullLine`` is returned.
  1196. ## * If some data has been retrieved; ``RecvPartialLine`` is returned.
  1197. ## * If the socket has been disconnected; ``RecvDisconnected`` is returned.
  1198. ## * If call to ``recv`` failed; ``RecvFail`` is returned.
  1199. ##
  1200. ## **Deprecated since version 0.9.2**: This function has been deprecated in
  1201. ## favour of readLineAsync.
  1202. setLen(line.string, 0)
  1203. while true:
  1204. var c: char
  1205. var n = recv(socket, addr(c), 1)
  1206. if n < 0:
  1207. return (if line.len == 0: RecvFail else: RecvPartialLine)
  1208. elif n == 0:
  1209. return (if line.len == 0: RecvDisconnected else: RecvPartialLine)
  1210. if c == '\r':
  1211. n = peekChar(socket, c)
  1212. if n > 0 and c == '\L':
  1213. discard recv(socket, addr(c), 1)
  1214. elif n <= 0:
  1215. return (if line.len == 0: RecvFail else: RecvPartialLine)
  1216. return RecvFullLine
  1217. elif c == '\L': return RecvFullLine
  1218. add(line.string, c)
  1219. proc readLineAsync*(socket: Socket,
  1220. line: var TaintedString): ReadLineResult {.tags: [ReadIOEffect].} =
  1221. ## Similar to ``recvLine`` but designed for non-blocking sockets.
  1222. ##
  1223. ## The values of the returned enum should be pretty self explanatory:
  1224. ##
  1225. ## * If a full line has been retrieved; ``ReadFullLine`` is returned.
  1226. ## * If some data has been retrieved; ``ReadPartialLine`` is returned.
  1227. ## * If the socket has been disconnected; ``ReadDisconnected`` is returned.
  1228. ## * If no data could be retrieved; ``ReadNone`` is returned.
  1229. ## * If call to ``recv`` failed; **an OSError exception is raised.**
  1230. setLen(line.string, 0)
  1231. template errorOrNone =
  1232. socket.raiseSocketError(async = true)
  1233. return ReadNone
  1234. while true:
  1235. var c: char
  1236. var n = recv(socket, addr(c), 1)
  1237. #echo(n)
  1238. if n < 0:
  1239. if line.len == 0: errorOrNone else: return ReadPartialLine
  1240. elif n == 0:
  1241. return (if line.len == 0: ReadDisconnected else: ReadPartialLine)
  1242. if c == '\r':
  1243. n = peekChar(socket, c)
  1244. if n > 0 and c == '\L':
  1245. discard recv(socket, addr(c), 1)
  1246. elif n <= 0:
  1247. if line.len == 0: errorOrNone else: return ReadPartialLine
  1248. return ReadFullLine
  1249. elif c == '\L': return ReadFullLine
  1250. add(line.string, c)
  1251. proc recv*(socket: Socket): TaintedString {.tags: [ReadIOEffect], deprecated.} =
  1252. ## receives all the available data from the socket.
  1253. ## Socket errors will result in an ``OSError`` error.
  1254. ## If socket is not a connectionless socket and socket is not connected
  1255. ## ``""`` will be returned.
  1256. ##
  1257. ## **Deprecated since version 0.9.2**: This function is not safe for use.
  1258. const bufSize = 4000
  1259. result = newStringOfCap(bufSize).TaintedString
  1260. var pos = 0
  1261. while true:
  1262. var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
  1263. if bytesRead == -1: raiseOSError(osLastError())
  1264. setLen(result.string, pos + bytesRead)
  1265. if bytesRead != bufSize-1: break
  1266. # increase capacity:
  1267. setLen(result.string, result.string.len + bufSize)
  1268. inc(pos, bytesRead)
  1269. when false:
  1270. var buf = newString(bufSize)
  1271. result = TaintedString""
  1272. while true:
  1273. var bytesRead = recv(socket, cstring(buf), bufSize-1)
  1274. # Error
  1275. if bytesRead == -1: OSError(osLastError())
  1276. buf[bytesRead] = '\0' # might not be necessary
  1277. setLen(buf, bytesRead)
  1278. add(result.string, buf)
  1279. if bytesRead != bufSize-1: break
  1280. {.push warning[deprecated]: off.}
  1281. proc recvTimeout*(socket: Socket, timeout: int): TaintedString {.
  1282. tags: [ReadIOEffect], deprecated.} =
  1283. ## overloaded variant to support a ``timeout`` parameter, the ``timeout``
  1284. ## parameter specifies the amount of milliseconds to wait for data on the
  1285. ## socket.
  1286. ##
  1287. ## **Deprecated since version 0.9.2**: This function is not safe for use.
  1288. if socket.bufLen == 0:
  1289. var s = @[socket]
  1290. if s.select(timeout) != 1:
  1291. raise newException(TimeoutError, "Call to recv() timed out.")
  1292. return socket.recv
  1293. {.pop.}
  1294. proc recvAsync*(socket: Socket, s: var TaintedString): bool {.
  1295. tags: [ReadIOEffect], deprecated.} =
  1296. ## receives all the data from a non-blocking socket. If socket is non-blocking
  1297. ## and there are no messages available, `False` will be returned.
  1298. ## Other socket errors will result in an ``OSError`` error.
  1299. ## If socket is not a connectionless socket and socket is not connected
  1300. ## ``s`` will be set to ``""``.
  1301. ##
  1302. ## **Deprecated since version 0.9.2**: This function is not safe for use.
  1303. const bufSize = 1000
  1304. # ensure bufSize capacity:
  1305. setLen(s.string, bufSize)
  1306. setLen(s.string, 0)
  1307. var pos = 0
  1308. while true:
  1309. var bytesRead = recv(socket, addr(string(s)[pos]), bufSize-1)
  1310. when defined(ssl):
  1311. if socket.isSSL:
  1312. if bytesRead <= 0:
  1313. var ret = SSLGetError(socket.sslHandle, bytesRead.cint)
  1314. case ret
  1315. of SSL_ERROR_ZERO_RETURN:
  1316. raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  1317. of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  1318. raiseSslError("Unexpected error occurred.") # This should just not happen.
  1319. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
  1320. return false
  1321. of SSL_ERROR_WANT_X509_LOOKUP:
  1322. raiseSslError("Function for x509 lookup has been called.")
  1323. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  1324. raiseSslError()
  1325. else: raiseSslError("Unknown Error")
  1326. if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
  1327. let err = osLastError()
  1328. when defined(windows):
  1329. if err.int32 == WSAEWOULDBLOCK:
  1330. return false
  1331. else: raiseOSError(err)
  1332. else:
  1333. if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
  1334. return false
  1335. else: raiseOSError(err)
  1336. setLen(s.string, pos + bytesRead)
  1337. if bytesRead != bufSize-1: break
  1338. # increase capacity:
  1339. setLen(s.string, s.string.len + bufSize)
  1340. inc(pos, bytesRead)
  1341. result = true
  1342. proc recvFrom*(socket: Socket, data: var string, length: int,
  1343. address: var string, port: var Port, flags = 0'i32): int {.
  1344. tags: [ReadIOEffect].} =
  1345. ## Receives data from ``socket``. This function should normally be used with
  1346. ## connection-less sockets (UDP sockets).
  1347. ##
  1348. ## If an error occurs the return value will be ``-1``. Otherwise the return
  1349. ## value will be the length of data received.
  1350. ##
  1351. ## **Warning:** This function does not yet have a buffered implementation,
  1352. ## so when ``socket`` is buffered the non-buffered implementation will be
  1353. ## used. Therefore if ``socket`` contains something in its buffer this
  1354. ## function will make no effort to return it.
  1355. # TODO: Buffered sockets
  1356. data.setLen(length)
  1357. var sockAddress: Sockaddr_in
  1358. var addrLen = sizeof(sockAddress).SockLen
  1359. result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
  1360. cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
  1361. if result != -1:
  1362. data.setLen(result)
  1363. address = $inet_ntoa(sockAddress.sin_addr)
  1364. port = ntohs(sockAddress.sin_port).Port
  1365. proc recvFromAsync*(socket: Socket, data: var string, length: int,
  1366. address: var string, port: var Port,
  1367. flags = 0'i32): bool {.tags: [ReadIOEffect].} =
  1368. ## Variant of ``recvFrom`` for non-blocking sockets. Unlike ``recvFrom``,
  1369. ## this function will raise an OSError error whenever a socket error occurs.
  1370. ##
  1371. ## If there is no data to be read from the socket ``False`` will be returned.
  1372. result = true
  1373. var callRes = recvFrom(socket, data, length, address, port, flags)
  1374. if callRes < 0:
  1375. let err = osLastError()
  1376. when defined(windows):
  1377. if err.int32 == WSAEWOULDBLOCK:
  1378. return false
  1379. else: raiseOSError(err)
  1380. else:
  1381. if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
  1382. return false
  1383. else: raiseOSError(err)
  1384. proc skip*(socket: Socket) {.tags: [ReadIOEffect], deprecated.} =
  1385. ## skips all the data that is pending for the socket
  1386. ##
  1387. ## **Deprecated since version 0.9.2**: This function is not safe for use.
  1388. const bufSize = 1000
  1389. var buf = alloc(bufSize)
  1390. while recv(socket, buf, bufSize) == bufSize: discard
  1391. dealloc(buf)
  1392. proc skip*(socket: Socket, size: int, timeout = -1) =
  1393. ## Skips ``size`` amount of bytes.
  1394. ##
  1395. ## An optional timeout can be specified in milliseconds, if skipping the
  1396. ## bytes takes longer than specified an ETimeout exception will be raised.
  1397. ##
  1398. ## Returns the number of skipped bytes.
  1399. var waited = 0.0
  1400. var dummy = alloc(size)
  1401. var bytesSkipped = 0
  1402. while bytesSkipped != size:
  1403. let avail = waitFor(socket, waited, timeout, size-bytesSkipped, "skip")
  1404. bytesSkipped += recv(socket, dummy, avail)
  1405. dealloc(dummy)
  1406. proc send*(socket: Socket, data: pointer, size: int): int {.
  1407. tags: [WriteIOEffect].} =
  1408. ## sends data to a socket.
  1409. when defined(ssl):
  1410. if socket.isSSL:
  1411. return SSLWrite(socket.sslHandle, cast[cstring](data), size)
  1412. when defined(windows) or defined(macosx):
  1413. result = send(socket.fd, data, size.cint, 0'i32)
  1414. else:
  1415. when defined(solaris):
  1416. const MSG_NOSIGNAL = 0
  1417. result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
  1418. proc send*(socket: Socket, data: string) {.tags: [WriteIOEffect].} =
  1419. ## sends data to a socket.
  1420. if socket.nonblocking:
  1421. raise newException(ValueError, "This function cannot be used on non-blocking sockets.")
  1422. let sent = send(socket, cstring(data), data.len)
  1423. if sent < 0:
  1424. when defined(ssl):
  1425. if socket.isSSL:
  1426. raiseSslError()
  1427. raiseOSError(osLastError())
  1428. if sent != data.len:
  1429. raiseOSError(osLastError(), "Could not send all data.")
  1430. proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} =
  1431. ## sends data to a non-blocking socket.
  1432. ## Returns ``0`` if no data could be sent, if data has been sent
  1433. ## returns the amount of bytes of ``data`` that was successfully sent. This
  1434. ## number may not always be the length of ``data`` but typically is.
  1435. ##
  1436. ## An OSError (or SslError if socket is an SSL socket) exception is raised if an error
  1437. ## occurs.
  1438. result = send(socket, cstring(data), data.len)
  1439. when defined(ssl):
  1440. if socket.isSSL:
  1441. if result <= 0:
  1442. let ret = SSLGetError(socket.sslHandle, result.cint)
  1443. case ret
  1444. of SSL_ERROR_ZERO_RETURN:
  1445. raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
  1446. of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
  1447. raiseSslError("Unexpected error occurred.") # This should just not happen.
  1448. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
  1449. return 0
  1450. of SSL_ERROR_WANT_X509_LOOKUP:
  1451. raiseSslError("Function for x509 lookup has been called.")
  1452. of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
  1453. raiseSslError()
  1454. else: raiseSslError("Unknown Error")
  1455. else:
  1456. return
  1457. if result == -1:
  1458. let err = osLastError()
  1459. when defined(windows):
  1460. if err.int32 == WSAEINPROGRESS:
  1461. return 0
  1462. else: raiseOSError(err)
  1463. else:
  1464. if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
  1465. return 0
  1466. else: raiseOSError(err)
  1467. proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
  1468. ## safe alternative to ``send``. Does not raise an OSError when an error occurs,
  1469. ## and instead returns ``false`` on failure.
  1470. result = send(socket, cstring(data), data.len) == data.len
  1471. proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
  1472. size: int, af: Domain = AF_INET, flags = 0'i32): int {.
  1473. tags: [WriteIOEffect].} =
  1474. ## low-level sendTo proc. This proc sends ``data`` to the specified ``address``,
  1475. ## which may be an IP address or a hostname, if a hostname is specified
  1476. ## this function will try each IP of that hostname.
  1477. ##
  1478. ## **Note:** This proc is not available for SSL sockets.
  1479. var hints: AddrInfo
  1480. var aiList: ptr AddrInfo = nil
  1481. hints.ai_family = toInt(af)
  1482. hints.ai_socktype = toInt(SOCK_STREAM)
  1483. hints.ai_protocol = toInt(IPPROTO_TCP)
  1484. gaiNim(address, port, hints, aiList)
  1485. # try all possibilities:
  1486. var success = false
  1487. var it = aiList
  1488. while it != nil:
  1489. result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
  1490. it.ai_addrlen.SockLen)
  1491. if result != -1'i32:
  1492. success = true
  1493. break
  1494. it = it.ai_next
  1495. freeaddrinfo(aiList)
  1496. proc sendTo*(socket: Socket, address: string, port: Port,
  1497. data: string): int {.tags: [WriteIOEffect].} =
  1498. ## Friendlier version of the low-level ``sendTo``.
  1499. result = socket.sendTo(address, port, cstring(data), data.len)
  1500. when defined(Windows):
  1501. const
  1502. IOCPARM_MASK = 127
  1503. IOC_IN = int(-2147483648)
  1504. FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or
  1505. (102 shl 8) or 126
  1506. proc ioctlsocket(s: SocketHandle, cmd: clong,
  1507. argptr: ptr clong): cint {.
  1508. stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".}
  1509. proc setBlocking(s: Socket, blocking: bool) =
  1510. when defined(Windows):
  1511. var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
  1512. if ioctlsocket(s.fd, FIONBIO, addr(mode)) == -1:
  1513. raiseOSError(osLastError())
  1514. else: # BSD sockets
  1515. var x: int = fcntl(s.fd, F_GETFL, 0)
  1516. if x == -1:
  1517. raiseOSError(osLastError())
  1518. else:
  1519. var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
  1520. if fcntl(s.fd, F_SETFL, mode) == -1:
  1521. raiseOSError(osLastError())
  1522. s.nonblocking = not blocking
  1523. discard """ proc setReuseAddr*(s: Socket) =
  1524. var blah: int = 1
  1525. var mode = SO_REUSEADDR
  1526. if setsockopt(s.fd, SOL_SOCKET, mode, addr blah, TSOcklen(sizeof(int))) == -1:
  1527. raiseOSError(osLastError()) """
  1528. proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
  1529. af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} =
  1530. ## Connects to server as specified by ``address`` on port specified by ``port``.
  1531. ##
  1532. ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
  1533. ## the connection to the server to be made.
  1534. let originalStatus = not socket.nonblocking
  1535. socket.setBlocking(false)
  1536. socket.connectAsync(address, port, af)
  1537. var s: seq[Socket] = @[socket]
  1538. if selectWrite(s, timeout) != 1:
  1539. raise newException(TimeoutError, "Call to 'connect' timed out.")
  1540. else:
  1541. when defined(ssl):
  1542. if socket.isSSL:
  1543. socket.setBlocking(true)
  1544. doAssert socket.handshake()
  1545. socket.setBlocking(originalStatus)
  1546. proc isSSL*(socket: Socket): bool = return socket.isSSL
  1547. ## Determines whether ``socket`` is a SSL socket.
  1548. proc getFD*(socket: Socket): SocketHandle = return socket.fd
  1549. ## Returns the socket's file descriptor
  1550. proc isBlocking*(socket: Socket): bool = not socket.nonblocking
  1551. ## Determines whether ``socket`` is blocking.
  1552. when defined(Windows):
  1553. var wsa: WSAData
  1554. if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())