🙬 ESP32forth Sockets 🙮
       🙚     🙘
    August 13, 2022

🙬 Berkeley Sockets 🙮
 
• THE Internet Networking API
• Released in 1983, free of AT&T in 1989
• File descriptors as network endpoints
• Multi-protocol and Multi-transport
• Designed to support concurrency

🙬 Multi-Transport 🙮
 
AF_INET  - IPv4
AF_INET6 - IPv6
AF_UNIX  - domain socket

🙬 IPv4 & IPv6 🙮
  
IPv4 192.168.0.1
IPv6 2001:0db8:85a3:0000:0000:8a2e:0370:7334
     2001:db8:85a3:::8a2e:370:7334

🙬 Multi-Protocol 🙮
 
SOCK_STREAM - TCP
SOCK_DGRAM  - UDP

🙬 TCP 🙮
 
• Transmission Control Protocol
• Bi-directional byte stream
• Connection oriented
  • Multiple inbound connections
• Reliable delivery
• Auto-adapts to network conditions

🙬 TCP Use-cases 🙮
 
• HTTP / HTTPS
• SSH
• Telnet
• FTP

🙬 UDP 🙮
 
• User Datagram Protocol
• Variable length packets
  • Up to 65,527 bytes
  • About ~500 bytes practical
• Connectionless
• Unreliabled, packets can be:
  • lost
  • corrupt
  • repeated
  • out of order

🙬 UDP Use-cases 🙮
 
• DNS
• DHCP
• Video/Audio streaming

🙬 struct sockaddr_in 🙮
 
[    ][    ][    ][    ]
------------------------
[  family  ][   port   ]
------------------------
[       address        ]
------------------------
[       unused         ]
------------------------
[       unused         ]
------------------------

🙬 struct sockaddr_in 🙮
 
[    ][    ][    ][    ]
------------------------
[ 16 ][fam ][   port   ]
------------------------
[       address        ]
------------------------
[       unused         ]
------------------------
[       unused         ]
------------------------

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET
    unsigned short   sin_port;     // e.g. htons(1234)
    struct in_addr   sin_addr;     // IP address big-endian
    char             sin_zero[8];  // unused
};

struct sockaddr_in {
    char             sin_len;      // sizeof(sockaddr_in)
    char             sin_family;   // e.g. AF_INET
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // IP address big-endian
    char             sin_zero[8];  // unused
};

🙬 struct sockaddr_in 🙮
 
[    ][    ][    ][    ][    ][    ][    ][    ]
------------------------------------------------
[  family  ][   port   ][       flow info      ]
------------------------------------------------
[                   address                    ]
------------------------------------------------
[       scope id       ]
------------------------

🙬 Big-Endian 🙮
  
ntohs htons
ntohl htonl

sockaddr addr  ( AF_INET pre-set )
->addr@ ( a -- ip )
->addr! ( ip a -- )
->port@ ( a -- port )
->port! ( port a -- )

🙬 Making a TCP Connection 🙮
   
gethostbyname(hostname)
socket(domain, type, protocol)
connect(sock, addr, addrlen)
send(sock, data, datalen, flags)     
recv(sock, data, datalen, flags)
close(sock)

🙬 Making a TCP Connection 🙮
   
gethostbyname - lookup DNS
socket        - make a socket
connect       - connect to an address
send          - send data
recv          - receive data
close         - close connection

🙬 Looking up a Host 🙮
 
struct hostent {
    char  *h_name;            /* official name of host */
    char **h_aliases;         /* alias list */
    int    h_addrtype;        /* host address type */
    int    h_length;          /* length of address */
    char **h_addr_list;       /* list of addresses */
}
#define h_addr h_addr_list[0] /* for backward compatibility */

( Lookup a Host ) 
z" google.com" gethostbyname constant google.com
google.com ->h_addr ip.
142.251.46.238 ok

( Fill in an address + port )
sockaddr googleaddr
80 googleaddr ->port!
google.com ->h_addr googleaddr ->addr!
 
( Create a socket and connect )
AF_INET SOCK_STREAM 0 socket value sock
sock googleaddr sizeof(sockaddr_in) connect throw

( Send an HTTP request )
s" GET / HTTP/1.0" sock write-file throw
: semit ( ch s -- ) swap >r rp@ swap 1 swap write-file throw rdrop ;
: semit ( ch s -- ) swap >r rp@ 1 0 send 0< throw rdrop ;
: scr   13 sock semit 10 sock semit ;
scr scr
   
( Read and print part of reply )
here 100000 sock read-file throw constant len
here len type

🙬 A TCP Server 🙮
   
socket(domain, type, protocol)
bind(sock, addr, addrlen)
listen(sock, backlog)
accept(sock, addr, *addrlen)
send(sock, data, datalen, flags)          
recv(sock, data, datalen, flags)
close(sock)

🙬 A TCP Server 🙮
   
socket  - make a socket
bind    - bind it to a port
listen  - listen for up to n connections
accept  - accept a connection (new socket)
send    - send data
recv    - receive data
close   - close the connection

🙬 Server Challenges 🙮
    
• Management multiple connections
• Blocking on connections
• poll / select
  • fd_set etc. absent

🙬 A UDP Client/Server 🙮
  
gethostbyname(hostname)
socket(domain, type, protocol)
bind(sock, addr, addrlen)
sendto(sock, data, datalen, flags, addr, addrlen)
recvfrom(sock, data, datalen, flags, addr, *addrlen)
close(sock)

🙬 A UDP Client/Server 🙮
  
gethostbyname - lookup other hosts
socket        - make a socket
bind          - bind it to an incoming port         
sendto        - send a packet
recvfrom      - receive a packet
close         - close the binding

( Create a addres to listen on )
sockaddr incoming
9999 incoming ->port!
 
( Create a socket and bind to address )
AF_INET SOCK_DGRAM 0 socket value sockfd
sockfd non-block throw  ( Optionally make non-blocking )
sockfd incoming sizeof(sockaddr_in) bind throw

( Read an incoming packet )
sockaddr received
variable received-len sizeof(sockaddr_in) received-len !
sockfd msg len 0 received received-len recvfrom to len
received ->addr@ ip. ." :" received ->port@ . 
    space space msg swap type cr

( Send an outgoing packet )
sockaddr outgoing
: say ( port -- "host" )
  ( Setup address )
  outgoing ->port!
  bl parse s>z gethostbyname ->h_addr outgoing ->addr!
  ( Sent rest of the parse buffer as the message )
  sockfd tib >in @ + #tib @ >in @ -
    0 outgoing sizeof(sockaddr_in) sendto drop
  #tib @ >in !
;

🙬 Visual Editor (BONUS) 🙮
  
• visual edit /spiffs/filename
• Arrows / PgUp / PgDn
• Ctrl-S to save
• Ctrl-X to exit
• Very wasteful, WIP

DEMO & QUESTIONS?
       🏵
   Thank you!