001 // vim: set ft=cpp:
002 
003 include "::/Doc/Comm"
004 
005 #define CMD_SOCKET        1
006 #define CMD_CLOSE         2
007 #define CMD_CONNECT_TCP   3
008 #define CMD_SEND          4
009 #define CMD_RECV          5
010 #define CMD_HELLO         0xAA
011 
012 #define SOCK_STREAM 1
013 #define SOCK_DGRAM  2
014 #define SOCK_RAW    3
015 
016 #define AF_UNSPEC   0
017 #define AF_INET     2
018 #define AF_INET6    10
019 
020 #define SNAIL_COM         3
021 #define SNAIL_TIMEOUT     500
022 #define SNAIL_FRAME_SIZE  112
023 
024 static CComm* snail_comm;
025 
026 static U8 ReadByte() {
027   U8 chr;
028   while (1) {
029     if (FifoU8Rem(snail_comm->RX_fifo, &chr))
030       return chr;
031     else
032       Yield;
033   }
034 }
035 
036 static I8 ReadI8() {
037   I8 chr;
038   while (1) {
039     if (FifoU8Rem(snail_comm->RX_fifo, &chr))
040       return chr;
041     else
042       Yield;
043   }
044 }
045 
046 static U0 ReadBlock(U8* buf, I64 count) {
047   while (count) {
048     if (FifoU8Rem(snail_comm->RX_fifo, buf)) {
049       buf++;
050       count--;
051     }
052     else Yield;
053   }
054 }
055 
056 I64 SocketInit() {
057   U8 chr;
058 
059   snail_comm = CommInit8n1(SNAIL_COM, 115200);
060   while (FifoU8Rem(snail_comm->RX_fifo, &chr)) {}
061 
062   CommPutChar(SNAIL_COM, CMD_HELLO);
063 
064   I64 max_time = cnts.jiffies + SNAIL_TIMEOUT * JIFFY_FREQ / 1000;
065 
066   do {
067     if (FifoU8Rem(snail_comm->RX_fifo, &chr)) {
068       if (chr == CMD_HELLO) {
069         return 0;
070       }
071       else {
072         "Failed to initialize Snail -- wrong hello 0x%02X\n", chr;
073         "Are you using the right version of snail.py?\n";
074         throw;
075       }
076       return chr;
077     }
078     else
079       Yield;
080   }
081   while (cnts.jiffies < max_time);
082 
083   "Failed to initialize Snail -- make sure COM%d "
084   "is properly configured & snail.py is running!\n", SNAIL_COM;
085   throw;
086 }
087 
088 I64 socket(I64 domain, I64 type) {
089   CommPutChar(SNAIL_COM, CMD_SOCKET);
090   CommPutChar(SNAIL_COM, domain);
091   CommPutChar(SNAIL_COM, type);
092   return ReadI8();
093 }
094 
095 I64 close(I64 sockfd) {
096   CommPutChar(SNAIL_COM, CMD_CLOSE);
097   CommPutChar(SNAIL_COM, sockfd);
098   return ReadI8();
099 }
100 
101 I64 create_connection(U8* addr, U16 port) {
102   I64 sockfd = socket(AF_INET, SOCK_STREAM);
103 
104   if (sockfd < 0)
105     return sockfd;
106 
107   CommPutChar(SNAIL_COM, CMD_CONNECT_TCP);
108   CommPutChar(SNAIL_COM, sockfd);
109   CommPutChar(SNAIL_COM, StrLen(addr));
110   CommPutS(SNAIL_COM, addr);
111   CommPutChar(SNAIL_COM, port & 0xff);
112   CommPutChar(SNAIL_COM, port >> 8);
113 
114   I64 error = ReadI8();
115   if (error < 0) {
116     close(sockfd);
117     return error;
118   }
119 
120   return sockfd;
121 }
122 
123 I64 recv(I64 sockfd, U8* buf, I64 len, I64 flags) {
124   // This will be problematic for UDP
125   if (len > SNAIL_FRAME_SIZE)
126     len = SNAIL_FRAME_SIZE;
127 
128   CommPutChar(SNAIL_COM, CMD_RECV);
129   CommPutChar(SNAIL_COM, sockfd);
130   CommPutChar(SNAIL_COM, len);
131   CommPutChar(SNAIL_COM, flags);
132   I64 got = ReadI8();
133 
134   if (got > 0)
135     ReadBlock(buf, got);
136 
137   return got;
138 }
139 
140 I64 send(I64 sockfd, U8* buf, I64 len, I64 flags) {
141   // FIXME: use frames
142   CommPutChar(SNAIL_COM, CMD_SEND);
143   CommPutChar(SNAIL_COM, sockfd);
144   CommPutChar(SNAIL_COM, len);
145   CommPutChar(SNAIL_COM, flags);
146   CommPutBlk(SNAIL_COM, buf, len);
147   return ReadI8();
148 }