diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-09-09 17:20:56 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2007-09-09 17:20:56 +0000 |
commit | 7a65f932826220c741ffbf5698b48692a787d915 (patch) | |
tree | 825e048f8fc18b7e69cb155ad96b7254566a3ffe /nuttx/net/send.c | |
parent | d12e00bdd6ffbb39ab5d45d5d5a484d293108021 (diff) | |
download | px4-nuttx-7a65f932826220c741ffbf5698b48692a787d915.tar.gz px4-nuttx-7a65f932826220c741ffbf5698b48692a787d915.tar.bz2 px4-nuttx-7a65f932826220c741ffbf5698b48692a787d915.zip |
Implement TCP send; remove uIP proto-sockets
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@339 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/net/send.c')
-rw-r--r-- | nuttx/net/send.c | 200 |
1 files changed, 191 insertions, 9 deletions
diff --git a/nuttx/net/send.c b/nuttx/net/send.c index cc2b154a2..037455faf 100644 --- a/nuttx/net/send.c +++ b/nuttx/net/send.c @@ -42,12 +42,125 @@ #include <sys/types.h> #include <sys/socket.h> +#include <string.h> #include <errno.h> +#include <arch/irq.h> #include "net-internal.h" /**************************************************************************** - * Global Functions + * Definitions + ****************************************************************************/ + +#define STATE_POLLWAIT 1 +#define STATE_DATA_SENT 2 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure holds the state of the send operation until it can be + * operated upon from the interrupt level. + */ + +struct send_s +{ + FAR struct socket *snd_sock; /* Points to the parent socket structure */ + sem_t snd_sem; /* Used to wake up the waiting thread */ + FAR const uint8 *snd_buffer; /* Points to the buffer of data to send */ + size_t snd_buflen; /* Number of bytes in the buffer to send */ + ssize_t snd_sent; /* The number of bytes sent */ + uint8 snd_state; /* The state of the send operation. */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: send_Interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * send operation when polled by the uIP layer. + * + * Parameters: + * private An instance of struct send_s cast to void* + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +static void send_interrupt(void *private) +{ + struct send_s *pstate = (struct send_s *)private; + struct uip_conn *conn; + + /* If the data has not been sent OR if it needs to be retransmitted, + * then send it now. + */ + + if (pstate->snd_state != STATE_DATA_SENT || uip_rexmit()) + { + if (pstate->snd_buflen > uip_mss()) + { + uip_send(pstate->snd_buffer, uip_mss()); + } + else + { + uip_send(pstate->snd_buffer, pstate->snd_buflen); + } + + pstate->snd_state = STATE_DATA_SENT; + } + + /* Check if all data has been sent and acknowledged */ + + else if (pstate->snd_state == STATE_DATA_SENT && uip_acked()) + { + /* Yes.. the data has been sent AND acknowledge */ + + if (pstate->snd_buflen > uip_mss()) + { + /* Not all data has been sent */ + + pstate->snd_sent += uip_mss(); + pstate->snd_buflen -= uip_mss(); + pstate->snd_buffer += uip_mss(); + + /* Send again on the next poll */ + + pstate->snd_state = STATE_POLLWAIT; + } + else + { + /* All data has been sent */ + + pstate->snd_sent += pstate->snd_buflen; + pstate->snd_buffer += pstate->snd_buflen; + pstate->snd_buflen = 0; + + /* Don't allow any further call backs. */ + + conn = (struct uip_conn *)pstate->snd_sock->s_conn; + conn->private = NULL; + conn->callback = NULL; + + /* Wake up the waiting thread, returning the number of bytes + * actually sent. + */ + + sem_post(&pstate->snd_sem); + } + } +} + +/**************************************************************************** + * Public Functions ****************************************************************************/ /**************************************************************************** @@ -57,8 +170,8 @@ * The send() call may be used only when the socket is in a connected state * (so that the intended recipient is known). The only difference between * send() and write() is the presence of flags. With zero flags parameter, - * send() is equivalent to write(). Also, send(s,buf,len,flags) is - * equivalent to sendto(s,buf,len,flags,NULL,0). + * send() is equivalent to write(). Also, send(sockfd,buf,len,flags) is + * equivalent to sendto(sockfd,buf,len,flags,NULL,0). * * Parameters: * sockfd Socket descriptor of socket @@ -117,7 +230,11 @@ ssize_t send(int sockfd, const void *buf, size_t len, int flags) { FAR struct socket *psock = sockfd_socket(sockfd); + struct uip_conn *conn; + struct send_s state; + irqstate_t save; int err; + int ret; /* Verify that the sockfd corresponds to valid, allocated socket */ @@ -129,21 +246,86 @@ ssize_t send(int sockfd, const void *buf, size_t len, int flags) /* If this is a connected socket, then return ENOTCONN */ - if (psock->s_type != SOCK_STREAM) + if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { err = ENOTCONN; goto errout; } + /* Set the socket state to sending */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); + /* Perform the TCP send operation */ -#warning "send() not implemented" - err = ENOSYS; + /* Initialize the state structure. This is done with interrupts + * disabled because we don't want anything to happen until we + * are ready. + */ + + save = irqsave(); + memset(&state, 0, sizeof(struct send_s)); + (void)sem_init(&state. snd_sem, 0, 0); /* Doesn't really fail */ + state.snd_sock = psock; + state.snd_buflen = len; + state.snd_buffer = buf; + state.snd_state = STATE_POLLWAIT; + + if (len > 0) + { + /* Set up the callback in the connection */ + + conn = (struct uip_conn *)psock->s_conn; + conn->private = (void*)&state; + conn->callback = send_interrupt; + + /* Wait for the send to complete or an error to occur: NOTES: (1) + * sem_wait will also terminate if a signal is received, (2) interrupts + * are disabled! They will be re-enabled while the task sleeps and + * automatically re-enabled when the task restarts. + */ + + ret = sem_wait(&state. snd_sem); + + /* Make sure that no further interrupts are processed */ + + conn->private = NULL; + conn->callback = NULL; + } + + sem_destroy(&state. snd_sem); + irqrestore(save); + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + + /* Check for a errors. Errors are signaled by negative errno values + * for the send length + */ + + if (state.snd_sent < 0) + { + err = state.snd_sent; + goto errout; + } + + /* If sem_wait failed, then we were probably reawakened by a signal. In + * this case, sem_wait will have set errno appropriately. + */ + + if (ret < 0) + { + err = -ret; + goto errout; + } + + /* Return the number of bytes actually sent */ + + return state.snd_sent; errout: - *get_errno_ptr() = ENOSYS; - return ERROR; - *get_errno_ptr() = ENOSYS; + *get_errno_ptr() = err; return ERROR; } |