adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 1 | #include "socket.h" |
| 2 | |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 3 | #define SOCKET_STATE_NONE 0 |
| 4 | #define SOCKET_STATE_ACKED 1 |
| 5 | #define SOCKET_STATE_READ 2 |
| 6 | #define SOCKET_STATE_BLOCKED_NEWDATA 3 |
| 7 | #define SOCKET_STATE_BLOCKED_CLOSE 4 |
| 8 | #define SOCKET_STATE_BLOCKED_SEND 5 |
| 9 | #define SOCKET_STATE_DATA_SENT 6 |
adamdunkels | c8e7c77 | 2004-08-14 21:57:36 +0000 | [diff] [blame] | 10 | |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 11 | /*---------------------------------------------------------------------------*/ |
| 12 | static char |
adamdunkels | e59ce4a | 2004-09-03 09:59:46 +0000 | [diff] [blame^] | 13 | send_data(register struct socket *s) |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 14 | { |
| 15 | if(s->state != SOCKET_STATE_DATA_SENT || uip_rexmit()) { |
| 16 | if(s->sendlen > uip_mss()) { |
| 17 | uip_send(s->sendptr, uip_mss()); |
adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 18 | } else { |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 19 | uip_send(s->sendptr, s->sendlen); |
adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 20 | } |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 21 | s->state = SOCKET_STATE_DATA_SENT; |
| 22 | return 1; |
adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 23 | } |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 24 | return 0; |
adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 25 | } |
| 26 | /*---------------------------------------------------------------------------*/ |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 27 | static char |
adamdunkels | e59ce4a | 2004-09-03 09:59:46 +0000 | [diff] [blame^] | 28 | data_sent(register struct socket *s) |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 29 | { |
| 30 | if(s->state == SOCKET_STATE_DATA_SENT && uip_acked()) { |
| 31 | if(s->sendlen > uip_mss()) { |
| 32 | s->sendlen -= uip_mss(); |
| 33 | s->sendptr += uip_mss(); |
| 34 | } else { |
| 35 | s->sendptr += s->sendlen; |
| 36 | s->sendlen = 0; |
| 37 | } |
| 38 | s->state = SOCKET_STATE_ACKED; |
| 39 | return 1; |
| 40 | } |
| 41 | return 0; |
| 42 | } |
| 43 | /*---------------------------------------------------------------------------*/ |
adamdunkels | e59ce4a | 2004-09-03 09:59:46 +0000 | [diff] [blame^] | 44 | PT_THREAD(socket_send(register struct socket *s, const char *buf, unsigned int len)) |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 45 | { |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 46 | PT_BEGIN(&s->socketpt); |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 47 | |
| 48 | if(len == 0) { |
| 49 | PT_EXIT(&s->socketpt); |
| 50 | } |
| 51 | |
| 52 | s->sendptr = buf; |
| 53 | s->sendlen = len; |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 54 | |
| 55 | s->state = SOCKET_STATE_NONE; |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 56 | |
| 57 | while(s->sendlen > 0) { |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 58 | PT_WAIT_UNTIL(&s->socketpt, data_sent(s) & send_data(s)); |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 59 | } |
| 60 | |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 61 | s->state = SOCKET_STATE_NONE; |
| 62 | |
| 63 | PT_END(&s->socketpt); |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 64 | } |
| 65 | /*---------------------------------------------------------------------------*/ |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 66 | char |
| 67 | socket_newdata(struct socket *s) |
adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 68 | { |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 69 | if(s->readlen > 0) { |
| 70 | /* Data in uip_appdata buffer that has not yet been read. */ |
| 71 | return 1; |
| 72 | } else if(s->state == SOCKET_STATE_READ) { |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 73 | /* Data in uip_appdata buffer already consumed. */ |
| 74 | s->state = SOCKET_STATE_BLOCKED_NEWDATA; |
| 75 | return 0; |
| 76 | } else if(uip_newdata()) { |
| 77 | /* There is new data that has not been consumed. */ |
| 78 | return 1; |
| 79 | } else { |
| 80 | /* There is no new data. */ |
| 81 | return 0; |
adamdunkels | c8e7c77 | 2004-08-14 21:57:36 +0000 | [diff] [blame] | 82 | } |
adamdunkels | c8e7c77 | 2004-08-14 21:57:36 +0000 | [diff] [blame] | 83 | } |
| 84 | /*---------------------------------------------------------------------------*/ |
adamdunkels | e59ce4a | 2004-09-03 09:59:46 +0000 | [diff] [blame^] | 85 | PT_THREAD(socket_readto(register struct socket *socket, unsigned char c)) |
adamdunkels | c8e7c77 | 2004-08-14 21:57:36 +0000 | [diff] [blame] | 86 | { |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 87 | PT_BEGIN(&socket->socketpt); |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 88 | |
adamdunkels | c8e7c77 | 2004-08-14 21:57:36 +0000 | [diff] [blame] | 89 | uipbuf_setup(&socket->buf, socket->bufptr, socket->bufsize); |
| 90 | |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 91 | /* XXX: Should add uipbuf_checkmarker() before do{} loop, if |
| 92 | incoming data has been handled while waiting for a write. */ |
| 93 | |
adamdunkels | c8e7c77 | 2004-08-14 21:57:36 +0000 | [diff] [blame] | 94 | do { |
| 95 | if(socket->readlen == 0) { |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 96 | PT_WAIT_UNTIL(&socket->socketpt, socket_newdata(socket)); |
adamdunkels | c8e7c77 | 2004-08-14 21:57:36 +0000 | [diff] [blame] | 97 | socket->state = SOCKET_STATE_READ; |
| 98 | socket->readptr = (u8_t *)uip_appdata; |
| 99 | socket->readlen = uip_datalen(); |
| 100 | } |
| 101 | } while((uipbuf_bufto(&socket->buf, c, |
| 102 | &socket->readptr, |
| 103 | &socket->readlen) & UIPBUF_FOUND) == 0 && |
| 104 | socket->readlen > 0); |
| 105 | |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 106 | if(uipbuf_len(&socket->buf) == 0) { |
| 107 | socket->state = SOCKET_STATE_NONE; |
| 108 | PT_RESTART(&socket->socketpt); |
| 109 | } |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 110 | |
adamdunkels | e0b4547 | 2004-08-20 21:17:41 +0000 | [diff] [blame] | 111 | |
adamdunkels | bdafa39 | 2004-09-01 19:09:49 +0000 | [diff] [blame] | 112 | PT_END(&socket->socketpt); |
adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 113 | } |
| 114 | /*---------------------------------------------------------------------------*/ |
| 115 | void |
adamdunkels | e59ce4a | 2004-09-03 09:59:46 +0000 | [diff] [blame^] | 116 | socket_init(register struct socket *socket, char *buffer, unsigned int buffersize) |
adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 117 | { |
| 118 | socket->state = SOCKET_STATE_NONE; |
| 119 | socket->readlen = 0; |
| 120 | socket->bufptr = buffer; |
| 121 | socket->bufsize = buffersize; |
| 122 | uipbuf_setup(&socket->buf, buffer, buffersize); |
| 123 | PT_INIT(&socket->pt); |
adamdunkels | c8e7c77 | 2004-08-14 21:57:36 +0000 | [diff] [blame] | 124 | PT_INIT(&socket->socketpt); |
adamdunkels | 039c3e0 | 2004-08-11 21:20:36 +0000 | [diff] [blame] | 125 | } |
| 126 | /*---------------------------------------------------------------------------*/ |