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
This commit is contained in:
parent
01207cc66e
commit
dcf7c7c365
@ -89,6 +89,7 @@ int user_start(int argc, char *argv[])
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_UIP_WEBSERVER)
|
||||
httpd_init();
|
||||
httpd_listen();
|
||||
#elif defined(CONFIG_EXAMPLE_UIP_TELNETD)
|
||||
telnetd_init();
|
||||
#elif defined(CONFIG_EXAMPLE_UIP_DHCPC)
|
||||
|
@ -28,51 +28,12 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HTTPD_H__
|
||||
#define __HTTPD_H__
|
||||
#ifndef _NET_UIP_HTTPD_H
|
||||
#define _NET_UIP_HTTPD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <net/uip/psock.h>
|
||||
|
||||
#define HTTPD_FS_STATISTICS 1
|
||||
extern void httpd_init(void);
|
||||
extern void httpd_listen(void);
|
||||
|
||||
struct httpd_fs_file
|
||||
{
|
||||
char *data;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct httpd_state
|
||||
{
|
||||
unsigned char timer;
|
||||
struct psock sin, sout;
|
||||
char inputbuf[50];
|
||||
char filename[20];
|
||||
char state;
|
||||
struct httpd_fs_file file;
|
||||
int len;
|
||||
char *scriptptr;
|
||||
int scriptlen;
|
||||
|
||||
unsigned short count;
|
||||
};
|
||||
|
||||
#ifdef HTTPD_FS_STATISTICS
|
||||
#if HTTPD_FS_STATISTICS == 1
|
||||
extern uint16 httpd_fs_count(char *name);
|
||||
#endif /* HTTPD_FS_STATISTICS */
|
||||
#endif /* HTTPD_FS_STATISTICS */
|
||||
|
||||
void httpd_init(void);
|
||||
void httpd_log(char *msg);
|
||||
void httpd_log_file(uint16 *requester, char *file);
|
||||
|
||||
/* file must be allocated by caller and will be filled in
|
||||
* by the function.
|
||||
*/
|
||||
|
||||
int httpd_fs_open(const char *name, struct httpd_fs_file *file);
|
||||
void httpd_fs_init(void);
|
||||
|
||||
|
||||
#endif /* __HTTPD_H__ */
|
||||
#endif /* _NET_UIP_HTTPD_H */
|
||||
|
@ -1,257 +0,0 @@
|
||||
/****************************************************************************
|
||||
* psock.h
|
||||
* Protosocket library header file
|
||||
*
|
||||
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
*
|
||||
* This logic was leveraged from uIP which also has a BSD-style license:
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __NET_UIP_PSOCK_H
|
||||
#define __NET_UIP_PSOCK_H
|
||||
|
||||
/* psock Protosockets library
|
||||
*
|
||||
* The protosocket library provides an interface to the uIP stack that is
|
||||
* similar to the traditional BSD socket interface. Unlike programs
|
||||
* written for the ordinary uIP event-driven interface, programs
|
||||
* written with the protosocket library are executed in a sequential
|
||||
* fashion and does not have to be implemented as explicit state
|
||||
* machines.
|
||||
*
|
||||
* Protosockets only work with TCP connections.
|
||||
*
|
||||
* The protosocket library uses \ref pt protothreads to provide
|
||||
* sequential control flow. This makes the protosockets lightweight in
|
||||
* terms of memory, but also means that protosockets inherits the
|
||||
* functional limitations of protothreads. Each protosocket lives only
|
||||
* within a single function. Automatic variables (stack variables) are
|
||||
* not retained across a protosocket library function call.
|
||||
*
|
||||
* \note Because the protosocket library uses protothreads, local
|
||||
* variables will not always be saved across a call to a protosocket
|
||||
* library function. It is therefore advised that local variables are
|
||||
* used with extreme care.
|
||||
*
|
||||
* The protosocket library provides functions for sending data without
|
||||
* having to deal with retransmissions and acknowledgements, as well
|
||||
* as functions for reading data without having to deal with data
|
||||
* being split across more than one TCP segment.
|
||||
*
|
||||
* Because each protosocket runs as a protothread, the protosocket has to be
|
||||
* started with a call to PSOCK_BEGIN() at the start of the function
|
||||
* in which the protosocket is used. Similarly, the protosocket protothread can
|
||||
* be terminated by a call to PSOCK_EXIT().
|
||||
*
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <net/uip/uipopt.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* The structure that holds the state of a buffer.
|
||||
*
|
||||
* This structure holds the state of a uIP buffer. The structure has
|
||||
* no user-visible elements, but is used through the functions
|
||||
* provided by the library.
|
||||
*
|
||||
*/
|
||||
|
||||
struct psock_buf
|
||||
{
|
||||
uint8 *ptr;
|
||||
unsigned short left;
|
||||
};
|
||||
|
||||
/* The representation of a protosocket.
|
||||
*
|
||||
* The protosocket structrure is an opaque structure with no user-visible
|
||||
* elements.
|
||||
*/
|
||||
|
||||
struct psock
|
||||
{
|
||||
const uint8 *sendptr; /* Pointer to the next data to be sent. */
|
||||
uint8 *readptr; /* Pointer to the next data to be read. */
|
||||
uint8 *bufptr; /* Pointer to the buffer used for buffering incoming data. */
|
||||
uint16 sendlen; /* The number of bytes left to be sent. */
|
||||
uint16 readlen; /* The number of bytes left to be read. */
|
||||
struct psock_buf buf; /* The structure holding the state of the input buffer. */
|
||||
unsigned int bufsize; /* The size of the input buffer. */
|
||||
unsigned char state; /* The state of the protosocket. */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public FunctionPrototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Initialize a protosocket.
|
||||
*
|
||||
* Initializes a protosocket and must be called before the
|
||||
* protosocket is used. The initialization also specifies the input buffer
|
||||
* for the protosocket.
|
||||
*
|
||||
* psock (struct psock *) A pointer to the protosocket to be
|
||||
* initialized
|
||||
*
|
||||
* buffer (char *) A pointer to the input buffer for the
|
||||
* protosocket.
|
||||
*
|
||||
* buffersize (unsigned int) The size of the input buffer.
|
||||
*/
|
||||
|
||||
extern void psock_init(struct psock *psock, char *buffer, unsigned int buffersize);
|
||||
|
||||
/* Send data.
|
||||
*
|
||||
* This macro sends data over a protosocket. The protosocket protothread blocks
|
||||
* until all data has been sent and is known to have been received by
|
||||
* the remote end of the TCP connection.
|
||||
*
|
||||
* psock (struct psock *) A pointer to the protosocket over which
|
||||
* data is to be sent.
|
||||
*
|
||||
* data (char *) A pointer to the data that is to be sent.
|
||||
*
|
||||
* datalen (unsigned int) The length of the data that is to be
|
||||
* sent.
|
||||
*/
|
||||
|
||||
extern void psock_send(struct psock *psock, const char *buf, unsigned int len);
|
||||
|
||||
/*Send a null-terminated string.
|
||||
*
|
||||
* psock Pointer to the protosocket.
|
||||
* str The string to be sent.
|
||||
*
|
||||
* This function sends a null-terminated string over the
|
||||
* protosocket.
|
||||
*/
|
||||
|
||||
#define PSOCK_SEND_STR(psock, str) psock_send(psock, str, strlen(str))
|
||||
|
||||
/* Generate data with a function and send it
|
||||
*
|
||||
* psock Pointer to the protosocket.
|
||||
* generator Pointer to the generator function
|
||||
* arg Argument to the generator function
|
||||
*
|
||||
* This function generates data and sends it over the
|
||||
* protosocket. This can be used to dynamically generate
|
||||
* data for a transmission, instead of generating the data
|
||||
* in a buffer beforehand. This function reduces the need for
|
||||
* buffer memory. The generator function is implemented by
|
||||
* the application, and a pointer to the function is given
|
||||
* as an argument with the call to PSOCK_GENERATOR_SEND().
|
||||
*
|
||||
* The generator function should place the generated data
|
||||
* directly in the uip_appdata buffer, and return the
|
||||
* length of the generated data. The generator function is
|
||||
* called by the protosocket layer when the data first is
|
||||
* sent, and once for every retransmission that is needed.
|
||||
*/
|
||||
|
||||
extern void psock_generator_send(struct psock *psock, unsigned short (*f)(void *), void *arg);
|
||||
|
||||
/* Close a protosocket.
|
||||
*
|
||||
* This macro closes a protosocket and can only be called from within the
|
||||
* protothread in which the protosocket lives.
|
||||
*
|
||||
* psock (struct psock *) A pointer to the protosocket that is to
|
||||
* be closed.
|
||||
*/
|
||||
|
||||
#define PSOCK_CLOSE(psock) uip_close()
|
||||
|
||||
/* Read data until the buffer is full.
|
||||
*
|
||||
* This macro will block waiting for data and read the data into the
|
||||
* input buffer specified with the call to PSOCK_INIT(). Data is read
|
||||
* until the buffer is full..
|
||||
*
|
||||
* psock (struct psock *) A pointer to the protosocket from which
|
||||
* data should be read.
|
||||
*/
|
||||
|
||||
extern void psock_readbuf(struct psock *psock);
|
||||
|
||||
/* Read data up to a specified character.
|
||||
*
|
||||
* This macro will block waiting for data and read the data into the
|
||||
* input buffer specified with the call to PSOCK_INIT(). Data is only
|
||||
* read until the specifieed character appears in the data stream.
|
||||
*
|
||||
* psock (struct psock *) A pointer to the protosocket from which
|
||||
* data should be read.
|
||||
*
|
||||
* c (char) The character at which to stop reading.
|
||||
*/
|
||||
|
||||
extern void psock_readto(struct psock *psock, unsigned char c);
|
||||
|
||||
/* The length of the data that was previously read.
|
||||
*
|
||||
* Returns the length of the data that was previously read
|
||||
* using PSOCK_READTO() or PSOCK_READ().
|
||||
*
|
||||
* psock (struct psock *) A pointer to the protosocket holding the data.
|
||||
*/
|
||||
|
||||
extern uint16 psock_datalen(struct psock *psock);
|
||||
|
||||
/* Check if there is new data has arrived on a protosocket without blocking
|
||||
*
|
||||
* psock (struct psock *) A pointer to the protosocket.
|
||||
*/
|
||||
|
||||
extern boolean psock_checknewdata(struct psock *s);
|
||||
|
||||
/* Block until new data has arrived on a protosocket.
|
||||
*
|
||||
* psock (struct psock *) A pointer to the protosocket.
|
||||
*/
|
||||
|
||||
extern void psock_waitnewdata(struct psock *s);
|
||||
|
||||
#endif /* CONFIG_NET */
|
||||
#endif /* __NET_UIP_PSOCK_H */
|
@ -46,7 +46,6 @@
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <net/uip/uip.h>
|
||||
#include <net/uip/psock.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Definitions
|
||||
@ -87,6 +86,7 @@ struct socket
|
||||
{
|
||||
int s_crefs; /* Reference count on the socket */
|
||||
uint8 s_type; /* Protocol type: Only SOCK_STREAM or SOCK_DGRAM */
|
||||
uint8 s_flags; /* See _SF_* definitions */
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
sockopt_t s_options; /* Selected socket options */
|
||||
#ifndef CONFIG_DISABLE_CLOCK
|
||||
|
@ -177,21 +177,21 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
EXTERN int socket(int domain, int type, int protocol);
|
||||
EXTERN int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
EXTERN int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
EXTERN int bind(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
EXTERN int connect(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
|
||||
EXTERN ssize_t send(int sockfd, const void *buf, size_t len, int flags);
|
||||
EXTERN ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen);
|
||||
EXTERN ssize_t send(int sockfd, FAR const void *buf, size_t len, int flags);
|
||||
EXTERN ssize_t sendto(int sockfd, FAR const void *buf, size_t len, int flags,
|
||||
FAR const struct sockaddr *to, socklen_t tolen);
|
||||
|
||||
EXTERN ssize_t recv(int sockfd, void *buf, size_t len, int flags);
|
||||
EXTERN ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen);
|
||||
EXTERN ssize_t recv(int sockfd, FAR void *buf, size_t len, int flags);
|
||||
EXTERN ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags,
|
||||
FAR struct sockaddr *from, FAR socklen_t *fromlen);
|
||||
|
||||
EXTERN int setsockopt(int sockfd, int level, int option,
|
||||
const void *value, socklen_t value_len);
|
||||
FAR const void *value, socklen_t value_len);
|
||||
EXTERN int getsockopt(int sockfd, int level, int option,
|
||||
void *value, socklen_t *value_len);
|
||||
FAR void *value, FAR socklen_t *value_len);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
|
@ -119,6 +119,7 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
case SOCK_STREAM:
|
||||
ret = uip_tcpbind(psock->s_conn, inaddr);
|
||||
psock->s_flags |= _SF_BOUND;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
|
@ -90,7 +90,7 @@
|
||||
* sa_family field.
|
||||
* EAGAIN
|
||||
* No more free local ports or insufficient entries in the routing
|
||||
* cache. For PF_INET.
|
||||
* cache.
|
||||
* EALREADY
|
||||
* The socket is non-blocking and a previous connection attempt has
|
||||
* not yet been completed.
|
||||
@ -155,12 +155,28 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
int ret = uip_tcpconnect(psock->s_conn, inaddr);
|
||||
int ret;
|
||||
|
||||
/* Verify that the socket is not already connected */
|
||||
|
||||
if (_SS_ISCONNECTED(psock->s_flags))
|
||||
{
|
||||
err = -EISCONN;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Perform the uIP connection operation */
|
||||
|
||||
ret = uip_tcpconnect(psock->s_conn, inaddr);
|
||||
if (ret < 0)
|
||||
{
|
||||
err = -ret;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Mark the connection bound and connected */
|
||||
|
||||
psock->s_flags |= (_SF_BOUND|_SF_CONNECTED);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -52,6 +52,26 @@
|
||||
* Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Definitions of 8-bit socket flags */
|
||||
|
||||
/* Bits 0:2 : Socket state */
|
||||
#define _SF_IDLE 0x00 /* There is no socket activity */
|
||||
#define _SF_LISTEN 0x01 /* Socket is listening */
|
||||
#define _SF_RECV 0x02 /* Waiting for recv action to complete */
|
||||
#define _SF_SEND 0x03 /* Waiting for send action to complete */
|
||||
#define _SF_MASK 0x03 /* Mask to isolate the above actions */
|
||||
/* Bits 3:5 : unused */
|
||||
#define _SF_BOUND 0x40 /* Bit 6: SOCK_STREAM is bound to an address */
|
||||
#define _SF_CONNECTED 0x80 /* Bit 7: SOCK_STREAM is connected */
|
||||
|
||||
/* Macro to manage the socket state and flags */
|
||||
|
||||
#define _SS_SETSTATE(s,f) (((s) & ~_SF_MASK) | (f))
|
||||
#define _SS_GETSTATE(s) ((s) & _SF_MASK)
|
||||
#define _SS_ISBUSY(s) (_SS_GETSTATE(s) != _SF_IDLE)
|
||||
#define _SS_ISCONNECTED(s) (((s) & _SF_CONNECTED) != 0)
|
||||
#define _SS_ISBOUND(s) (((s) & _SF_CONNECTED) != 0)
|
||||
|
||||
/* This macro converts a socket option value into a bit setting */
|
||||
|
||||
#define _SO_BIT(o) (1 << (o))
|
||||
|
@ -69,7 +69,7 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
|
||||
ssize_t recv(int sockfd, FAR void *buf, size_t len, int flags)
|
||||
{
|
||||
return recvfrom(sockfd, buf, len, flags, NULL, 0);
|
||||
}
|
||||
|
294
net/recvfrom.c
294
net/recvfrom.c
@ -77,6 +77,7 @@ struct recvfrom_s
|
||||
void recvfrom_interrupt(void *private)
|
||||
{
|
||||
struct recvfrom_s *pstate = (struct recvfrom_s *)private;
|
||||
struct uip_udp_conn *udp_conn;
|
||||
size_t recvlen;
|
||||
|
||||
/* 'private' might be null in some race conditions (?) */
|
||||
@ -88,9 +89,9 @@ void recvfrom_interrupt(void *private)
|
||||
if (uip_newdata())
|
||||
{
|
||||
/* Get the length of the data to return */
|
||||
if (uip_len > pstate-> rf_buflen)
|
||||
if (uip_len > pstate->rf_buflen)
|
||||
{
|
||||
recvlen = pstate-> rf_buflen;
|
||||
recvlen = pstate->rf_buflen;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -103,15 +104,16 @@ void recvfrom_interrupt(void *private)
|
||||
|
||||
/* Don't allow any further call backs. */
|
||||
|
||||
uip_conn->private = NULL;
|
||||
uip_conn->callback = NULL;
|
||||
udp_conn = (struct uip_udp_conn *)pstate->rf_sock->s_conn;
|
||||
udp_conn->private = NULL;
|
||||
udp_conn->callback = NULL;
|
||||
|
||||
/* Wake up the waiting thread, returning the number of bytes
|
||||
* actually read.
|
||||
*/
|
||||
|
||||
pstate->rf_buflen = recvlen;
|
||||
sem_post(&pstate-> rf_sem);
|
||||
sem_post(&pstate->rf_sem);
|
||||
}
|
||||
|
||||
/* No data has been received -- this is some other event... probably a
|
||||
@ -131,15 +133,16 @@ void recvfrom_interrupt(void *private)
|
||||
{
|
||||
/* Don't allow any further call backs. */
|
||||
|
||||
uip_conn->private = NULL;
|
||||
uip_conn->callback = NULL;
|
||||
udp_conn = (struct uip_udp_conn *)pstate->rf_sock->s_conn;
|
||||
udp_conn->private = NULL;
|
||||
udp_conn->callback = NULL;
|
||||
|
||||
/* Wake up the waiting thread, returning the error -EAGAIN
|
||||
* that signals the timeout event
|
||||
*/
|
||||
|
||||
pstate->rf_buflen = -EAGAIN;
|
||||
sem_post(&pstate-> rf_sem);
|
||||
sem_post(&pstate->rf_sem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,6 +150,157 @@ void recvfrom_interrupt(void *private)
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: udp_recvfrom
|
||||
*
|
||||
* Description:
|
||||
* Perform the recvfrom operation for a UDP SOCK_DGRAM
|
||||
*
|
||||
* Parameters:
|
||||
* psock Pointer to the socket structure for the SOCK_DRAM socket
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* infrom INET ddress of source
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters sent. On error,
|
||||
* -errno is returned (see recvfrom for list of errnos).
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
|
||||
FAR const struct sockaddr_in6 *infrom )
|
||||
#else
|
||||
static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
|
||||
FAR const struct sockaddr_in *infrom )
|
||||
#endif
|
||||
{
|
||||
struct uip_udp_conn *udp_conn;
|
||||
struct recvfrom_s state;
|
||||
irqstate_t save;
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
/* Perform the UDP recvfrom() operation */
|
||||
|
||||
/* 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 recvfrom_s));
|
||||
(void)sem_init(&state. rf_sem, 0, 0); /* Doesn't really fail */
|
||||
state.rf_sock = psock;
|
||||
state.rf_buflen = len;
|
||||
state.rf_buffer = buf;
|
||||
|
||||
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
|
||||
/* Set up the start time for the timeout */
|
||||
|
||||
state.rf_starttime = g_system_timer;
|
||||
#endif
|
||||
|
||||
/* Setup the UDP socket */
|
||||
|
||||
err = uip_udpconnect(psock->s_conn, NULL);
|
||||
if (err < 0)
|
||||
{
|
||||
irqrestore(save);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set up the callback in the connection */
|
||||
|
||||
udp_conn = (struct uip_udp_conn *)psock->s_conn;
|
||||
udp_conn->private = (void*)&state;
|
||||
udp_conn->callback = recvfrom_interrupt;
|
||||
|
||||
/* Wait for either the receive to complete or for an error/timeout 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. rf_sem);
|
||||
|
||||
/* Make sure that no further interrupts are processed */
|
||||
|
||||
udp_conn->private = NULL;
|
||||
udp_conn->callback = NULL;
|
||||
sem_destroy(&state. rf_sem);
|
||||
irqrestore(save);
|
||||
|
||||
/* Check for a error/timeout detected by the interrupt handler. Errors are
|
||||
* signaled by negative errno values for the rcv length
|
||||
*/
|
||||
|
||||
if (state.rf_buflen < 0)
|
||||
{
|
||||
/* Return EGAIN on a timeout */
|
||||
|
||||
return state.rf_buflen;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return -*get_errno_ptr();
|
||||
}
|
||||
|
||||
#warning "Needs to return server address"
|
||||
return state.rf_buflen;
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
/****************************************************************************
|
||||
* Function: tcp_recvfrom
|
||||
*
|
||||
* Description:
|
||||
* Perform the recvfrom operation for a TCP/IP SOCK_STREAM
|
||||
*
|
||||
* Parameters:
|
||||
* psock Pointer to the socket structure for the SOCK_DRAM socket
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* infrom INET ddress of source
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters sent. On error,
|
||||
* -errno is returned (see recvfrom for list of errnos).
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
|
||||
FAR const struct sockaddr_in6 *infrom )
|
||||
#else
|
||||
static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
|
||||
FAR const struct sockaddr_in *infrom )
|
||||
#endif
|
||||
{
|
||||
/* Verify that the SOCK_STREAM has been connected */
|
||||
|
||||
if (_SS_ISCONNECTED(psock->s_flags))
|
||||
{
|
||||
/* The SOCK_STREAM must be connect in order to recive */
|
||||
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
#warning "TCP/IP recv not implemented"
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Global Functions
|
||||
****************************************************************************/
|
||||
@ -203,8 +357,8 @@ void recvfrom_interrupt(void *private)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *from,
|
||||
socklen_t *fromlen)
|
||||
ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen)
|
||||
{
|
||||
FAR struct socket *psock;
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
@ -212,13 +366,16 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
#else
|
||||
FAR const struct sockaddr_in *infrom = (const struct sockaddr_in *)from;
|
||||
#endif
|
||||
#ifdef CONFIG_NET_UDP
|
||||
struct uip_udp_conn *udp_conn;
|
||||
struct recvfrom_s state;
|
||||
irqstate_t save;
|
||||
#endif
|
||||
ssize_t ret;
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
/* Verify that non-NULL pointers were passed */
|
||||
|
||||
if (!buf || !from || !fromlen)
|
||||
{
|
||||
err = EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Get the underlying socket structure */
|
||||
/* Verify that the sockfd corresponds to valid, allocated socket */
|
||||
@ -230,95 +387,52 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Perform the TCP/IP recv() operation */
|
||||
/* Verify that a valid address has been provided */
|
||||
|
||||
if (psock->s_type == SOCK_STREAM)
|
||||
{
|
||||
#warning "TCP/IP recv not implemented"
|
||||
err = ENOSYS;
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (from->sa_family != AF_INET6 || *fromlen < sizeof(struct sockaddr_in6))
|
||||
#else
|
||||
if (from->sa_family != AF_INET || *fromlen < sizeof(struct sockaddr_in))
|
||||
#endif
|
||||
{
|
||||
err = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform the UDP recvfrom() operation */
|
||||
/* Set the socket state to receiving */
|
||||
|
||||
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV);
|
||||
|
||||
/* Perform the TCP/IP or UDP recv() operation */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
/* 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 recvfrom_s));
|
||||
(void)sem_init(&state. rf_sem, 0, 0); /* Doesn't really fail */
|
||||
state. rf_buflen = len;
|
||||
state. rf_buffer = buf;
|
||||
|
||||
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
|
||||
/* Set up the start time for the timeout */
|
||||
|
||||
state.rf_starttime = g_system_timer;
|
||||
if (psock->s_type == SOCK_STREAM)
|
||||
#endif
|
||||
{
|
||||
ret = tcp_recvfrom(psock, buf, len, infrom);
|
||||
}
|
||||
#ifdef CONFIG_NET_UDP
|
||||
else
|
||||
{
|
||||
ret = udp_recvfrom(psock, buf, len, infrom);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup the UDP socket */
|
||||
/* Set the socket state to idle */
|
||||
|
||||
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
|
||||
|
||||
/* Handle returned errors */
|
||||
|
||||
ret = uip_udpconnect(psock->s_conn, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
irqrestore(save);
|
||||
err = -ret;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Set up the callback in the connection */
|
||||
/* Success return */
|
||||
|
||||
udp_conn = (struct uip_udp_conn *)psock->s_conn;
|
||||
udp_conn->private = (void*)&state;
|
||||
udp_conn->callback = recvfrom_interrupt;
|
||||
|
||||
/* Wait for either the read to complete: 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. rf_sem);
|
||||
|
||||
/* Make sure that no further interrupts are processed */
|
||||
|
||||
uip_conn->private = NULL;
|
||||
uip_conn->callback = NULL;
|
||||
sem_destroy(&state. rf_sem);
|
||||
irqrestore(save);
|
||||
|
||||
/* Check for a timeout. Errors are signaled by negative errno values
|
||||
* for the rcv length
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
|
||||
if (state.rf_buflen < 0)
|
||||
{
|
||||
/* Return EGAIN on a timeout */
|
||||
|
||||
err = -state.rf_buflen;
|
||||
goto errout;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
#warning "Needs to return server address"
|
||||
return state.rf_buflen;
|
||||
|
||||
#else
|
||||
err = ENOSYS;
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
errout:
|
||||
*get_errno_ptr() = err;
|
||||
|
200
net/send.c
200
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;
|
||||
}
|
||||
|
||||
|
10
net/sendto.c
10
net/sendto.c
@ -97,7 +97,7 @@ void sendto_interrupt(void *private)
|
||||
*
|
||||
* Description:
|
||||
* If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET)
|
||||
* socket, the parameters to and tolen are ignored (and the error EISCONN
|
||||
* socket, the parameters to and 'tolen' are ignored (and the error EISCONN
|
||||
* may be returned when they are not NULL and 0), and the error ENOTCONN is
|
||||
* returned when the socket was not actually connected.
|
||||
*
|
||||
@ -214,6 +214,10 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
/* Perform the UDP sendto operation */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
/* Set the socket state to sending */
|
||||
|
||||
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
|
||||
|
||||
/* Initialize the state structure. This is done with interrupts
|
||||
* disabled because we don't want anything to happen until we
|
||||
* are ready.
|
||||
@ -244,6 +248,10 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
|
||||
sem_wait(&state.st_sem);
|
||||
sem_destroy(&state.st_sem);
|
||||
|
||||
/* Set the socket state to idle */
|
||||
|
||||
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
|
||||
return len;
|
||||
#else
|
||||
err = ENOSYS;
|
||||
|
@ -34,6 +34,6 @@
|
||||
############################################################################
|
||||
|
||||
UIP_ASRCS =
|
||||
UIP_CSRCS = psock.c uip-arp.c uip.c uip-fw.c uip-neighbor.c uip-split.c \
|
||||
UIP_CSRCS = uip-arp.c uip.c uip-fw.c uip-neighbor.c uip-split.c \
|
||||
uip-tcpconn.c uip-udpconn.c uip-wait.c
|
||||
|
||||
|
385
net/uip/psock.c
385
net/uip/psock.c
@ -1,385 +0,0 @@
|
||||
/****************************************************************************
|
||||
* net/uip/psock.c
|
||||
*
|
||||
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
*
|
||||
* Based on uIP which also has a BSD style license:
|
||||
*
|
||||
* Copyright (c) 2004, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <net/uip/uip.h>
|
||||
#include <net/uip/uipopt.h>
|
||||
#include <net/uip/psock.h>
|
||||
|
||||
#define STATE_NONE 0
|
||||
#define STATE_ACKED 1
|
||||
#define STATE_READ 2
|
||||
#define STATE_BLOCKED_NEWDATA 3
|
||||
#define STATE_BLOCKED_CLOSE 4
|
||||
#define STATE_BLOCKED_SEND 5
|
||||
#define STATE_DATA_SENT 6
|
||||
|
||||
/*
|
||||
* Return value of the buffering functions that indicates that a
|
||||
* buffer was not filled by incoming data.
|
||||
*
|
||||
*/
|
||||
#define BUF_NOT_FULL 0
|
||||
#define BUF_NOT_FOUND 0
|
||||
|
||||
/*
|
||||
* Return value of the buffering functions that indicates that a
|
||||
* buffer was completely filled by incoming data.
|
||||
*
|
||||
*/
|
||||
#define BUF_FULL 1
|
||||
|
||||
/*
|
||||
* Return value of the buffering functions that indicates that an
|
||||
* end-marker byte was found.
|
||||
*
|
||||
*/
|
||||
#define BUF_FOUND 2
|
||||
|
||||
static void buf_setup(struct psock_buf *buf, uint8 *bufptr, uint16 bufsize)
|
||||
{
|
||||
buf->ptr = bufptr;
|
||||
buf->left = bufsize;
|
||||
}
|
||||
|
||||
static uint8 buf_bufdata(struct psock_buf *buf, uint16 len, uint8 **dataptr, uint16 *datalen)
|
||||
{
|
||||
if (*datalen < buf->left)
|
||||
{
|
||||
memcpy(buf->ptr, *dataptr, *datalen);
|
||||
buf->ptr += *datalen;
|
||||
buf->left -= *datalen;
|
||||
*dataptr += *datalen;
|
||||
*datalen = 0;
|
||||
return BUF_NOT_FULL;
|
||||
}
|
||||
else if (*datalen == buf->left)
|
||||
{
|
||||
memcpy(buf->ptr, *dataptr, *datalen);
|
||||
buf->ptr += *datalen;
|
||||
buf->left = 0;
|
||||
*dataptr += *datalen;
|
||||
*datalen = 0;
|
||||
return BUF_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(buf->ptr, *dataptr, buf->left);
|
||||
buf->ptr += buf->left;
|
||||
*datalen -= buf->left;
|
||||
*dataptr += buf->left;
|
||||
buf->left = 0;
|
||||
return BUF_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8 buf_bufto(struct psock_buf *buf, uint8 endmarker, uint8 **dataptr, uint16 *datalen)
|
||||
{
|
||||
uint8 c;
|
||||
while(buf->left > 0 && *datalen > 0)
|
||||
{
|
||||
c = *buf->ptr = **dataptr;
|
||||
++*dataptr;
|
||||
++buf->ptr;
|
||||
--*datalen;
|
||||
--buf->left;
|
||||
|
||||
if (c == endmarker)
|
||||
{
|
||||
return BUF_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (*datalen == 0)
|
||||
{
|
||||
return BUF_NOT_FOUND;
|
||||
}
|
||||
|
||||
while(*datalen > 0)
|
||||
{
|
||||
c = **dataptr;
|
||||
--*datalen;
|
||||
++*dataptr;
|
||||
|
||||
if (c == endmarker)
|
||||
{
|
||||
return BUF_FOUND | BUF_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
return BUF_FULL;
|
||||
}
|
||||
|
||||
static boolean send_data(register struct psock *s)
|
||||
{
|
||||
/* Inidicate that we are blocked waiting for the send to complete */
|
||||
|
||||
s->state = STATE_BLOCKED_SEND;
|
||||
|
||||
/* Loop until we successfully send the data */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* If the data has not been sent OR if it needs to be retransmitted,
|
||||
* then send it now.
|
||||
*/
|
||||
|
||||
if (s->state != STATE_DATA_SENT || uip_rexmit())
|
||||
{
|
||||
if (s->sendlen > uip_mss())
|
||||
{
|
||||
uip_send(s->sendptr, uip_mss());
|
||||
}
|
||||
else
|
||||
{
|
||||
uip_send(s->sendptr, s->sendlen);
|
||||
}
|
||||
|
||||
s->state = STATE_DATA_SENT;
|
||||
}
|
||||
|
||||
/* Check if all data has been sent and acknowledged */
|
||||
|
||||
if (s->state == STATE_DATA_SENT && uip_acked())
|
||||
{
|
||||
/* Yes.. the data has been sent AND acknowledge */
|
||||
|
||||
if (s->sendlen > uip_mss())
|
||||
{
|
||||
s->sendlen -= uip_mss();
|
||||
s->sendptr += uip_mss();
|
||||
}
|
||||
else
|
||||
{
|
||||
s->sendptr += s->sendlen;
|
||||
s->sendlen = 0;
|
||||
}
|
||||
|
||||
s->state = STATE_ACKED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* No.. then wait on the retransmit or acked events */
|
||||
|
||||
(void)uip_event_wait(UIP_ACKDATA|UIP_REXMIT);
|
||||
}
|
||||
|
||||
return FALSE; /* We never get here */
|
||||
}
|
||||
|
||||
void psock_send(struct psock *s, const char *buf, unsigned int len)
|
||||
{
|
||||
/* If there is no data to send, we exit immediately. */
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* Save the length of and a pointer to the data that is to be sent. */
|
||||
|
||||
s->sendptr = (const uint8*)buf;
|
||||
s->sendlen = len;
|
||||
s->state = STATE_NONE;
|
||||
|
||||
/* Loop here until all data is sent. The s->sendlen variable is updated
|
||||
* by the data_sent() function.
|
||||
*/
|
||||
|
||||
while(s->sendlen > 0) {
|
||||
|
||||
/* Wait until the data has been sent and acknowledged */
|
||||
|
||||
send_data(s);
|
||||
}
|
||||
|
||||
/* Done */
|
||||
|
||||
s->state = STATE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void psock_generator_send(register struct psock *s, unsigned short (*generate)(void *), void *arg)
|
||||
{
|
||||
/* Ensure that there is a generator function to call. */
|
||||
|
||||
if (generate != NULL)
|
||||
{
|
||||
/* Call the generator function to generate the data in the uip_appdata
|
||||
* buffer.
|
||||
*/
|
||||
|
||||
s->sendlen = generate(arg);
|
||||
s->sendptr = uip_appdata;
|
||||
s->state = STATE_NONE;
|
||||
|
||||
do
|
||||
{
|
||||
/* Call the generator function again if we are called to perform a
|
||||
* retransmission.
|
||||
*/
|
||||
|
||||
if (uip_rexmit())
|
||||
{
|
||||
generate(arg);
|
||||
}
|
||||
|
||||
/* Wait until all data is sent and acknowledged. */
|
||||
|
||||
send_data(s);
|
||||
}
|
||||
while(s->sendlen > 0);
|
||||
|
||||
/* Done */
|
||||
|
||||
s->state = STATE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 psock_datalen(struct psock *psock)
|
||||
{
|
||||
return psock->bufsize - psock->buf.left;
|
||||
}
|
||||
|
||||
boolean psock_checknewdata(struct psock *s)
|
||||
{
|
||||
if (s->readlen > 0)
|
||||
{
|
||||
/* There is data in the uip_appdata buffer that has not yet been read
|
||||
* with the PSOCK_READ functions.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
else if (s->state == STATE_READ)
|
||||
{
|
||||
/* All data in uip_appdata buffer already consumed. */
|
||||
|
||||
s->state = STATE_BLOCKED_NEWDATA;
|
||||
return FALSE;
|
||||
}
|
||||
else if (uip_newdata())
|
||||
{
|
||||
/* There is new data that has not been consumed. */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There is no new data. */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void psock_waitnewdata(struct psock *s)
|
||||
{
|
||||
while (!psock_checknewdata(s))
|
||||
{
|
||||
uip_event_wait(UIP_NEWDATA);
|
||||
}
|
||||
}
|
||||
|
||||
void psock_readto(register struct psock *psock, unsigned char c)
|
||||
{
|
||||
restart:
|
||||
buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
|
||||
|
||||
/* XXX: Should add buf_checkmarker() before do{} loop, if
|
||||
incoming data has been handled while waiting for a write. */
|
||||
|
||||
do
|
||||
{
|
||||
if (psock->readlen == 0)
|
||||
{
|
||||
psock_waitnewdata(psock);
|
||||
psock->state = STATE_READ;
|
||||
psock->readptr = (uint8 *)uip_appdata;
|
||||
psock->readlen = uip_datalen();
|
||||
}
|
||||
}
|
||||
while((buf_bufto(&psock->buf, c, &psock->readptr, &psock->readlen) & BUF_FOUND) == 0);
|
||||
|
||||
if (psock_datalen(psock) == 0)
|
||||
{
|
||||
psock->state = STATE_NONE;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
void psock_readbuf(register struct psock *psock)
|
||||
{
|
||||
restart:
|
||||
buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
|
||||
|
||||
/* XXX: Should add buf_checkmarker() before do{} loop, if
|
||||
incoming data has been handled while waiting for a write. */
|
||||
|
||||
do
|
||||
{
|
||||
if (psock->readlen == 0)
|
||||
{
|
||||
psock_waitnewdata(psock);
|
||||
dbg("Waited for newdata\n");
|
||||
psock->state = STATE_READ;
|
||||
psock->readptr = (uint8 *)uip_appdata;
|
||||
psock->readlen = uip_datalen();
|
||||
}
|
||||
}
|
||||
while(buf_bufdata(&psock->buf, psock->bufsize, &psock->readptr, &psock->readlen) != BUF_FULL);
|
||||
|
||||
if (psock_datalen(psock) == 0)
|
||||
{
|
||||
psock->state = STATE_NONE;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
void psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)
|
||||
{
|
||||
psock->state = STATE_NONE;
|
||||
psock->readlen = 0;
|
||||
psock->bufptr = (uint8*)buffer;
|
||||
psock->bufsize = buffersize;
|
||||
buf_setup(&psock->buf, (uint8*)buffer, buffersize);
|
||||
}
|
||||
|
@ -122,6 +122,69 @@ static struct uip_conn *uip_find_conn(uint16 portno)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: uip_selectport()
|
||||
*
|
||||
* Description:
|
||||
* If the portnumber is zero; select an unused port for the connection.
|
||||
* If the portnumber is non-zero, verify that no other connection has
|
||||
* been created with this port number.
|
||||
*
|
||||
* Input Parameters:
|
||||
* portno -- the selected port number in host order. Zero means no port
|
||||
* selected.
|
||||
*
|
||||
* Return:
|
||||
* 0 on success, -ERRNO on failure
|
||||
*
|
||||
* Assumptions:
|
||||
* Interrupts are disabled
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int uip_selectport(uint16 portno)
|
||||
{
|
||||
if (portno == 0)
|
||||
{
|
||||
/* No local port assigned. Loop until we find a valid listen port number
|
||||
* that is not being used by any other connection.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
/* Guess that the next available port number will be the one after
|
||||
* the last port number assigned.
|
||||
*/
|
||||
portno = ++g_last_tcp_port;
|
||||
|
||||
/* Make sure that the port number is within range */
|
||||
|
||||
if (g_last_tcp_port >= 32000)
|
||||
{
|
||||
g_last_tcp_port = 4096;
|
||||
}
|
||||
}
|
||||
while (uip_find_conn(g_last_tcp_port));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A port number has been supplied. Verify that no other TCP/IP
|
||||
* connection is using this local port.
|
||||
*/
|
||||
|
||||
if (uip_find_conn(portno))
|
||||
{
|
||||
/* It is in use... return EADDRINUSE */
|
||||
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the selecte or verified port number */
|
||||
|
||||
return portno;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -422,6 +485,20 @@ int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in6 *addr)
|
||||
int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in *addr)
|
||||
#endif
|
||||
{
|
||||
irqstate_t flags;
|
||||
int port;
|
||||
|
||||
/* Verify or select a local port */
|
||||
|
||||
flags = irqsave();
|
||||
port = uip_selectport(ntohs(conn->lport));
|
||||
irqrestore(flags);
|
||||
|
||||
if (port < 0)
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
#warning "Need to implement bind logic"
|
||||
return -ENOSYS;
|
||||
}
|
||||
@ -453,7 +530,7 @@ int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr)
|
||||
#endif
|
||||
{
|
||||
irqstate_t flags;
|
||||
uint16 port;
|
||||
int port;
|
||||
|
||||
/* The connection is expected to be in the UIP_ALLOCATED state.. i.e.,
|
||||
* allocated via up_tcpalloc(), but not yet put into the active connections
|
||||
@ -469,29 +546,13 @@ int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr)
|
||||
* one now.
|
||||
*/
|
||||
|
||||
port = ntohs(conn->lport);
|
||||
if (port == 0)
|
||||
flags = irqsave();
|
||||
port = uip_selectport(ntohs(conn->lport));
|
||||
irqrestore(flags);
|
||||
|
||||
if (port < 0)
|
||||
{
|
||||
/* No local port assigned. Loop until we find a valid listen port number\
|
||||
* that is not being used by any other connection.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
/* Guess that the next available port number will be the one after
|
||||
* the last port number assigned.
|
||||
*/
|
||||
#warning "This need protection from other threads and from interrupts"
|
||||
port = ++g_last_tcp_port;
|
||||
|
||||
/* Make sure that the port number is within range */
|
||||
|
||||
if (g_last_tcp_port >= 32000)
|
||||
{
|
||||
g_last_tcp_port = 4096;
|
||||
}
|
||||
}
|
||||
while (uip_find_conn(g_last_tcp_port));
|
||||
return port;
|
||||
}
|
||||
|
||||
/* Initialize and return the connection structure, bind it to the port number */
|
||||
@ -511,7 +572,7 @@ int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr)
|
||||
conn->rto = UIP_RTO;
|
||||
conn->sa = 0;
|
||||
conn->sv = 16; /* Initial value of the RTT variance. */
|
||||
conn->lport = htons(port);
|
||||
conn->lport = htons((uint16)port);
|
||||
|
||||
/* The sockaddr port is 16 bits and already in network order */
|
||||
|
||||
|
@ -47,13 +47,14 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <semaphore.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/uip/uip.h>
|
||||
#include <net/uip/psock.h>
|
||||
#include <net/uip/smtp.h>
|
||||
|
||||
#include "smtp-strings.h"
|
||||
@ -77,7 +78,6 @@ struct smtp_state
|
||||
uint8 state;
|
||||
boolean connected;
|
||||
sem_t sem;
|
||||
struct psock psock;
|
||||
uip_ipaddr_t smtpserver;
|
||||
char *localhostname;
|
||||
char *to;
|
||||
@ -89,146 +89,155 @@ struct smtp_state
|
||||
int sentlen;
|
||||
int textlen;
|
||||
int sendptr;
|
||||
int result;
|
||||
char buffer[SMTP_INPUT_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
static volatile struct smtp_state *gpsmtp = 0;
|
||||
|
||||
static void smtp_send_message(struct smtp_state *psmtp)
|
||||
static inline int smtp_send_message(int sockfd, struct smtp_state *psmtp)
|
||||
{
|
||||
psock_readto(&psmtp->psock, ISO_nl);
|
||||
if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (strncmp(psmtp->buffer, smtp_220, 3) != 0)
|
||||
{
|
||||
PSOCK_CLOSE(&psmtp->psock);
|
||||
psmtp->result = 2;
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_helo);
|
||||
PSOCK_SEND_STR(&psmtp->psock, psmtp->localhostname);
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl);
|
||||
snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_helo, psmtp->localhostname);
|
||||
if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
psock_readto(&psmtp->psock, ISO_nl);
|
||||
if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (psmtp->buffer[0] != ISO_2)
|
||||
{
|
||||
PSOCK_CLOSE(&psmtp->psock);
|
||||
psmtp->result = 3;
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_mail_from);
|
||||
PSOCK_SEND_STR(&psmtp->psock, psmtp->from);
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl);
|
||||
snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_mail_from, psmtp->from);
|
||||
if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
psock_readto(&psmtp->psock, ISO_nl);
|
||||
if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (psmtp->buffer[0] != ISO_2)
|
||||
{
|
||||
PSOCK_CLOSE(&psmtp->psock);
|
||||
psmtp->result = 3;
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_rcpt_to);
|
||||
PSOCK_SEND_STR(&psmtp->psock, psmtp->to);
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl);
|
||||
snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_rcpt_to, psmtp->to);
|
||||
if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
psock_readto(&psmtp->psock, ISO_nl);
|
||||
if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (psmtp->buffer[0] != ISO_2)
|
||||
{
|
||||
PSOCK_CLOSE(&psmtp->psock);
|
||||
psmtp->result = 5;
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (psmtp->cc != 0)
|
||||
{
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_rcpt_to);
|
||||
PSOCK_SEND_STR(&psmtp->psock, psmtp->cc);
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl);
|
||||
snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_rcpt_to, psmtp->cc);
|
||||
if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
psock_readto(&psmtp->psock, ISO_nl);
|
||||
if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (psmtp->buffer[0] != ISO_2)
|
||||
{
|
||||
PSOCK_CLOSE(&psmtp->psock);
|
||||
psmtp->result = 6;
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_data);
|
||||
if (send(sockfd, smtp_data, strlen(smtp_data), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
psock_readto(&psmtp->psock, ISO_nl);
|
||||
if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (psmtp->buffer[0] != ISO_3)
|
||||
{
|
||||
PSOCK_CLOSE(&psmtp->psock);
|
||||
psmtp->result = 7;
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_to);
|
||||
PSOCK_SEND_STR(&psmtp->psock, psmtp->to);
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl);
|
||||
snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_to, psmtp->to);
|
||||
if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (psmtp->cc != 0)
|
||||
{
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)psmtp->cc);
|
||||
PSOCK_SEND_STR(&psmtp->psock, psmtp->cc);
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl);
|
||||
snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_to, psmtp->cc);
|
||||
if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_from);
|
||||
PSOCK_SEND_STR(&psmtp->psock, psmtp->from);
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl);
|
||||
snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_from, psmtp->from);
|
||||
if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_subject);
|
||||
PSOCK_SEND_STR(&psmtp->psock, psmtp->subject);
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnl);
|
||||
snprintf(psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, "%s%s\r\n", smtp_subject, psmtp->subject);
|
||||
if (send(sockfd, psmtp->buffer, strlen(psmtp->buffer), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
psock_send(&psmtp->psock, psmtp->msg, psmtp->msglen);
|
||||
if (send(sockfd, psmtp->msg, psmtp->msglen, 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_crnlperiodcrnl);
|
||||
if (send(sockfd, smtp_crnlperiodcrnl, strlen(smtp_crnlperiodcrnl), 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (recv(sockfd, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE, 0) < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
psock_readto(&psmtp->psock, ISO_nl);
|
||||
if (psmtp->buffer[0] != ISO_2)
|
||||
{
|
||||
PSOCK_CLOSE(&psmtp->psock);
|
||||
psmtp->result = 8;
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
PSOCK_SEND_STR(&psmtp->psock, (char *)smtp_quit);
|
||||
psmtp->result = 0;
|
||||
}
|
||||
|
||||
/* This function is called by the UIP interrupt handling logic whenevent an
|
||||
* event of interest occurs.
|
||||
*/
|
||||
|
||||
void uip_interrupt_event(void)
|
||||
{
|
||||
#warning OBSOLETE -- needs to be redesigned
|
||||
if (gpsmtp)
|
||||
if (send(sockfd, smtp_quit, strlen(smtp_quit), 0) < 0)
|
||||
{
|
||||
if (uip_closed())
|
||||
{
|
||||
gpsmtp->connected = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uip_aborted() || uip_timedout())
|
||||
{
|
||||
gpsmtp->connected = FALSE;
|
||||
}
|
||||
|
||||
sem_post((sem_t*)&gpsmtp->sem);
|
||||
return ERROR;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Specificy an SMTP server and hostname.
|
||||
@ -264,6 +273,7 @@ int smtp_send(void *handle, char *to, char *cc, char *from, char *subject, char
|
||||
struct smtp_state *psmtp = (struct smtp_state *)handle;
|
||||
struct sockaddr_in server;
|
||||
int sockfd;
|
||||
int ret;
|
||||
|
||||
/* Setup */
|
||||
|
||||
@ -274,7 +284,6 @@ int smtp_send(void *handle, char *to, char *cc, char *from, char *subject, char
|
||||
psmtp->subject = subject;
|
||||
psmtp->msg = msg;
|
||||
psmtp->msglen = msglen;
|
||||
psmtp->result = OK;
|
||||
|
||||
/* Create a socket */
|
||||
|
||||
@ -284,12 +293,6 @@ int smtp_send(void *handle, char *to, char *cc, char *from, char *subject, char
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Make this instance globally visible (we will get interrupts as
|
||||
* soon as we connect
|
||||
*/
|
||||
|
||||
gpsmtp = psmtp;
|
||||
|
||||
/* Connect to server. First we have to set some fields in the
|
||||
* 'server' structure. The system will assign me an arbitrary
|
||||
* local port that is not in use.
|
||||
@ -301,27 +304,16 @@ int smtp_send(void *handle, char *to, char *cc, char *from, char *subject, char
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0)
|
||||
{
|
||||
close(sockfd);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Initialize the psock structure inside the smtp state structure */
|
||||
|
||||
psock_init(&psmtp->psock, psmtp->buffer, SMTP_INPUT_BUFFER_SIZE);
|
||||
|
||||
/* And wait for the the socket to be connected */
|
||||
|
||||
sem_wait(&psmtp->sem);
|
||||
gpsmtp = 0;
|
||||
|
||||
/* Was an error reported by interrupt handler? */
|
||||
|
||||
if (psmtp->result == OK )
|
||||
{
|
||||
/* No... Send the message */
|
||||
smtp_send_message(psmtp);
|
||||
}
|
||||
|
||||
return psmtp->result;
|
||||
/* Send the message */
|
||||
|
||||
ret = smtp_send_message(sockfd, psmtp);
|
||||
|
||||
close(sockfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *smtp_open(void)
|
||||
|
@ -30,15 +30,15 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/uip/uip.h>
|
||||
#include <net/uip/psock.h>
|
||||
#include <net/uip/httpd.h>
|
||||
|
||||
#include "httpd-cgi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CONFIG_HTTPDCGI_FILESTATS 1
|
||||
#undef CONFIG_HTTPDCGI_DCPSTATS
|
||||
#define CONFIG_HTTPDCGI_NETSTATS 1
|
||||
@ -101,7 +101,7 @@ static const char *states[] =
|
||||
};
|
||||
#endif
|
||||
|
||||
static void nullfunction(struct httpd_state *s, char *ptr)
|
||||
static void nullfunction(struct httpd_state *pstate, char *ptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -120,66 +120,57 @@ httpd_cgifunction httpd_cgi(char *name)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HTTPDCGI_FILESTATS
|
||||
static unsigned short generate_file_stats(void *arg)
|
||||
static void file_stats(struct httpd_state *pstate, char *ptr)
|
||||
{
|
||||
char *f = (char *)arg;
|
||||
return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, "%5u", httpd_fs_count(f));
|
||||
}
|
||||
|
||||
static void file_stats(struct httpd_state *s, char *ptr)
|
||||
{
|
||||
psock_generator_send(&s->sout, generate_file_stats, strchr(ptr, ' ') + 1);
|
||||
char buffer[16];
|
||||
char *pcount = strchr(ptr, ' ') + 1;
|
||||
snprintf(buffer, 16, "%5u", httpd_fs_count(pcount));
|
||||
(void)send(pstate->sockout, buffer, strlen(buffer), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_HTTPDCGI_TCPSTATS
|
||||
static unsigned short generate_tcp_stats(void *arg)
|
||||
static void tcp_stats(struct httpd_state *pstate, char *ptr)
|
||||
{
|
||||
struct uip_conn *conn;
|
||||
struct httpd_state *s = (struct httpd_state *)arg;
|
||||
struct httpd_state *pstate = (struct httpd_state *)arg;
|
||||
char buffer[256];
|
||||
|
||||
conn = &uip_conns[s->count];
|
||||
return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE,
|
||||
"<tr><td>%d</td><td>%u.%u.%u.%u:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n",
|
||||
htons(conn->lport),
|
||||
htons(conn->ripaddr[0]) >> 8,
|
||||
htons(conn->ripaddr[0]) & 0xff,
|
||||
htons(conn->ripaddr[1]) >> 8,
|
||||
htons(conn->ripaddr[1]) & 0xff,
|
||||
htons(conn->rport),
|
||||
states[conn->tcpstateflags & UIP_TS_MASK],
|
||||
conn->nrtx,
|
||||
conn->timer,
|
||||
(uip_outstanding(conn))? '*':' ',
|
||||
(uip_stopped(conn))? '!':' ');
|
||||
}
|
||||
|
||||
static void tcp_stats(struct httpd_state *s, char *ptr)
|
||||
{
|
||||
for(s->count = 0; s->count < UIP_CONNS; ++s->count)
|
||||
for(pstate->count = 0; pstate->count < UIP_CONNS; ++pstate->count)
|
||||
{
|
||||
if((uip_conns[s->count].tcpstateflags & UIP_TS_MASK) != UIP_CLOSED)
|
||||
conn = &uip_conns[pstate->count];
|
||||
if((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED)
|
||||
{
|
||||
psock_generator_send(&s->sout, generate_tcp_stats, s);
|
||||
snprintf(buffer, 25t,
|
||||
"<tr><td>%d</td><td>%u.%u.%u.%u:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n",
|
||||
htons(conn->lport),
|
||||
htons(conn->ripaddr[0]) >> 8,
|
||||
htons(conn->ripaddr[0]) & 0xff,
|
||||
htons(conn->ripaddr[1]) >> 8,
|
||||
htons(conn->ripaddr[1]) & 0xff,
|
||||
htons(conn->rport),
|
||||
states[conn->tcpstateflags & UIP_TS_MASK],
|
||||
conn->nrtx,
|
||||
conn->timer,
|
||||
(uip_outstanding(conn))? '*':' ',
|
||||
(uip_stopped(conn))? '!':' ');
|
||||
|
||||
(void)send(pstate->sockout, buffer, strlen(buffer), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HTTPDCGI_NETSTATS
|
||||
static unsigned short generate_net_stats(void *arg)
|
||||
{
|
||||
struct httpd_state *s = (struct httpd_state *)arg;
|
||||
return snprintf((char*)uip_appdata, UIP_APPDATA_SIZE,
|
||||
"%5u\n", ((uip_stats_t *)&uip_stat)[s->count]);
|
||||
}
|
||||
|
||||
static void net_stats(struct httpd_state *s, char *ptr)
|
||||
static void net_stats(struct httpd_state *pstate, char *ptr)
|
||||
{
|
||||
#if UIP_STATISTICS
|
||||
for(s->count = 0; s->count < sizeof(uip_stat) / sizeof(uip_stats_t); ++s->count)
|
||||
char buffer[16];
|
||||
|
||||
for(pstate->count = 0; pstate->count < sizeof(uip_stat) / sizeof(uip_stats_t); ++pstate->count)
|
||||
{
|
||||
psock_generator_send(&s->sout, generate_net_stats, s);
|
||||
snprintf(buffer, 16, "%5u\n", ((uip_stats_t *)&uip_stat)[pstate->count]);
|
||||
send(pstate->sockout, buffer, strlen(buffer), 0);
|
||||
}
|
||||
#endif /* UIP_STATISTICS */
|
||||
}
|
||||
|
@ -33,9 +33,10 @@
|
||||
#ifndef __HTTPD_CGI_H__
|
||||
#define __HTTPD_CGI_H__
|
||||
|
||||
#include <net/uip/psock.h>
|
||||
#include <net/uip/httpd.h>
|
||||
|
||||
#include "httpd.h"
|
||||
|
||||
typedef void (* httpd_cgifunction)(struct httpd_state *, char *);
|
||||
|
||||
httpd_cgifunction httpd_cgi(char *name);
|
||||
|
@ -45,6 +45,7 @@
|
||||
|
||||
#include <net/uip/httpd.h>
|
||||
|
||||
#include "httpd.h"
|
||||
#include "httpd-fsdata.h"
|
||||
|
||||
#ifndef NULL
|
||||
|
@ -35,9 +35,12 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/uip/uip.h>
|
||||
#include <net/uip/httpd.h>
|
||||
|
||||
#include "httpd.h"
|
||||
#include "httpd-cgi.h"
|
||||
#include "http-strings.h"
|
||||
|
||||
@ -54,244 +57,208 @@
|
||||
#define ISO_slash 0x2f
|
||||
#define ISO_colon 0x3a
|
||||
|
||||
static unsigned short generate_part_of_file(void *state)
|
||||
#define SEND_STR(psock, str) psock_send(psock, str, strlen(str))
|
||||
|
||||
static inline int send_file(struct httpd_state *pstate)
|
||||
{
|
||||
struct httpd_state *s = (struct httpd_state *)state;
|
||||
|
||||
if (s->file.len > uip_mss()) {
|
||||
s->len = uip_mss();
|
||||
} else {
|
||||
s->len = s->file.len;
|
||||
}
|
||||
memcpy(uip_appdata, s->file.data, s->len);
|
||||
|
||||
return s->len;
|
||||
return send(pstate->sockout, pstate->file.data, pstate->file.len, 0);
|
||||
}
|
||||
|
||||
static void send_file(struct httpd_state *s)
|
||||
static inline int send_part_of_file(struct httpd_state *pstate)
|
||||
{
|
||||
do {
|
||||
psock_generator_send(&s->sout, generate_part_of_file, s);
|
||||
s->file.len -= s->len;
|
||||
s->file.data += s->len;
|
||||
} while(s->file.len > 0);
|
||||
#warning REVISIT must not return until file sent
|
||||
return send(pstate->sockout, pstate->file.data, pstate->len, 0);
|
||||
}
|
||||
|
||||
static void send_part_of_file(struct httpd_state *s)
|
||||
{
|
||||
psock_send(&s->sout, s->file.data, s->len);
|
||||
#warning REVISIT must not return until file sent
|
||||
}
|
||||
|
||||
static void next_scriptstate(struct httpd_state *s)
|
||||
static void next_scriptstate(struct httpd_state *pstate)
|
||||
{
|
||||
char *p;
|
||||
p = strchr(s->scriptptr, ISO_nl) + 1;
|
||||
s->scriptlen -= (unsigned short)(p - s->scriptptr);
|
||||
s->scriptptr = p;
|
||||
p = strchr(pstate->scriptptr, ISO_nl) + 1;
|
||||
pstate->scriptlen -= (unsigned short)(p - pstate->scriptptr);
|
||||
pstate->scriptptr = p;
|
||||
}
|
||||
|
||||
static void handle_script(struct httpd_state *s)
|
||||
static void handle_script(struct httpd_state *pstate)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
while(s->file.len > 0) {
|
||||
|
||||
while(pstate->file.len > 0) {
|
||||
|
||||
/* Check if we should start executing a script. */
|
||||
if (*s->file.data == ISO_percent &&
|
||||
*(s->file.data + 1) == ISO_bang) {
|
||||
s->scriptptr = s->file.data + 3;
|
||||
s->scriptlen = s->file.len - 3;
|
||||
if (*(s->scriptptr - 1) == ISO_colon) {
|
||||
httpd_fs_open(s->scriptptr + 1, &s->file);
|
||||
send_file(s);
|
||||
if (*pstate->file.data == ISO_percent &&
|
||||
*(pstate->file.data + 1) == ISO_bang) {
|
||||
pstate->scriptptr = pstate->file.data + 3;
|
||||
pstate->scriptlen = pstate->file.len - 3;
|
||||
if (*(pstate->scriptptr - 1) == ISO_colon) {
|
||||
httpd_fs_open(pstate->scriptptr + 1, &pstate->file);
|
||||
send_file(pstate);
|
||||
} else {
|
||||
httpd_cgi(s->scriptptr)(s, s->scriptptr);
|
||||
httpd_cgi(pstate->scriptptr)(pstate, pstate->scriptptr);
|
||||
}
|
||||
next_scriptstate(s);
|
||||
next_scriptstate(pstate);
|
||||
|
||||
/* The script is over, so we reset the pointers and continue
|
||||
sending the rest of the file. */
|
||||
s->file.data = s->scriptptr;
|
||||
s->file.len = s->scriptlen;
|
||||
pstate->file.data = pstate->scriptptr;
|
||||
pstate->file.len = pstate->scriptlen;
|
||||
} else {
|
||||
/* See if we find the start of script marker in the block of HTML
|
||||
to be sent. */
|
||||
|
||||
if (s->file.len > uip_mss()) {
|
||||
s->len = uip_mss();
|
||||
if (pstate->file.len > uip_mss()) {
|
||||
pstate->len = uip_mss();
|
||||
} else {
|
||||
s->len = s->file.len;
|
||||
pstate->len = pstate->file.len;
|
||||
}
|
||||
|
||||
if (*s->file.data == ISO_percent) {
|
||||
ptr = strchr(s->file.data + 1, ISO_percent);
|
||||
if (*pstate->file.data == ISO_percent) {
|
||||
ptr = strchr(pstate->file.data + 1, ISO_percent);
|
||||
} else {
|
||||
ptr = strchr(s->file.data, ISO_percent);
|
||||
ptr = strchr(pstate->file.data, ISO_percent);
|
||||
}
|
||||
if (ptr != NULL &&
|
||||
ptr != s->file.data) {
|
||||
s->len = (int)(ptr - s->file.data);
|
||||
if (s->len >= uip_mss()) {
|
||||
s->len = uip_mss();
|
||||
ptr != pstate->file.data) {
|
||||
pstate->len = (int)(ptr - pstate->file.data);
|
||||
if (pstate->len >= uip_mss()) {
|
||||
pstate->len = uip_mss();
|
||||
}
|
||||
}
|
||||
send_part_of_file(s);
|
||||
s->file.data += s->len;
|
||||
s->file.len -= s->len;
|
||||
send_part_of_file(pstate);
|
||||
pstate->file.data += pstate->len;
|
||||
pstate->file.len -= pstate->len;
|
||||
}
|
||||
}
|
||||
#warning REVISIT must not return until sent
|
||||
}
|
||||
|
||||
static void send_headers(struct httpd_state *s, const char *statushdr)
|
||||
static int send_headers(struct httpd_state *pstate, const char *statushdr)
|
||||
{
|
||||
char *ptr;
|
||||
int ret;
|
||||
|
||||
PSOCK_SEND_STR(&s->sout, statushdr);
|
||||
ret = send(pstate->sockout, statushdr, strlen(statushdr), 0);
|
||||
|
||||
ptr = strrchr(s->filename, ISO_period);
|
||||
if (ptr == NULL) {
|
||||
PSOCK_SEND_STR(&s->sout, http_content_type_binary);
|
||||
} else if (strncmp(http_html, ptr, 5) == 0 ||
|
||||
strncmp(http_shtml, ptr, 6) == 0) {
|
||||
PSOCK_SEND_STR(&s->sout, http_content_type_html);
|
||||
} else if (strncmp(http_css, ptr, 4) == 0) {
|
||||
PSOCK_SEND_STR(&s->sout, http_content_type_css);
|
||||
} else if (strncmp(http_png, ptr, 4) == 0) {
|
||||
PSOCK_SEND_STR(&s->sout, http_content_type_png);
|
||||
} else if (strncmp(http_gif, ptr, 4) == 0) {
|
||||
PSOCK_SEND_STR(&s->sout, http_content_type_gif);
|
||||
} else if (strncmp(http_jpg, ptr, 4) == 0) {
|
||||
PSOCK_SEND_STR(&s->sout, http_content_type_jpg);
|
||||
} else {
|
||||
PSOCK_SEND_STR(&s->sout, http_content_type_plain);
|
||||
}
|
||||
#warning REVISIT must not return until sent
|
||||
}
|
||||
|
||||
static void handle_output(struct httpd_state *s)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!httpd_fs_open(s->filename, &s->file))
|
||||
ptr = strrchr(pstate->filename, ISO_period);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
httpd_fs_open(http_404_html, &s->file);
|
||||
strcpy(s->filename, http_404_html);
|
||||
send_headers(s, http_header_404);
|
||||
send_file(s);
|
||||
ret = send(pstate->sockout, http_content_type_binary, strlen(http_content_type_binary), 0);
|
||||
}
|
||||
else if (strncmp(http_html, ptr, 5) == 0 || strncmp(http_shtml, ptr, 6) == 0)
|
||||
{
|
||||
ret = send(pstate->sockout, http_content_type_html, strlen(http_content_type_html), 0);
|
||||
}
|
||||
else if (strncmp(http_css, ptr, 4) == 0)
|
||||
{
|
||||
ret = send(pstate->sockout, http_content_type_css, strlen(http_content_type_css), 0);
|
||||
}
|
||||
else if (strncmp(http_png, ptr, 4) == 0)
|
||||
{
|
||||
ret = send(pstate->sockout, http_content_type_png, strlen(http_content_type_png), 0);
|
||||
}
|
||||
else if (strncmp(http_gif, ptr, 4) == 0)
|
||||
{
|
||||
ret = send(pstate->sockout, http_content_type_gif, strlen(http_content_type_gif), 0);
|
||||
}
|
||||
else if (strncmp(http_jpg, ptr, 4) == 0)
|
||||
{
|
||||
ret = send(pstate->sockout, http_content_type_jpg, strlen(http_content_type_jpg), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
send_headers(s, http_header_200);
|
||||
ptr = strchr(s->filename, ISO_period);
|
||||
ret = send(pstate->sockout, http_content_type_plain, strlen(http_content_type_plain), 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handle_output(struct httpd_state *pstate)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!httpd_fs_open(pstate->filename, &pstate->file))
|
||||
{
|
||||
httpd_fs_open(http_404_html, &pstate->file);
|
||||
strcpy(pstate->filename, http_404_html);
|
||||
send_headers(pstate, http_header_404);
|
||||
send_file(pstate);
|
||||
}
|
||||
else
|
||||
{
|
||||
send_headers(pstate, http_header_200);
|
||||
ptr = strchr(pstate->filename, ISO_period);
|
||||
if (ptr != NULL && strncmp(ptr, http_shtml, 6) == 0)
|
||||
{
|
||||
handle_script(s);
|
||||
handle_script(pstate);
|
||||
}
|
||||
else
|
||||
{
|
||||
send_file(s);
|
||||
send_file(pstate);
|
||||
}
|
||||
}
|
||||
PSOCK_CLOSE(&s->sout);
|
||||
}
|
||||
|
||||
static void handle_input(struct httpd_state *s)
|
||||
static int handle_input(struct httpd_state *pstate)
|
||||
{
|
||||
psock_readto(&s->sin, ISO_space);
|
||||
ssize_t recvlen;
|
||||
|
||||
if (strncmp(s->inputbuf, http_get, 4) != 0)
|
||||
if (recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0) < 0)
|
||||
{
|
||||
PSOCK_CLOSE(&s->sin);
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (strncmp(pstate->inputbuf, http_get, 4) != 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
psock_readto(&s->sin, ISO_space);
|
||||
recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0);
|
||||
if (recvlen < 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (s->inputbuf[0] != ISO_slash)
|
||||
if (pstate->inputbuf[0] != ISO_slash)
|
||||
{
|
||||
PSOCK_CLOSE(&s->sin);
|
||||
return;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (s->inputbuf[1] == ISO_space)
|
||||
if (pstate->inputbuf[1] == ISO_space)
|
||||
{
|
||||
strncpy(s->filename, http_index_html, sizeof(s->filename));
|
||||
strncpy(pstate->filename, http_index_html, sizeof(pstate->filename));
|
||||
}
|
||||
else
|
||||
{
|
||||
s->inputbuf[psock_datalen(&s->sin) - 1] = 0;
|
||||
strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
|
||||
pstate->inputbuf[recvlen - 1] = 0;
|
||||
strncpy(pstate->filename, &pstate->inputbuf[0], sizeof(pstate->filename));
|
||||
}
|
||||
|
||||
s->state = STATE_OUTPUT;
|
||||
pstate->state = STATE_OUTPUT;
|
||||
|
||||
while(1)
|
||||
{
|
||||
psock_readto(&s->sin, ISO_nl);
|
||||
|
||||
if (strncmp(s->inputbuf, http_referer, 8) == 0)
|
||||
recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0);
|
||||
if (recvlen < 0)
|
||||
{
|
||||
s->inputbuf[psock_datalen(&s->sin) - 2] = 0;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (strncmp(pstate->inputbuf, http_referer, 8) == 0)
|
||||
{
|
||||
pstate->inputbuf[recvlen - 2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void handle_connection(struct httpd_state *s)
|
||||
static void handle_connection(struct httpd_state *pstate)
|
||||
{
|
||||
handle_input(s);
|
||||
if (s->state == STATE_OUTPUT) {
|
||||
handle_output(s);
|
||||
handle_input(pstate);
|
||||
if (pstate->state == STATE_OUTPUT) {
|
||||
handle_output(pstate);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is called by the UIP interrupt handling logic whenevent an
|
||||
* event of interest occurs.
|
||||
*/
|
||||
|
||||
void uip_interrupt_event(void)
|
||||
void httpd_listen(void)
|
||||
{
|
||||
#warning OBSOLETE -- needs to be redesigned
|
||||
/* Get the private application specific data */
|
||||
struct httpd_state *s = (struct httpd_state *)(uip_conn->private);
|
||||
|
||||
/* Has application specific data been allocate yet? */
|
||||
|
||||
if (!s)
|
||||
{
|
||||
/* No.. allocate it now */
|
||||
s = (struct httpd_state *)malloc(sizeof(struct httpd_state));
|
||||
if (!s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* And assign the private instance to the connection */
|
||||
uip_conn->private = s;
|
||||
}
|
||||
|
||||
if (uip_closed() || uip_aborted() || uip_timedout()) {
|
||||
} else if (uip_connected()) {
|
||||
psock_init(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
|
||||
psock_init(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
|
||||
s->state = STATE_WAITING;
|
||||
s->timer = 0;
|
||||
handle_connection(s);
|
||||
} else if (s != NULL) {
|
||||
if (uip_poll()) {
|
||||
++s->timer;
|
||||
if (s->timer >= 20) {
|
||||
uip_abort();
|
||||
}
|
||||
} else {
|
||||
s->timer = 0;
|
||||
}
|
||||
handle_connection(s);
|
||||
} else {
|
||||
uip_abort();
|
||||
}
|
||||
#warning "this is all very broken at the moment"
|
||||
}
|
||||
|
||||
/* Initialize the web server
|
||||
|
74
netutils/webserver/httpd.h
Normal file
74
netutils/webserver/httpd.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* httpd.h
|
||||
*
|
||||
* Copyright (c) 2001-2005, Adam Dunkels.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _NETUTILS_WEBSERVER_HTTPD_H
|
||||
#define _NETUTILS_WEBSERVER_HTTPD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define HTTPD_FS_STATISTICS 1
|
||||
#define HTTPD_INBUFFER_SIZE 50
|
||||
|
||||
struct httpd_fs_file
|
||||
{
|
||||
char *data;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct httpd_state
|
||||
{
|
||||
unsigned char timer;
|
||||
int sockin;
|
||||
int sockout;
|
||||
char inputbuf[HTTPD_INBUFFER_SIZE];
|
||||
char filename[20];
|
||||
char state;
|
||||
struct httpd_fs_file file;
|
||||
int len;
|
||||
char *scriptptr;
|
||||
int scriptlen;
|
||||
|
||||
unsigned short count;
|
||||
};
|
||||
|
||||
#ifdef HTTPD_FS_STATISTICS
|
||||
#if HTTPD_FS_STATISTICS == 1
|
||||
extern uint16 httpd_fs_count(char *name);
|
||||
#endif /* HTTPD_FS_STATISTICS */
|
||||
#endif /* HTTPD_FS_STATISTICS */
|
||||
|
||||
/* file must be allocated by caller and will be filled in
|
||||
* by the function.
|
||||
*/
|
||||
|
||||
int httpd_fs_open(const char *name, struct httpd_fs_file *file);
|
||||
void httpd_fs_init(void);
|
||||
|
||||
#endif /* _NETUTILS_WEBSERVER_HTTPD_H */
|
Loading…
Reference in New Issue
Block a user