cloudFPGA (cF) API  1.0
The documentation of the source code of cloudFPGA (cF)
http.cpp
Go to the documentation of this file.
1 
17 
30 #include <stdint.h>
31 #include "ap_int.h"
32 #include "ap_utils.h"
33 #include <assert.h>
34 
35 #include "fmc.hpp"
36 #include "http.hpp"
37 
38 
39 static char* httpHeader = "HTTP/1.1 ";
40 static char* generalHeaderBegin = "Cache-Control: private\r\nContent-Type: text/plain; charset=utf-8\r\nServer: cloudFPGA/";
41 static char* httpNL = "\r\n";
42 static char* contentLengthHeader = "Content-Length: ";
43 
44 static char* status200 = "200 OK";
45 static char* status400 = "400 Bad Request";
46 static char* status403 = "403 Forbidden";
47 static char* status404 = "404 Not Found";
48 static char* status422 = "422 Unprocessable Entity";
49 static char* status500 = "500 Internal Server Error";
50 
51 
52 int my_strlen(char *s) {
53  int sum = 0;
54  char c = s[0];
55 
56  while(c != '\0') {
57  sum++;
58  c = s[sum];
59  }
60  return sum;
61 }
62 
63 int my_wordlen(char *s) {
64  //word in the sense of: string to next space
65  int sum = 0;
66  char c = s[0];
67 
68  while(c != ' ') {
69  sum++;
70  c = s[sum];
71  }
72  return sum;
73 }
74 
75 
76 int writeString(char* s)
77 {
78  int len = 0;
79  for(int i = 0; i<OUT_BUFFER_SIZE; i++)
80  {
81  if(s[i] == '\0')
82  {
83  break;
84  }
85  bufferOut[bufferOutPtrWrite + i] = s[i];
86  len++;
87  }
88  bufferOutPtrWrite += len;
90  return len;
91 }
92 
93 void strrev (char *str)
94 {
95  unsigned char temp, len=0, i=0;
96 
97  if( str == '\0' || !(*str) ) // If str is NULL or empty, do nothing
98  return;
99 
100  while(str[len] != '\0')
101  {
102  len++;
103  }
104  len=len-1;
105 
106  // Swap the characters
107  while(i < len)
108  {
109  temp = str[i];
110  str[i] = str[len];
111  str[len] = temp;
112  i++;
113  len--;
114  }
115 }
116 
117 
118 //write integer until 64bits
119 int writeUnsignedLong(unsigned long num, uint8_t base)
120 {
121  unsigned char i=0,rem=0;
122  char arr[66];
123 
124  // Handle 0 explicitly, otherwise empty string is printed for 0
125  if (num == 0)
126  {
127  arr[i++] = '0';
128  }
129  // Process individual digits
130  while (num != 0 && i<=64)
131  {
132  rem = num % base;
133  arr[i++] = (rem > 9)? (rem-10) + 'A' : rem + '0';
134  num = num/base;
135  }
136  arr[i] = '\0'; // Append string terminator
137  strrev(arr); // Reverses the string
138 
139  //now, copy to buffer out
140  //<i, because we don't want to copy \0
141  for(int p = 0; p<i; p++)
142  {
143  bufferOut[bufferOutPtrWrite + p] = arr[p];
144  }
145  bufferOutPtrWrite += i;
146  printf("written unsigned long %s of length %d with basis %d\n",arr,i, (int) base);
147 
149  return i;
150 }
151 
152 
153 void my_itoa(unsigned long num, char *arr, unsigned char base)
154 {
155  unsigned char i=0,rem=0;
156 
157  // Handle 0 explicitly, otherwise empty string is printed for 0
158  if (num == 0)
159  {
160  arr[i++] = '0';
161  arr[i] = '\0';
162  }
163 
164  // Process individual digits
165  while (num != 0)
166  {
167  rem = num % base;
168  arr[i++] = (rem > 9)? (rem-10) + 'A' : rem + '0';
169  num = num/base;
170  }
171  arr[i] = '\0'; // Append string terminator
172  strrev(arr); // Reverses the string
173 }
174 
175 
176 
177 int my_atoi(char *str, int strlen)
178 {
179  int res = 0;
180 
181  for (int i = 0; i < strlen; ++i)
182  {
183  res = res*10 + (str[i] - '0');
184  }
185 
186  return res;
187 }
188 
189 
190 int8_t writeHttpStatus(int status, uint16_t content_length){
191 
192  char* toWrite;
193 
194  switch (status) {
195  case 200:
196  toWrite = status200;
197  break;
198  case 400:
199  toWrite = status400;
200  break;
201  case 403:
202  toWrite = status403;
203  break;
204  case 404:
205  toWrite = status404;
206  break;
207  case 422:
208  toWrite = status422;
209  break;
210  default:
211  toWrite = status500;
212  break;
213  }
214 
215  //Assemble Header
216  int len = writeString(httpHeader);
217  len += writeString(toWrite);
218  len += writeString(httpNL);
219  len += writeString(generalHeaderBegin);
221  len += writeString(httpNL);
222 
223  //TODO: maybe include in future versions
224  /* if ( content_length > 0)
225  {
226  char *lengthAscii = new char[6];
227 
228  for(int i = 0; i < 6; i++)
229  {
230  lengthAscii[i] = 0x20;
231  }
232 
233  my_itoa(content_length, lengthAscii, 10);
234 
235  len += writeString(contentLengthHeader);
236  len += writeString(lengthAscii);
237  len += writeString(httpNL);
238  }
239  */
240  len += writeString(httpNL); // to finish header
241 
242  return len;
243 }
244 
245 
246 int my_strcmp(char *tmp1, volatile uint8_t tmp2[IN_BUFFER_SIZE], int max_length)
247 {
248  int cnt = 0;
249  while(*tmp1 && tmp2[cnt])
250  {
251  if(*tmp1== tmp2[cnt])
252  {
253  tmp1++;
254  cnt++;
255  }
256  else
257  {
258  if(*tmp1< tmp2[cnt])
259  {
260  return -1;
261  }
262  else
263  {
264  return 1;
265  }
266  }
267  //if (cnt == max_length -1 )
268  if (cnt == max_length ) //\0 is at the end
269  {
270  return 0; //equal until max_length
271  }
272  }
273  return 0; //strings are same
274 }
275 
276 
277 
278 static char *statusPath = "GET /status "; //the last space is important!
279 static char *configurePath = "POST /configure ";
280 static char *putRank = "PUT /rank/"; //NO space here, since it is the request contains a parameter
281 static char *putSize = "PUT /size/"; //NO space here, since it is the request contains a parameter
282 static char *postRouting = "POST /routing ";
283 
285 
286 int request_len(ap_uint<16> offset, int maxLength)
287 {
288 
289  if (bufferIn[offset + 0] == 0x00)
290  {//empty
291  return 0;
292  }
293 
294  int sum = 0;
295  char c1 = 0, c2 = 0, c3 = 0, c4 = 0;
296  c1 = (char) bufferIn[offset + 0 + 0];
297  c2 = (char) bufferIn[offset + 0 + 1];
298  c3 = (char) bufferIn[offset + 0 + 2];
299  c4 = (char) bufferIn[offset + 0 + 3];
300 
301  while( (c1 != '\r' || c2 != '\n' || c3 != '\r' || c4 != '\n' ) && sum < maxLength)
302  {
303  //NOT! sum += 4;
304  sum++;
305  c1 = (char) bufferIn[offset + sum + 0];
306  c2 = (char) bufferIn[offset + sum + 1];
307  c3 = (char) bufferIn[offset + sum + 2];
308  c4 = (char) bufferIn[offset + sum + 3];
309  }
310 
311 
312  if (sum >= maxLength)
313  { //not a valid end of header found --> invalid content, since we should have already the complete request in the buffer here
314  return -1;
315  }
316 
317  return sum;
318 
319 }
320 
321 int8_t extract_path(bool rx_done)
322 {
323  int stringlen = my_strlen((char*) (uint8_t*) bufferIn);
324  // strlen works, because after the request is the buffer 00ed
325  // and we see single pages --> not the complete transfer at once
326 
327  printf("stringlen: %d\n",(int) stringlen);
328 
329  if (stringlen == 0)
330  {
331  return 0;
332  }
333 
334 
335  int requestLen = request_len(0, stringlen);
336  printf("requestLen: %d\n",(int) requestLen);
337 
338 
339  //from here it looks like a valid header
340 
341  reqType = REQ_INVALID; //reset
342 
343  if(requestLen <= 0)
344  {//not a valid header
345  if (stringlen == PAYLOAD_BYTES_PER_PAGE || !rx_done)
346  {//not yet complete
347  return -1;
348  }
349  return -2;
350  }
351 
352  if (my_strcmp(statusPath, bufferIn, my_strlen(statusPath)) == 0 )
353  {
354  //printf("strlen status: %d\n", my_strlen(statusPath));
356  return 1;
357  } else if (my_strcmp(configurePath, bufferIn, my_strlen(configurePath)) == 0 )
358  {
359  bufferInPtrNextRead = requestLen + 4;
361  return 2;
362  } else if(my_strcmp(putRank, bufferIn, my_strlen(putRank)) == 0 )
363  {
364  reqType = PUT_RANK;
365  char* intStart = (char*) &bufferIn[my_strlen(putRank)];
366  int intLen = my_wordlen(intStart);
367 
368  ap_uint<32> newRank = (unsigned int) my_atoi(intStart, intLen);
369  if(newRank >= MAX_CLUSTER_SIZE)
370  {//invalid
371  return -2;
372  }
373  setRank(newRank);
374  return 3;
375  } else if(my_strcmp(putSize, bufferIn, my_strlen(putSize)) == 0 )
376  {
377  reqType = PUT_SIZE;
378  char* intStart = (char*) &bufferIn[my_strlen(putSize)];
379  int intLen = my_wordlen(intStart);
380 
381  ap_uint<32> newSize = (unsigned int) my_atoi(intStart, intLen);
382  if(newSize >= MAX_CLUSTER_SIZE)
383  {//invalid
384  return -2;
385  }
386  setSize(newSize);
387  return 4;
388  } else if(my_strcmp(postRouting, bufferIn, my_strlen(postRouting)) == 0 )
389  {
391  bufferInPtrNextRead = requestLen + 4;
392 
393  return 5;
394  } else {
395  //Invalid / Not Found
396  return -3;
397  }
398 }
399 
400 
401 void parseHttpInput(bool transferErr, ap_uint<1> wasAbort, bool invalidPayload, bool rx_done)
402 {
403 
404  switch (httpState) {
405  case HTTP_IDLE: //both the same
406  case HTTP_PARSE_HEADER:
407  //search for HTTP
408  switch (extract_path(rx_done)) {
409  default:
410  case -3: //404
413  break;
414  case -2: //invalid content
417  break;
418  case -1: //not yet complete
420  break;
421  case 0: //not vaild until now
422  break;
423  case 1: //get status
425  break;
426  case 2: //post config
428  break;
429  case 3: //put rank
431  break;
432  case 4: //put size
434  break;
435  case 5: //post routing
437  break;
438  }
439  break;
440  case HTTP_HEADER_PARSED: //this state is valid for one core-cycle: after that the current payload should start at 0
442  //no break
443  case HTTP_READ_PAYLOAD:
444  break;
445  case HTTP_REQUEST_COMPLETE:
446  // break;
447  case HTTP_SEND_RESPONSE:
448  //emptyOutBuffer(); ensured by global state machine
449  if(wasAbort == 1) //abort always also triggers transferErr --> so check this first
450  {
452  } else if (transferErr == true || invalidPayload == true)
453  {
455  } else if(reqType == GET_STATUS)
456  {
457  //combine status
458  //length??
460  //write status
461  uint32_t contentLen = writeDisplaysToOutBuffer();
462  writeString(httpNL); //to finish body
463  if (contentLen > 0)
464  {
465  bufferOutContentLength += contentLen;
466  }
467  } else if(reqType == POST_CONFIG)
468  {
470  bufferOutContentLength += writeString("Partial reconfiguration finished successfully!\r\n\r\n");
471  //write success message
472  } else {
473  //PUT_RANK, PUT_SIZE, POST_ROUTING
475  }
477  break;
478  default:
479  break;
480  }
481 
482  printf("parseHttpInput returns with state %d\n",httpState);
483  //printf("RequestType after parseHttpInput %d\n",reqType);
484 
485 }
486 
#define CFDK_VERSION_STRING
Definition: cfdk.hpp:30
#define OUT_BUFFER_SIZE
Definition: fmc.hpp:133
int my_wordlen(char *s)
Definition: http.cpp:63
uint8_t bufferOut[1024]
Definition: fmc.cpp:59
uint16_t bufferOutContentLength
Definition: fmc.cpp:61
uint8_t reqType
Definition: http.cpp:284
#define POST_ROUTING
Definition: http.hpp:44
#define HTTP_REQUEST_COMPLETE
Definition: fmc.hpp:162
#define REQ_INVALID
Definition: http.hpp:39
#define HTTP_HEADER_PARSED
Definition: fmc.hpp:160
#define HTTP_IDLE
Definition: fmc.hpp:158
int8_t writeHttpStatus(int status, uint16_t content_length)
Definition: http.cpp:190
int my_atoi(char *str, int strlen)
Definition: http.cpp:177
#define HTTP_SEND_RESPONSE
Definition: fmc.hpp:163
void setRank(ap_uint< 32 > newRank)
Definition: fmc.cpp:451
void parseHttpInput(bool transferErr, ap_uint< 1 > wasAbort, bool invalidPayload, bool rx_done)
Definition: http.cpp:401
#define RequestType
Definition: http.hpp:46
int my_strlen(char *s)
Definition: http.cpp:52
uint8_t httpState
Definition: fmc.cpp:72
#define POST_CONFIG
Definition: http.hpp:40
int writeString(char *s)
Definition: http.cpp:76
int writeUnsignedLong(unsigned long num, uint8_t base)
Definition: http.cpp:119
#define HTTP_PARSE_HEADER
Definition: fmc.hpp:159
#define PAYLOAD_BYTES_PER_PAGE
Definition: fmc.hpp:126
int my_strcmp(char *tmp1, volatile uint8_t tmp2[4096], int max_length)
Definition: http.cpp:246
#define IN_BUFFER_SIZE
Definition: fmc.hpp:131
uint16_t bufferOutPtrWrite
Definition: fmc.cpp:60
#define PUT_SIZE
Definition: http.hpp:43
uint32_t writeDisplaysToOutBuffer()
Definition: fmc.cpp:270
int8_t extract_path(bool rx_done)
Definition: http.cpp:321
uint32_t bufferInPtrNextRead
Definition: fmc.cpp:56
int request_len(ap_uint< 16 > offset, int maxLength)
Definition: http.cpp:286
void my_itoa(unsigned long num, char *arr, unsigned char base)
Definition: http.cpp:153
#define MAX_CLUSTER_SIZE
Definition: fmc.hpp:151
void setSize(ap_uint< 32 > newSize)
Definition: fmc.cpp:458
uint8_t bufferIn[4096]
Definition: fmc.cpp:52
#define HTTP_READ_PAYLOAD
Definition: fmc.hpp:161
#define HTTP_DONE
Definition: fmc.hpp:165
#define GET_STATUS
Definition: http.hpp:41
void strrev(char *str)
Definition: http.cpp:93
#define HTTP_INVALID_REQUEST
Definition: fmc.hpp:164
#define PUT_RANK
Definition: http.hpp:42
: The HTTP parsing functions for the FMC.