all repos — min @ db83f364723f6574ffbff6c58e807178051ac98a

A small but practical concatenative programming language.

lib/min_net.nim

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
import net, nativesockets, strutils, critbits
import 
  ../core/types,
  ../core/parser,
  ../core/interpreter, 
  ../core/utils

# Network

proc net_module*(i: In)=

  i.define("net")
  
    .symbol("^socket") do (i: In):
      var q: MinValue
      i.reqQuotation q
      # (ipv4 stream tcp)
      if q.qVal.len < 3 or not (q.qVal[0].isSymbol and q.qVal[1].isSymbol and q.qVal[2].isSymbol):
        raiseInvalid("Quotation must contain three symbols for <domain> <type> <protocol>")
      let vals = q.qVal
      if not ["ipv4", "ipv6"].contains(vals[0].symVal):
        raiseInvalid("Domain symbol must be 'ipv4' or 'ipv6'")
      if not ["stream", "dgram"].contains(vals[1].symVal):
        raiseInvalid("Type symbol must be 'stream' or 'dgram'")
      if not ["tcp", "udp"].contains(vals[2].symVal):
        raiseInvalid("Protocol symbol must be 'tcp' or 'udp'")
      var 
        domain: Domain
        sockettype: SockType
        protocol: Protocol
        sDomain, sSockType, sProtocol: string
      # Process domain
      if vals[0].symVal == "ipv4":
        sDomain = "ipv4"
        domain = AF_INET
      else:
        sDomain = "ipv6"
        domain = AF_INET6
      if vals[1].symVal == "stream":
        sSockType = "stream"
        sockettype = SOCK_STREAM
      else:
        sSockType = "dgram"
        sockettype = SOCK_DGRAM
      if vals[2].symVal == "tcp":
        sProtocol = "tcp"
        protocol = IPPROTO_TCP
      else:
        sProtocol = "udp"
        protocol = IPPROTO_UDP
      var socket = newSocket(domain, sockettype, protocol)
      var qs = @[
        @["domain".newSym, sDomain.newVal].newVal, 
        @["type".newSym, sSockType.newVal].newVal,
        @["protocol".newSym, sProtocol.newVal].newVal
      ].newVal
      qs.objType = "socket"
      qs.obj = socket[].addr
      i.newScope("<socket>", qs)

      var sAddress: string
      var sPort: BiggestInt
  
      qs.scope
        .symbol("close") do (i: In):
          qs.to(Socket).close()
    
        .symbol("listen") do (i: In):
          var port: MinValue
          i.reqInt port
          var socket = qs.to(Socket)
          sAddress = "0.0.0.0"
          sPort = port.intVal
          socket.bindAddr(Port(sPort))
          qs.qVal.add @["address".newSym, sAddress.newVal].newVal
          qs.qVal.add @["port".newSym, sPort.newVal].newVal
          socket.listen()
          i.push qs
    
        .symbol("accept") do (i: In):
          # Open same socket type as server
          i.eval "($1 $2 $3) net %^socket" % [sDomain, sSockType, sProtocol]
          var clientVal: MinValue
          i.reqObject "socket", clientVal
          var client = clientVal.to(Socket)
          var address = ""
          qs.to(Socket).acceptAddr(client, address)
          clientVal.qVal.add address.newSym
          i.push clientVal
    
        .symbol("connect") do (i: In):
          var address, port: MinValue
          i.reqInt port
          i.reqStringLike address
          qs.to(Socket).connect(address.strVal, Port(port.intVal))
          #var qc = @[
          #  @["domain".newSym, sDomain.newVal].newVal, 
          #  @["type".newSym, sSockType.newVal].newVal, 
          #  @["protocol".newSym, sProtocol.newVal].newVal
          #].newVal
          qs.qVal.add @["address".newSym, address.getString.newVal].newVal
          qs.qVal.add @["port".newSym, port].newVal
          i.push qs
    
        .symbol("send") do (i: In):
          echo "sending"
          var s: MinValue
          i.reqString s
          qs.to(Socket).send s.strVal
          i.push qs
    
        .symbol("recv") do (i: In):
          var size: MinValue
          i.reqInt size
          var s = ""
          discard qs.to(Socket).recv(s, size.intVal.int)
          i.push qs
          i.push s.newVal
    
        .symbol("recv-line") do (i: In):
          var s = ""
          qs.to(Socket).readLine(s)
          i.push @[qs]
          i.push s.newVal
    
        .finalize()
        
      i.push qs
  
    .finalize()