diff --git a/ChangeLog b/ChangeLog index b4c345e501802b062db95941f69c01e97b8d5247..2541ff5da9b5f047e7a6d2d5aaa6b2c9e1a73188 100644 --- a/ChangeLog +++ b/ChangeLog @@ -205,4 +205,5 @@ http://www.sics.se/~adam/uip/index.php/Main_Page) * Adding socket(), bind(), connect() * Added snprintf() - + * Added send() and sendto(); integrate write() and close() with socket descriptors. + * Added recv() and recvfrom(). diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index ef9aa49f7de02fdcd79b40124ba34de385966c99..e42714ad255fc3379cbb0589ade5ec894d266e52 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -639,6 +639,8 @@ Other memory: http://www.sics.se/~adam/uip/index.php/Main_Page) * Adding socket(), bind(), connect() * Added snprintf() + * Added send() and sendto(); integrate write() and close() with socket descriptors. + * Added recv() and recvfrom(). </pre></ul> <table width ="100%"> diff --git a/examples/uip/main.c b/examples/uip/main.c index 367e7e1c190bed0be4ae1e0db8348c12bcf285ef..d7cfc6bb224d3454b31a5d5d2a4a847bf364c0e8 100644 --- a/examples/uip/main.c +++ b/examples/uip/main.c @@ -31,7 +31,7 @@ * * This file is part of the uIP TCP/IP stack. * - * $Id: main.c,v 1.3 2007-09-01 18:06:12 patacongo Exp $ + * $Id: main.c,v 1.4 2007-09-03 20:34:43 patacongo Exp $ * */ @@ -84,6 +84,7 @@ int user_start(int argc, char *argv[]) #elif defined(CONFIG_EXAMPLE_UIP_TELNETD) telnetd_init(); #elif defined(CONFIG_EXAMPLE_UIP_DHCPC) + resolv_init(); handle = dhcpc_open(&mac, 6); if (handle) { @@ -126,21 +127,6 @@ void uip_log(char *m) printf("uIP log message: %s\n", m); } -void resolv_found(char *name, uint16 *ipaddr) -{ - if (ipaddr == NULL) - { - printf("Host '%s' not found.\n", name); - } - else - { - printf("Found name '%s' = %d.%d.%d.%d\n", name, - htons(ipaddr[0]) >> 8, htons(ipaddr[0]) & 0xff, - htons(ipaddr[1]) >> 8, htons(ipaddr[1]) & 0xff); - /* webclient_get("www.sics.se", 80, "/~adam/uip");*/ - } -} - void webclient_closed(void) { printf("Webclient: connection closed\n"); diff --git a/fs/fs_close.c b/fs/fs_close.c index a704d1d5ec67307ad3c56a61c2bfbf1db4d9ed98..5a63ba6a909a2aea88dac42e6646908b07d44a08 100644 --- a/fs/fs_close.c +++ b/fs/fs_close.c @@ -43,70 +43,120 @@ #include <sched.h> #include <errno.h> #include <nuttx/fs.h> + +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 +# include <nuttx/net.h> +#endif + #include "fs_internal.h" /**************************************************************************** * Global Functions ****************************************************************************/ +/**************************************************************************** + * Function: close + * + * Description: + * close() closes a file descriptor, so that it no longer refers to any + * file and may be reused. Any record locks (see fcntl(2)) held on the file + * it was associated with, and owned by the process, are removed (regardless + * of the file descriptor that was used to obtain the lock). + * + * If fd is the last copy of a particular file descriptor the resources + * associated with it are freed; if the descriptor was the last reference + * to a file which has been removed using unlink(2) the file is deleted. + * + * Parameters: + * fd file descriptor to close + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately. + * + * Assumptions: + * + ****************************************************************************/ + int close(int fd) { FAR struct filelist *list; + FAR struct inode *inode; + int err; + + /* Did we get a valid file descriptor? */ + + if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS) + { + /* Close a socket descriptor */ +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 + if ((unsigned int)fd < (CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS)) + { + return net_close(fd); + } + else +#endif + { + err = EBADF; + goto errout; + } + } /* Get the thread-specific file list */ list = sched_getfiles(); if (!list) { - *get_errno_ptr() = EMFILE; - return ERROR; + err = EMFILE; + goto errout; } - if ((unsigned int)fd < CONFIG_NFILE_DESCRIPTORS) + /* If the file was properly opened, there should be an inode assigned */ + + inode = list->fl_files[fd].f_inode; + if (!inode) + { + err = EBADF; + goto errout; + } + + /* Close the driver or mountpoint. NOTES: (1) there is no + * exclusion mechanism here , the driver or mountpoint must be + * able to handle concurrent operations internally, (2) The driver + * may have been opened numerous times (for different file + * descriptors) and must also handle being closed numerous times. + * (3) for the case of the mountpoint, we depend on the close + * methods bing identical in signature and position in the operations + * vtable. + */ + + if (inode->u.i_ops && inode->u.i_ops->close) { - FAR struct inode *inode = list->fl_files[fd].f_inode; - if (inode) + /* Perform the close operation (by the driver) */ + + int ret = inode->u.i_ops->close(&list->fl_files[fd]); + if (ret < 0) { - int ret = OK; - - /* Close the driver or mountpoint. NOTES: (1) there is no - * exclusion mechanism here , the driver or mountpoint must be - * able to handle concurrent operations internally, (2) The driver - * may have been opened numerous times (for different file - * descriptors) and must also handle being closed numerous times. - * (3) for the case of the mountpoint, we depend on the close - * methods bing identical in signature and position in the operations - * vtable. - */ - - if (inode->u.i_ops && inode->u.i_ops->close) - { - /* Perform the close operation (by the driver) */ - - int status = inode->u.i_ops->close(&list->fl_files[fd]); - if (status < 0) - { - /* An error occurred while closing the driver */ - - *get_errno_ptr() = -status; - ret = ERROR; - } - } - - /* Release the file descriptor */ - - files_release(fd); - - /* Decrement the reference count on the inode. This may remove the inode and - * eliminate the name from the namespace - */ - - inode_release(inode); - return ret; + /* An error occurred while closing the driver */ + + err = -ret; + goto errout; } } - *get_errno_ptr() = EBADF; + /* Release the file descriptor */ + + files_release(fd); + + /* Decrement the reference count on the inode. This may remove the inode and + * eliminate the name from the namespace + */ + + inode_release(inode); + + return OK; + +errout: + *get_errno_ptr() = err; return ERROR; } diff --git a/fs/fs_write.c b/fs/fs_write.c index 60a6b829045f14b47dc4c93d517a11dfedb04159..7de7898f446a7380d87da7e27554f5fd4e9db6c9 100644 --- a/fs/fs_write.c +++ b/fs/fs_write.c @@ -47,48 +47,134 @@ #include <fcntl.h> #include <sched.h> #include <errno.h> + +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 +# include <sys/socket.h> +#endif + #include "fs_internal.h" /************************************************************ * Global Functions ************************************************************/ +/**************************************************************************** + * Function: send + * + * Description: + * write() writes up to nytes bytes to the file referenced by the file + * descriptor fd from the buffer starting at buf. + * + * Parameters: + * fd file descriptor (or socket descriptor) to write to + * buf Data to write + * nbytes Length of data to write + * + * Returned Value: + * On success, the number of bytes written are returned (zero indicates + * nothing was written). On error, -1 is returned, and errno is set appro‐ + * priately: + * + * EAGAIN + * Non-blocking I/O has been selected using O_NONBLOCK and the write + * would block. + * EBADF + * fd is not a valid file descriptor or is not open for writing. + * EFAULT + * buf is outside your accessible address space. + * EFBIG + * An attempt was made to write a file that exceeds the implementation + * defined maximum file size or the process' file size limit, or + * to write at a position past the maximum allowed offset. + * EINTR + * The call was interrupted by a signal before any data was written. + * EINVAL + * fd is attached to an object which is unsuitable for writing; or + * the file was opened with the O_DIRECT flag, and either the address + * specified in buf, the value specified in count, or the current + * file offset is not suitably aligned. + * EIO + * A low-level I/O error occurred while modifying the inode. + * ENOSPC + * The device containing the file referred to by fd has no room for + * the data. + * EPIPE + * fd is connected to a pipe or socket whose reading end is closed. + * When this happens the writing process will also receive a SIGPIPE + * signal. (Thus, the write return value is seen only if the program + * catches, blocks or ignores this signal.) + * + * Assumptions: + * + ****************************************************************************/ + int write(int fd, const void *buf, unsigned int nbytes) { FAR struct filelist *list; - int ret = EBADF; + FAR struct file *this_file; + FAR struct inode *inode; + int err; + int ret; + + /* Did we get a valid file descriptor? */ + + if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS) + { + /* Write to a socket descriptor is equivalent to send with flags == 0 */ + +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 + if ((unsigned int)fd < (CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS)) + { + return send(fd, buf, nbytes, 0); + } + else +#endif + { + err = EBADF; + goto errout; + } + } /* Get the thread-specific file list */ list = sched_getfiles(); if (!list) { - *get_errno_ptr() = EMFILE; - return ERROR; + err = EMFILE; + goto errout; } - /* Did we get a valid file descriptor? */ + /* Was this file opened for write access? */ - if ((unsigned int)fd < CONFIG_NFILE_DESCRIPTORS) + this_file = &list->fl_files[fd]; + if ((this_file->f_oflags & O_WROK) == 0) { - FAR struct file *this_file = &list->fl_files[fd]; - - /* Was this file opened for write access? */ + err = EBADF; + goto errout; + } - if ((this_file->f_oflags & O_WROK) != 0) - { - struct inode *inode = this_file->f_inode; + /* Is a driver registered? Does it support the write method? */ - /* Is a driver registered? Does it support the write method? */ + inode = this_file->f_inode; + if (!inode || !inode->u.i_ops && inode->u.i_ops->write) + { + err = EBADF; + goto errout; + } - if (inode && inode->u.i_ops && inode->u.i_ops->write) - { - /* Yes, then let it perform the write */ + /* Yes, then let the driver perform the write */ - ret = inode->u.i_ops->write(this_file, buf, nbytes); - } - } + ret = inode->u.i_ops->write(this_file, buf, nbytes); + if (ret < 0) + { + err = -ret; + goto errout; } + return ret; + +errout: + *get_errno_ptr() = err; + return ERROR; } diff --git a/include/net/uip/resolv.h b/include/net/uip/resolv.h index 3411966eae11a0c381923658c814a30982944fa9..9ab900978be10d1949a15f41c9635387609ab252 100644 --- a/include/net/uip/resolv.h +++ b/include/net/uip/resolv.h @@ -36,25 +36,31 @@ #include <sys/types.h> #include <net/uip/uipopt.h> -/* Callback function which is called when a hostname is found. - * - * This function must be implemented by the module that uses the DNS - * resolver. It is called when a hostname is found, or when a hostname - * was not found. - * - * name A pointer to the name that was looked up. \param - * ipaddr A pointer to a 4-byte array containing the IP address of the - * hostname, or NULL if the hostname could not be found. - */ - -extern void resolv_found(char *name, uint16 *ipaddr); +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif /* Functions. */ -extern void resolv_conf(uint16 *dnsserver); -extern uint16 *resolv_getserver(void); -extern void resolv_init(void); -extern uint16 *resolv_lookup(char *name); -extern void resolv_query(char *name); +EXTERN int resolv_init(void); + +#ifdef CONFIG_NET_IPv6 +EXTERN void resolv_conf(const struct sockaddr_in6 *dnsserver); +EXTERN void resolv_getserver(const struct sockaddr_in6 *dnsserver); +EXTERN int resolv_query(char *name, struct sockaddr_in6 *addr); +#else +EXTERN void resolv_conf(const struct sockaddr_in *dnsserver); +EXTERN void resolv_getserver(const struct sockaddr_in *dnsserver); +EXTERN int resolv_query(char *name, struct sockaddr_in *addr); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif #endif /* __UIP_RESOLV_H__ */ diff --git a/include/net/uip/uip.h b/include/net/uip/uip.h index 65a772e60556cab99b97dbc86a4f18ba174db527..b03233ed35cc81d654d92695abdab728ca73d3f9 100644 --- a/include/net/uip/uip.h +++ b/include/net/uip/uip.h @@ -48,8 +48,9 @@ * Included Files ****************************************************************************/ -#include <sys/types.h> #include <nuttx/config.h> +#include <sys/types.h> +#include <queue.h> #include <arpa/inet.h> #include <net/uip/uipopt.h> @@ -158,12 +159,11 @@ typedef uip_ip4addr_t uip_ipaddr_t; struct uip_conn { + dq_entry_t node; /* Implements a doubly linked list */ uip_ipaddr_t ripaddr; /* The IP address of the remote host. */ - uint16 lport; /* The local TCP port, in network byte order. */ uint16 rport; /* The local remote TCP port, in network byte order. */ - uint8 rcv_nxt[4]; /* The sequence number that we expect to receive next. */ uint8 snd_nxt[4]; /* The sequence number that was last sent by @@ -188,6 +188,7 @@ struct uip_conn */ void *private; + void (*callback)(void *private); }; #ifdef CONFIG_NET_UDP @@ -195,16 +196,16 @@ struct uip_conn struct uip_udp_conn { + dq_entry_t node; /* Implements a doubly linked list */ uip_ipaddr_t ripaddr; /* The IP address of the remote peer. */ uint16 lport; /* The local port number in network byte order. */ uint16 rport; /* The remote port number in network byte order. */ uint8 ttl; /* Default time-to-live. */ - /* Higher level logic can retain application specific information - * in the following: - */ + /* Defines the UDP callback */ void *private; + void (*callback)(void *private); }; #endif /* CONFIG_NET_UDP */ @@ -613,9 +614,6 @@ void uip_setipid(uint16 id); */ extern void uip_interrupt_event(void); -#ifdef CONFIG_NET_UDP -extern void uip_interrupt_udp_event(void); -#endif /* Find a free connection structure and allocate it for use. This is * normally something done by the implementation of the socket() API @@ -635,6 +633,34 @@ extern void uip_tcpfree(struct uip_conn *conn); extern void uip_udpfree(struct uip_udp_conn *conn); #endif +/* Bind a TCP connection to a local address */ + +#ifdef CONFIG_NET_IPv6 +extern int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in6 *addr); +#else +extern int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in *addr); +#endif + +/* This function implements the UIP specific parts of the standard + * TCP connect() operation: It connects to a remote host using TCP. + * + * This function is used to start a new connection to the specified + * port on the specied host. It uses the connection structure that was + * allocated by a preceding socket() call. It sets the connection to + * the SYN_SENT state and sets the retransmission timer to 0. This will + * cause a TCP SYN segment to be sent out the next time this connection + * is periodically processed, which usually is done within 0.5 seconds + * after the call to uip_tcpconnect(). + * + * This function is called from normal user level code. + */ + +#ifdef CONFIG_NET_IPv6 +extern int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in6 *addr); +#else +extern int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr); +#endif + /* Start listening to the specified port. * * Note: Since this function expects the port number in network byte @@ -848,51 +874,31 @@ void uip_send(const void *data, int len); #define uip_mss() (uip_conn->mss) -/* Set up a new UDP connection. - * - * This function sets up a new UDP connection. The function will +/* Bind a UDP connection to a local address */ + +#ifdef CONFIG_NET_IPv6 +extern int uip_udpbind(struct uip_udp_conn *conn, const struct sockaddr_in6 *addr); +#else +extern int uip_udpbind(struct uip_udp_conn *conn, const struct sockaddr_in *addr); +#endif + +/* This function sets up a new UDP connection. The function will * automatically allocate an unused local port for the new * connection. However, another port can be chosen by using the - * uip_udp_bind() call, after the uip_udp_new() function has been + * uip_udpbind() call, after the uip_udpconnect() function has been * called. * - * Example: + * This function is called as part of the implementation of sendto + * and recvfrom. * - * uip_ipaddr_t addr; - * struct uip_udp_conn *c; - * - * uip_ipaddr(&addr, 192,168,2,1); - * c = uip_udp_new(&addr, HTONS(12345)); - * if(c != NULL) { - * uip_udp_bind(c, HTONS(12344)); - * } - * - * ripaddr The IP address of the remote host. - * - * rport The remote port number in network byte order. - * - * Return: The uip_udp_conn structure for the new connection or NULL - * if no connection could be allocated. + * addr The address of the remote host. */ -struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, uint16 rport); - -/* Removed a UDP connection. - * - * conn A pointer to the uip_udp_conn structure for the connection. - */ - -#define uip_udp_remove(conn) (conn)->lport = 0 - -/* Bind a UDP connection to a local port. - * - * conn A pointer to the uip_udp_conn structure for the - * connection. - * - * port The local port number, in network byte order. - */ - -#define uip_udp_bind(conn, port) (conn)->lport = port +#ifdef CONFIG_NET_IPv6 +extern int uip_udpconnect(struct uip_udp_conn *conn, const struct sockaddr_in6 *addr); +#else +extern int uip_udpconnect(struct uip_udp_conn *conn, const struct sockaddr_in *addr); +#endif /* Send a UDP datagram of length len on the current connection. * diff --git a/include/nuttx/net.h b/include/nuttx/net.h index bb8ec8da311496e058d916851f6a8f763b9c2f55..ab6b4b93ae8d80017fe3c2ba0549d4978d50728c 100644 --- a/include/nuttx/net.h +++ b/include/nuttx/net.h @@ -106,6 +106,10 @@ EXTERN FAR struct socketlist *net_alloclist(void); EXTERN int net_addreflist(FAR struct socketlist *list); EXTERN int net_releaselist(FAR struct socketlist *list); +/* net-close.c ***************************************************************/ + +EXTERN int net_close(int sockfd); + #undef EXTERN #ifdef __cplusplus } diff --git a/include/sys/socket.h b/include/sys/socket.h index 589fafe13423f44b16bf443ea825ee25a7e31491..e1204e68a044c5bc3f657c0295d273650b9f2bad 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -93,6 +93,28 @@ #define SOCK_RDM 4 /* Provides a reliable datagram layer that does not guarantee ordering. */ #define SOCK_PACKET 5 /* Obsolete and should not be used in new programs */ + +/* Bits in the FLAGS argument to `send', `recv', et al. These are the bits + * recognized by Linus, not all are supported by NuttX. + */ + +#define MSG_OOB 0x0001 /* Process out-of-band data. */ +#define MSG_PEEK 0x0002 /* Peek at incoming messages. */ +#define MSG_DONTROUTE 0x0004 /* Don't use local routing. */ +#define MSG_CTRUNC 0x0008 /* Control data lost before delivery. */ +#define MSG_PROXY 0x0010 /* Supply or ask second address. */ +#define MSG_TRUNC 0x0020 +#define MSG_DONTWAIT 0x0040 /* Enable nonblocking IO. */ +#define MSG_EOR 0x0080 /* End of record. */ +#define MSG_WAITALL 0x0100 /* Wait for a full request. */ +#define MSG_FIN 0x0200 +#define MSG_SYN 0x0400 +#define MSG_CONFIRM 0x0800 /* Confirm path validity. */ +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue. */ +#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE. */ +#define MSG_MORE 0x8000 /* Sender will send more. */ + /**************************************************************************** * Type Definitions ****************************************************************************/ @@ -119,9 +141,15 @@ 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 ssize_t send(int s, const void *buf, size_t len, int flags); -EXTERN ssize_t sendto(int s, const void *buf, size_t len, int flags, +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 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); + + #undef EXTERN #if defined(__cplusplus) } diff --git a/net/Makefile b/net/Makefile index 25b5c46df37ffbdd9ea15de531f89fb2595579b0..089d45513f082f36665a4340d0013ecaf4636e57 100644 --- a/net/Makefile +++ b/net/Makefile @@ -1,4 +1,4 @@ -############################################################ +############################################################################ # Makefile # # Copyright (C) 2007 Gregory Nutt. All rights reserved. @@ -31,7 +31,7 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # -############################################################ +############################################################################ -include $(TOPDIR)/Make.defs CFLAGS += -I./uip @@ -40,7 +40,8 @@ MKDEP = $(TOPDIR)/tools/mkdeps.sh ifeq ($(CONFIG_NET),y) STD_ASRCS = -STD_CSRCS = socket.c bind.c connect.c net_sockets.c +STD_CSRCS = socket.c bind.c connect.c send.c sendto.c recv.c recvfrom.c \ + net_sockets.c net-close.c include uip/Make.defs endif diff --git a/net/bind.c b/net/bind.c index 332214d3355965d656e9b081ef3a1de8af0f16c7..97ff479b4e87da3e09b077e12d5f507724fcea19 100644 --- a/net/bind.c +++ b/net/bind.c @@ -61,7 +61,7 @@ * * Parameters: * sockfd Socket descriptor from socket - * my_addr Socket local address + * addr Socket local address * addrlen Length of my_addr * * Returned Value: @@ -91,6 +91,7 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) FAR const struct sockaddr_in *inaddr = (const struct sockaddr_in *)addr; #endif int err; + int ret; /* Verify that the sockfd corresponds to valid, allocated socket */ @@ -113,24 +114,32 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) } /* Perform the binding depending on the protocol type */ + switch (psock->s_type) { case SOCK_STREAM: -#warning Put TCP/IP binding logic here + ret = uip_tcpbind(psock->s_conn, inaddr); break; #ifdef CONFIG_NET_UDP case SOCK_DGRAM: -#warning Put UDP binding logic here + ret = uip_udpbind(psock->s_conn, inaddr); break; #endif default: - err = EBADF; + err = -EBADF; goto errout; } - err = ENOSYS; - /*return OK;*/ + /* Was the bind successful */ + + if (ret < 0) + { + err = -ret; + goto errout; + } + + return OK; errout: *get_errno_ptr() = err; diff --git a/net/connect.c b/net/connect.c index 2fcb8bc7912a879cb0e527f2074cac32a6d4cfc3..bbc112f19d86ea01b5b97e5f4d97bc2fcc1ba5c7 100644 --- a/net/connect.c +++ b/net/connect.c @@ -149,7 +149,8 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) goto errout; } - /* Perform the binding depending on the protocol type */ + /* Perform the connection depending on the protocol type */ + switch (psock->s_type) { case SOCK_STREAM: diff --git a/net/net-close.c b/net/net-close.c new file mode 100644 index 0000000000000000000000000000000000000000..294a4f7b7e78a9f8d50af1ecb9e74a25c7b85aba --- /dev/null +++ b/net/net-close.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * net/net-close.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * 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 NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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 <nuttx/config.h> +#ifdef CONFIG_NET + +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include "net_internal.h" + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: net_close + * + * Description: + * Performs the close operation on socket descriptors + * + * Parameters: + * sockfd Socket descriptor of socket + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately. + * + * Assumptions: + * + ****************************************************************************/ + +int net_close(int sockfd) +{ + FAR struct socket *psock = sockfd_socket(sockfd); + int err; + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (!psock || psock->s_crefs <= 0) + { + err = EBADF; + goto errout; + } + + /* Perform the close depending on the protocol type */ + + switch (psock->s_type) + { + case SOCK_STREAM: + uip_tcpfree(psock->s_conn); + break; + +#ifdef CONFIG_NET_UDP + case SOCK_DGRAM: + uip_udpfree(psock->s_conn); + break; +#endif + default: + err = -EBADF; + goto errout; + } + + /* Save the protocol type */ + + psock->s_type = 0; + psock->s_conn = NULL; + + return OK; + +errout: + *get_errno_ptr() = err; + return ERROR; +} + +#endif /* CONFIG_NET */ diff --git a/net/net_sockets.c b/net/net_sockets.c index d2be221a8758bf5a85dabefe7038aa6d01f37418..bed48ffe3ab4c9ee692fbe5b0b9b3691e8d1b1bb 100644 --- a/net/net_sockets.c +++ b/net/net_sockets.c @@ -251,4 +251,4 @@ FAR struct socket *sockfd_socket(int sockfd) } } return NULL; -} \ No newline at end of file +} diff --git a/net/recv.c b/net/recv.c new file mode 100644 index 0000000000000000000000000000000000000000..70cd4d995b479d2da281927156973ec547c21a5b --- /dev/null +++ b/net/recv.c @@ -0,0 +1,77 @@ +/**************************************************************************** + * net/recv.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * 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 NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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 <nuttx/config.h> +#ifdef CONFIG_NET + +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include "net_internal.h" + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: recv + * + * Description: + * The recv() call is identical to recvfrom() with a NULL from parameter. + * + * Parameters: + * sockfd Socket descriptor of socket + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * + * Returned Value: + * (see recvfrom) + * + * Assumptions: + * + ****************************************************************************/ + +ssize_t recv(int sockfd, void *buf, size_t len, int flags) +{ + return recvfrom(sockfd, buf, len, flags, NULL, 0); +} + +#endif /* CONFIG_NET */ diff --git a/net/recvfrom.c b/net/recvfrom.c new file mode 100644 index 0000000000000000000000000000000000000000..9632b5ca030f7580d7afa6d95ee0be05e6d3794a --- /dev/null +++ b/net/recvfrom.c @@ -0,0 +1,239 @@ +/**************************************************************************** + * net/recvfrom.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * 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 NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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 <nuttx/config.h> +#ifdef CONFIG_NET + +#include <sys/types.h> +#include <sys/socket.h> +#include <string.h> +#include <errno.h> +#include <arch/irq.h> + +#include "net_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct recvfrom_s +{ + sem_t rf_sem; + uint16 rf_buflen; + char * rf_buffer; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +void recvfrom_interrupt(void *private) +{ + struct recvfrom_s *pstate = (struct recvfrom_s *)private; + size_t recvlen; + + if (uip_newdata() && private) + { + /* Get the length of the data to return */ + if (uip_len > pstate-> rf_buflen) + { + recvlen = pstate-> rf_buflen; + } + else + { + recvlen = uip_len; + } + + /* Copy the appdate into the user data and send it */ + + memcpy(pstate->rf_buffer, uip_appdata, recvlen); + + /* Don't allow any furhter call backs. */ + + uip_conn->private = NULL; + uip_conn->callback = NULL; + + /* Wake up the waiting thread */ + + pstate->rf_buflen = recvlen; + sem_post(&pstate-> rf_sem); + } +} + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: recvfrom + * + * Description: + * recvfrom() receives messages from a socket, and may be used to receive + * data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument fromlen + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Parameters: + * sockfd Socket descriptor of socket + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN + * The socket is marked non-blocking and the receive operation would block, + * or a receive timeout had been set and the timeout expired before data + * was received. + * EBADF + * The argument sockfd is an invalid descriptor. + * ECONNREFUSED + * A remote host refused to allow the network connection (typically because + * it is not running the requested service). + * EFAULT + * The receive buffer pointer(s) point outside the process's address space. + * EINTR + * The receive was interrupted by delivery of a signal before any data were + * available. + * EINVAL + * Invalid argument passed. + * ENOMEM + * Could not allocate memory for recvmsg(). + * ENOTCONN + * The socket is associated with a connection-oriented protocol and has + * not been connected. + * ENOTSOCK + * The argument sockfd does not refer to a socket. + * + * Assumptions: + * + ****************************************************************************/ + +ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *from, + socklen_t *fromlen) +{ + FAR struct socket *psock; +#ifdef CONFIG_NET_IPv6 + FAR const struct sockaddr_in6 *infrom = (const struct sockaddr_in6 *)from; +#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 + int err; + int ret; + + /* Get the underlying socket structure */ + /* Verify that the sockfd corresponds to valid, allocated socket */ + + psock = sockfd_socket(sockfd); + if (!psock || psock->s_crefs <= 0) + { + err = EBADF; + goto errout; + } + + /* Perform the TCP/IP recv() operation */ + + if (psock->s_type == SOCK_STREAM) + { +#warning "TCP/IP recv not implemented" + err = ENOSYS; + goto errout; + } + + /* Perform the UDP recvfrom() 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)); + sem_init(&state. rf_sem, 0, 0); + state. rf_buflen = len; + state. rf_buffer = buf; + + /* Setup the UDP socket */ + + ret = uip_udpconnect(psock->s_conn, NULL); + if (ret < 0) + { + irqrestore(save); + err = -ret; + goto errout; + } + + /* 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; + irqrestore(save); + + sem_wait(&state. rf_sem); + sem_destroy(&state. rf_sem); + return state.rf_buflen; +#warning "Needs to return server address" +#else + err = ENOSYS; +#endif + +errout: + *get_errno_ptr() = err; + return ERROR; +} + +#endif /* CONFIG_NET */ diff --git a/net/send.c b/net/send.c new file mode 100644 index 0000000000000000000000000000000000000000..cb93995a7ccd8ea2df314854b9afb6acc0a538a9 --- /dev/null +++ b/net/send.c @@ -0,0 +1,150 @@ +/**************************************************************************** + * net/send.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * 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 NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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 <nuttx/config.h> +#ifdef CONFIG_NET + +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include "net_internal.h" + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: send + * + * Description: + * 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). + * + * Parameters: + * sockfd Socket descriptor of socket + * buf Data to send + * len Length of data to send + * flags Send flags + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN or EWOULDBLOCK + * The socket is marked non-blocking and the requested operation + * would block. + * EBADF + * An invalid descriptor was specified. + * ECONNRESET + * Connection reset by peer. + * EDESTADDRREQ + * The socket is not connection-mode, and no peer address is set. + * EFAULT + * An invalid user space address was specified for a parameter. + * EINTR + * A signal occurred before any data was transmitted. + * EINVAL + * Invalid argument passed. + * EISCONN + * The connection-mode socket was connected already but a recipient + * was specified. (Now either this error is returned, or the recipient + * specification is ignored.) + * EMSGSIZE + * The socket type requires that message be sent atomically, and the + * size of the message to be sent made this impossible. + * ENOBUFS + * The output queue for a network interface was full. This generally + * indicates that the interface has stopped sending, but may be + * caused by transient congestion. + * ENOMEM + * No memory available. + * ENOTCONN + * The socket is not connected, and no target has been given. + * ENOTSOCK + * The argument s is not a socket. + * EOPNOTSUPP + * Some bit in the flags argument is inappropriate for the socket + * type. + * EPIPE + * The local end has been shut down on a connection oriented socket. + * In this case the process will also receive a SIGPIPE unless + * MSG_NOSIGNAL is set. + * + * Assumptions: + * + ****************************************************************************/ + +ssize_t send(int sockfd, const void *buf, size_t len, int flags) +{ + FAR struct socket *psock = sockfd_socket(sockfd); + int err; + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (!psock || psock->s_crefs <= 0) + { + err = EBADF; + goto errout; + } + + /* If this is a connected socket, then return ENOTCONN */ + + if (psock->s_type != SOCK_STREAM) + { + err = ENOTCONN; + goto errout; + } + + /* Perform the TCP send operation */ + +#warning "send() not implemented" + err = ENOSYS; + +errout: + *get_errno_ptr() = ENOSYS; + return ERROR; + *get_errno_ptr() = ENOSYS; + return ERROR; +} + +#endif /* CONFIG_NET */ diff --git a/net/sendto.c b/net/sendto.c new file mode 100644 index 0000000000000000000000000000000000000000..86be9968bf6f8999b03426971b839c49ce3ca055 --- /dev/null +++ b/net/sendto.c @@ -0,0 +1,257 @@ +/**************************************************************************** + * net/sendto.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * 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 NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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 <nuttx/config.h> +#ifdef CONFIG_NET + +#include <sys/types.h> +#include <sys/socket.h> +#include <string.h> +#include <errno.h> +#include <arch/irq.h> + +#include "net_internal.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sendto_s +{ + sem_t st_sem; + uint16 st_buflen; + const char *st_buffer; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +void sendto_interrupt(void *private) +{ + struct sendto_s *pstate = (struct sendto_s *)private; + if (private) + { + /* Copy the user data into appdata and send it */ + + memcpy(uip_appdata, pstate->st_buffer, pstate->st_buflen); + uip_udp_send(pstate->st_buflen); + + /* Don't allow any furhter call backs. */ + + uip_conn->private = NULL; + uip_conn->callback = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->st_sem); + } +} + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: sendto + * + * 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 + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Parameters: + * sockfd Socket descriptor of socket + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately: + * + * EAGAIN or EWOULDBLOCK + * The socket is marked non-blocking and the requested operation + * would block. + * EBADF + * An invalid descriptor was specified. + * ECONNRESET + * Connection reset by peer. + * EDESTADDRREQ + * The socket is not connection-mode, and no peer address is set. + * EFAULT + * An invalid user space address was specified for a parameter. + * EINTR + * A signal occurred before any data was transmitted. + * EINVAL + * Invalid argument passed. + * EISCONN + * The connection-mode socket was connected already but a recipient + * was specified. (Now either this error is returned, or the recipient + * specification is ignored.) + * EMSGSIZE + * The socket type requires that message be sent atomically, and the + * size of the message to be sent made this impossible. + * ENOBUFS + * The output queue for a network interface was full. This generally + * indicates that the interface has stopped sending, but may be + * caused by transient congestion. + * ENOMEM + * No memory available. + * ENOTCONN + * The socket is not connected, and no target has been given. + * ENOTSOCK + * The argument s is not a socket. + * EOPNOTSUPP + * Some bit in the flags argument is inappropriate for the socket + * type. + * EPIPE + * The local end has been shut down on a connection oriented socket. + * In this case the process will also receive a SIGPIPE unless + * MSG_NOSIGNAL is set. + * + * Assumptions: + * + ****************************************************************************/ + +ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + FAR struct socket *psock; +#ifdef CONFIG_NET_IPv6 + FAR const struct sockaddr_in6 *into = (const struct sockaddr_in6 *)to; +#else + FAR const struct sockaddr_in *into = (const struct sockaddr_in *)to; +#endif +#ifdef CONFIG_NET_UDP + struct uip_udp_conn *udp_conn; + struct sendto_s state; + irqstate_t save; +#endif + int err; + int ret; + + /* If to is NULL or tolen is zero, then this function is same as send */ + + if (!to || !tolen) + { + return send(sockfd, buf, len, flags); + } + + /* Verify that a valid address has been provided */ + +#ifdef CONFIG_NET_IPv6 + if (to->sa_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6)) +#else + if (to->sa_family != AF_INET || tolen < sizeof(struct sockaddr_in)) +#endif + { + err = EBADF; + goto errout; + } + + /* Get the underlying socket structure */ + /* Verify that the sockfd corresponds to valid, allocated socket */ + + psock = sockfd_socket(sockfd); + if (!psock || psock->s_crefs <= 0) + { + err = EBADF; + goto errout; + } + + /* If this is a connected socket, then return EISCONN */ + + if (psock->s_type != SOCK_DGRAM) + { + err = EISCONN; + goto errout; + } + + /* Perform the UDP sendto 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 sendto_s)); + sem_init(&state.st_sem, 0, 0); + state.st_buflen = len; + state.st_buffer = buf; + + /* Setup the UDP socket */ + + ret = uip_udpconnect(psock->s_conn, into); + if (ret < 0) + { + irqrestore(save); + err = -ret; + goto errout; + } + + /* Set up the callback in the connection */ + + udp_conn = (struct uip_udp_conn *)psock->s_conn; + udp_conn->private = (void*)&state; + udp_conn->callback = sendto_interrupt; + irqrestore(save); + + sem_wait(&state.st_sem); + sem_destroy(&state.st_sem); + return len; +#else + err = ENOSYS; +#endif + +errout: + *get_errno_ptr() = err; + return ERROR; +} + +#endif /* CONFIG_NET */ diff --git a/net/socket.c b/net/socket.c index ad3ef1e9279580e2d67c605d09f2216edfe14ae8..43d4645fd28fe66a2a9bffc666ea9454fce93719 100644 --- a/net/socket.c +++ b/net/socket.c @@ -135,10 +135,27 @@ int socket(int domain, int type, int protocol) /* Save the protocol type */ psock->s_type = type; + psock->s_conn = NULL; - /* Allocate a TCP connection structure */ + /* Allocate the appropriate connection structure */ + + switch (type) + { + case SOCK_STREAM: + psock->s_conn = uip_tcpalloc(); + break; + +#ifdef CONFIG_NET_UDP + case SOCK_DGRAM: + psock->s_conn = uip_udpalloc(); + break; +#endif + default: + break; + } + + /* Did we succesfully allocate some kind of connection structure? */ - psock->s_conn = uip_tcpalloc(); if (!psock->s_conn) { /* Failed to reserve a connection structure */ diff --git a/net/uip/uip-internal.h b/net/uip/uip-internal.h index 0f47fbc52d5403f36373ae1d5256c01bf6e60133..f8613c63a0eca76ad06a881078f2cebfced738d1 100644 --- a/net/uip/uip-internal.h +++ b/net/uip/uip-internal.h @@ -57,10 +57,6 @@ * Public Data ****************************************************************************/ -/* g_tcp_sequence[] is used to generate TCP sequence numbers */ - -extern uint8 g_tcp_sequence[4]; - extern const uip_ipaddr_t all_ones_addr; extern const uip_ipaddr_t all_zeroes_addr; @@ -79,6 +75,7 @@ extern "C" { EXTERN void uip_tcpinit(void); EXTERN struct uip_conn *uip_tcpactive(struct uip_tcpip_hdr *buf); +EXTERN struct uip_conn *uip_tcplistener(struct uip_tcpip_hdr *buf); EXTERN void uip_tcpnextsequence(void); /* Defined in uip_udpconn.c *************************************************/ diff --git a/net/uip/uip-tcpconn.c b/net/uip/uip-tcpconn.c index 2c6d0cd023466b05adf272ed672c8315eb691254..9d1380f6bc9eb645ee4324142572e80a26df1932 100644 --- a/net/uip/uip-tcpconn.c +++ b/net/uip/uip-tcpconn.c @@ -62,10 +62,6 @@ * Public Data ****************************************************************************/ -/* g_tcp_sequence[] is used to generate TCP sequence numbers */ - -uint8 g_tcp_sequence[4]; - /**************************************************************************** * Private Data ****************************************************************************/ @@ -74,17 +70,34 @@ uint8 g_tcp_sequence[4]; static struct uip_conn g_tcp_connections[UIP_CONNS]; +/* A list of all free TCP connections */ + +static dq_queue_t g_free_tcp_connections; + +/* A list of all connected TCP connections */ + +static dq_queue_t g_active_tcp_connections; + /* Last port used by a TCP connection connection. */ static uint16 g_last_tcp_port; +/* g_tcp_sequence[] is used to generate TCP sequence numbers */ + +static uint8 g_tcp_sequence[4]; + /**************************************************************************** * Private Functions ****************************************************************************/ -/* Given a port number, find the socket bound to the port number. - * Primary use: to determine if a port number is available. - */ +/**************************************************************************** + * Name: uip_find_conn() + * + * Description: + * Given a port number, find the socket bound to the port number. + * Primary use: to determine if a port number is available. + * + ****************************************************************************/ static struct uip_conn *uip_find_conn(uint16 portno) { @@ -118,16 +131,27 @@ static struct uip_conn *uip_find_conn(uint16 portno) * * Description: * Initialize the TCP/IP connection structures. Called only once and only - * from the UIP layer. + * from the UIP layer at startup in normal user mode. * ****************************************************************************/ void uip_tcpinit(void) { int i; + + /* Initialize the queues */ + + dq_init(&g_free_tcp_connections); + dq_init(&g_active_tcp_connections); + + /* Now initialize each connection structure */ + for (i = 0; i < UIP_CONNS; i++) { + /* Mark the connection closed and move it to the free list */ + g_tcp_connections[i].tcpstateflags = UIP_CLOSED; + dq_addlast(&g_tcp_connections[i].node, &g_free_tcp_connections); } g_last_tcp_port = 1024; @@ -146,60 +170,67 @@ void uip_tcpinit(void) struct uip_conn *uip_tcpalloc(void) { -#if 0 /* Revisit */ - struct uip_conn *oldest = NULL; -#endif + struct uip_conn *conn; irqstate_t flags; - unsigned int i; /* Because this routine is called from both interrupt level and * and from user level, we have not option but to disable interrupts - * while accessing g_tcp_connections[]; + * while accessing g_free_tcp_connections[]; */ flags = irqsave(); - /* Check if there are any available connections. */ - - for (i = 0; i < UIP_CONNS; i++) - { - /* First, check if any connections structures are marked as - * CLOSED in the table of pre-allocated connection structures. - */ - - if (g_tcp_connections[i].tcpstateflags == UIP_CLOSED) - { - /* We found an unused structure. Mark as allocated, but not - * initialized. - */ + /* Return the entry from the head of the free list */ - memset(&g_tcp_connections[i], 0, sizeof(struct uip_conn)); - g_tcp_connections[i].tcpstateflags = UIP_ALLOCATED; - - irqrestore(flags); - return &g_tcp_connections[i]; - } + conn = (struct uip_conn *)dq_remfirst(&g_free_tcp_connections); #if 0 /* Revisit */ + /* Is the free list empty? */ + + if (!conn) + { /* As a fallback, check for connection structures in the TIME_WAIT * state. If no CLOSED connections are found, then take the oldest */ - if (g_tcp_connections[i].tcpstateflags == UIP_TIME_WAIT) + struct uip_conn *tmp = g_active_tcp_connections.head; + while (tmp) { - if (!oldest || g_tcp_connections[i].timer > oldest->timer) + /* Is this connectin in the UIP_TIME_WAIT state? */ + + if (tmp->tcpstateflags == UIP_TIME_WAIT) { - oldest = &g_tcp_connections[i]; + /* Is it the oldest one we have seen so far? */ + + if (!conn || tmp->timer > conn->timer) + { + /* Yes.. remember it */ + + conn = tmp; + } } + + /* Look at the next active connection */ + + tmp = tmp->node.flink; } + + /* If we found one, remove it from the active connection list */ + + dq_rem(&conn->node, &g_active_tcp_connections); } - return oldest; -#else - } +#endif irqrestore(flags); - return NULL; -#endif + + /* Mark the connection allocated */ + + if (conn) + { + conn->tcpstateflags = UIP_ALLOCATED; + } + + return conn; } /**************************************************************************** @@ -213,9 +244,31 @@ struct uip_conn *uip_tcpalloc(void) void uip_tcpfree(struct uip_conn *conn) { - /* this action is atomic and should require no special protetion */ + irqstate_t flags; + + /* Because g_free_tcp_connections is accessed from user level and interrupt + * level, code, it is necessary to keep interrupts disabled during this + * operation. + */ + + flags = irqsave(); + + /* UIP_ALLOCATED means that that the connection is not in the active list + * yet. + */ + + if (conn->tcpstateflags != UIP_ALLOCATED) + { + /* Remove the connection from the active list */ + + dq_rem(&conn->node, &g_free_tcp_connections); + } + + /* Mark the connection available and put it into the free list */ conn->tcpstateflags = UIP_CLOSED; + dq_addlast(&conn->node, &g_free_tcp_connections); + irqrestore(flags); } /**************************************************************************** @@ -232,8 +285,8 @@ void uip_tcpfree(struct uip_conn *conn) struct uip_conn *uip_tcpactive(struct uip_tcpip_hdr *buf) { - struct uip_conn *conn; - for (conn = g_tcp_connections; conn <= &g_tcp_connections[UIP_CONNS - 1]; conn++) + struct uip_conn *conn = (struct uip_conn *)g_active_tcp_connections.head; + while (conn) { /* Find an open connection matching the tcp input */ @@ -241,15 +294,64 @@ struct uip_conn *uip_tcpactive(struct uip_tcpip_hdr *buf) buf->destport == conn->lport && buf->srcport == conn->rport && uip_ipaddr_cmp(buf->srcipaddr, conn->ripaddr)) { - /* Matching connection found.. return a reference to it */ + /* Matching connection found.. break out of the loop and return a + * reference to it. + */ - return conn; + break; } + + /* Look at the next active connection */ + + conn = (struct uip_conn *)conn->node.flink; } - /* No match found */ + return conn; +} - return NULL; +/**************************************************************************** + * Name: uip_tcpactive() + * + * Description: + * Called when uip_interupt matches the incoming packet with a connection + * in LISTEN. In that case, this function will create a new connection and + * initialize it to send a SYNACK in return. + * + * Assumptions: + * This function is called from UIP logic at interrupt level + * + ****************************************************************************/ + +struct uip_conn *uip_tcplistener(struct uip_tcpip_hdr *buf) +{ + struct uip_conn *conn = uip_tcpalloc(); + if (conn) + { + /* Fill in the necessary fields for the new connection. */ + + conn->rto = conn->timer = UIP_RTO; + conn->sa = 0; + conn->sv = 4; + conn->nrtx = 0; + conn->lport = buf->destport; + conn->rport = buf->srcport; + uip_ipaddr_copy(conn->ripaddr, buf->srcipaddr); + conn->tcpstateflags = UIP_SYN_RCVD; + + conn->snd_nxt[0] = g_tcp_sequence[0]; + conn->snd_nxt[1] = g_tcp_sequence[1]; + conn->snd_nxt[2] = g_tcp_sequence[2]; + conn->snd_nxt[3] = g_tcp_sequence[3]; + conn->len = 1; + + /* rcv_nxt should be the seqno from the incoming packet + 1. */ + + conn->rcv_nxt[3] = buf->seqno[3]; + conn->rcv_nxt[2] = buf->seqno[2]; + conn->rcv_nxt[1] = buf->seqno[1]; + conn->rcv_nxt[0] = buf->seqno[0]; + } + return conn; } /**************************************************************************** @@ -345,13 +447,24 @@ int uip_tcpbind(struct uip_conn *conn, const struct sockaddr_in *addr) ****************************************************************************/ #ifdef CONFIG_NET_IPv6 -int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in6 *addr ) +int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in6 *addr) #else -int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr ) +int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr) #endif { + irqstate_t flags; uint16 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 + * list. + */ + + if (!conn || conn->tcpstateflags != UIP_ALLOCATED) + { + return -EISCONN; + } + /* If the TCP port has not alread been bound to a local port, then select * one now. */ @@ -407,6 +520,17 @@ int uip_tcpconnect(struct uip_conn *conn, const struct sockaddr_in *addr ) /* The sockaddr address is 32-bits in network order. */ uip_ipaddr_copy(&conn->ripaddr, addr->sin_addr.s_addr); + + /* And, finally, put the connection structure into the active + * list. Because g_active_tcp_connections is accessed from user level and + * interrupt level, code, it is necessary to keep interrupts disabled during + * this operation. + */ + + flags = irqsave(); + dq_addlast(&conn->node, &g_active_tcp_connections); + irqrestore(flags); + return OK; } diff --git a/net/uip/uip-udpconn.c b/net/uip/uip-udpconn.c index 1738e5d5a45d2897e7cb2520e289ec35a0583a13..24739bee1dfd7f2d0b3c075e4290a5137c7d6205 100644 --- a/net/uip/uip-udpconn.c +++ b/net/uip/uip-udpconn.c @@ -1,4 +1,4 @@ -/************************************************************ +/**************************************************************************** * uip-udpconn.c * * Copyright (C) 2007 Gregory Nutt. All rights reserved. @@ -34,21 +34,23 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Compilation Switches - ************************************************************/ + ****************************************************************************/ -/************************************************************ +/**************************************************************************** * Included Files - ************************************************************/ + ****************************************************************************/ #include <nuttx/config.h> #if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) #include <sys/types.h> #include <string.h> +#include <semaphore.h> +#include <assert.h> #include <errno.h> #include <arch/irq.h> @@ -58,43 +60,93 @@ #include "uip-internal.h" -/************************************************************ +/**************************************************************************** * Private Data - ************************************************************/ + ****************************************************************************/ /* The array containing all uIP UDP connections. */ -struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +struct uip_udp_conn g_udp_connections[UIP_UDP_CONNS]; + +/* A list of all free UDP connections */ + +static dq_queue_t g_free_udp_connections; +static sem_t g_free_sem; + +/* A list of all allocated UDP connections */ + +static dq_queue_t g_active_udp_connections; /* Last port used by a UDP connection connection. */ static uint16 g_last_udp_port; -/************************************************************ +/**************************************************************************** * Private Functions - ************************************************************/ + ****************************************************************************/ -#ifdef CONFIG_NET_UDP -struct uip_udp_conn *uip_find_udp_conn( uint16 portno ) +/**************************************************************************** + * Name: _uip_semtake() and _uip_semgive() + * + * Description: + * Take/give semaphore + * + ****************************************************************************/ + +static inline void _uip_semtake(sem_t *sem) +{ + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(sem) != 0) + { + /* The only case that an error should occr here is if + * the wait was awakened by a signal. + */ + + ASSERT(*get_errno_ptr() == EINTR); + } +} + +#define _uip_semgive(sem) sem_post(sem) + +/**************************************************************************** + * Name: uip_find_conn() + * + * Description: + * Find the UDP connection that uses this local port number. Called only + * from user, non-interrupt level logic. + * + ****************************************************************************/ + +struct uip_udp_conn *uip_find_conn( uint16 portno ) { struct uip_udp_conn *conn; - int i; + uint16 nlastport = htons(g_last_udp_port); + irqstate_t flags; - for (i = 0; i < UIP_UDP_CONNS; i++) + /* Now search each active connection structure. This list is modifiable + * from interrupt level, we we must diable interrupts to access it safely. + */ + + flags = irqsave(); + conn = (struct uip_udp_conn *)g_active_udp_connections.head; + while (conn) { - if (uip_udp_conns[i].lport == htons(g_last_udp_port)) + if (conn->lport == nlastport) { - return conn; + break; } + + conn = (struct uip_udp_conn *)conn->node.flink; } - return NULL; + irqrestore(flags); + return conn; } -#endif /* CONFIG_NET_UDP */ -/************************************************************ +/**************************************************************************** * Public Functions - ************************************************************/ + ****************************************************************************/ /**************************************************************************** * Name: uip_udpinit() @@ -108,9 +160,19 @@ struct uip_udp_conn *uip_find_udp_conn( uint16 portno ) void uip_udpinit(void) { int i; + + /* Initialize the queues */ + + dq_init(&g_free_udp_connections); + dq_init(&g_active_udp_connections); + sem_init(&g_free_sem, 0, 1); + for (i = 0; i < UIP_UDP_CONNS; i++) { - uip_udp_conns[i].lport = 0; + /* Mark the connection closed and move it to the free list */ + + g_udp_connections[i].lport = 0; + dq_addlast(&g_udp_connections[i].node, &g_free_udp_connections); } g_last_udp_port = 1024; @@ -120,15 +182,28 @@ void uip_udpinit(void) * Name: uip_udpalloc() * * Description: - * Find a free UDP connection structure and allocate it for use. This is - * normally something done by the implementation of the socket() API. + * Alloc a new, uninitialized UDP connection structure. * ****************************************************************************/ struct uip_udp_conn *uip_udpalloc(void) { -#warning "Need to implement allocation logic" - return NULL; + struct uip_udp_conn *conn; + + /* The free list is only accessed from user, non-interrupt level and + * is protected by a semaphore (that behaves like a mutex). + */ + + _uip_semtake(&g_free_sem); + conn = (struct uip_udp_conn *)dq_remfirst(&g_free_udp_connections); + if (conn) + { + /* Make sure that the connectin is marked as uninitialized */ + + conn->lport = 0; + } + _uip_semgive(&g_free_sem); + return conn; } /**************************************************************************** @@ -142,7 +217,27 @@ struct uip_udp_conn *uip_udpalloc(void) void uip_udpfree(struct uip_udp_conn *conn) { -#warning "Need to implement release logic" + irqstate_t flags; + + /* The active list is accessed from the interrupt level and me must be + * certain that no interrupts occur while the active list is modified. + */ + + flags = irqsave(); + if (conn->lport != 0) + { + dq_rem(&conn->node, &g_active_udp_connections); + } + irqrestore(flags); + + /* The free list is only accessed from user, non-interrupt level and + * is protected by a semaphore (that behaves like a mutex). + */ + + _uip_semtake(&g_free_sem); + conn->lport = 0; + dq_addlast(&conn->node, &g_free_udp_connections); + _uip_semgive(&g_free_sem); } /**************************************************************************** @@ -159,8 +254,8 @@ void uip_udpfree(struct uip_udp_conn *conn) struct uip_udp_conn *uip_udpactive(struct uip_udpip_hdr *buf) { - struct uip_udp_conn *conn; - for (conn = &uip_udp_conns[0]; conn < &uip_udp_conns[UIP_UDP_CONNS]; conn++) + struct uip_udp_conn *conn = (struct uip_udp_conn *)g_active_udp_connections.head; + while (conn) { /* If the local UDP port is non-zero, the connection is considered * to be used. If so, the local port number is checked against the @@ -179,11 +274,13 @@ struct uip_udp_conn *uip_udpactive(struct uip_udpip_hdr *buf) { /* Matching connection found.. return a reference to it */ - return conn; + break; } - } - /* No match found */ + /* Look at the next active connection */ + + conn = (struct uip_udp_conn *)conn->node.flink; + } return NULL; } @@ -207,63 +304,26 @@ struct uip_udp_conn *uip_udpactive(struct uip_udpip_hdr *buf) void uip_udppoll(unsigned int conn) { - uip_udp_conn = &uip_udp_conns[conn]; + uip_udp_conn = &g_udp_connections[conn]; uip_interrupt(UIP_UDP_TIMER); } -/**************************************************************************** - * Name: uip_tcpbind() - * - * Description: - * This function implements the UIP specific parts of the standard TCP - * bind() operation. - * - * Assumptions: - * This function is called from normal user level code. - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IPv6 -int uip_udpbind(struct uip_udp_conn *conn, const struct sockaddr_in6 *addr) -#else -int uip_udpbind(struct uip_udp_conn *conn, const struct sockaddr_in *addr) -#endif -{ -#warning "Need to implement bind logic" - return -ENOSYS; -} - -/* Set up a new UDP connection. - * - * This function sets up a new UDP connection. The function will +/* This function sets up a new UDP connection. The function will * automatically allocate an unused local port for the new * connection. However, another port can be chosen by using the - * uip_udp_bind() call, after the uip_udp_new() function has been + * uip_udpbind() call, after the uip_udpconnect() function has been * called. * - * Example: - * - * uip_ipaddr_t addr; - * struct uip_udp_conn *c; - * - * uip_ipaddr(&addr, 192,168,2,1); - * c = uip_udp_new(&addr, HTONS(12345)); - * if(c != NULL) { - * uip_udp_bind(c, HTONS(12344)); - * } - * - * ripaddr The IP address of the remote host. - * - * rport The remote port number in network byte order. - * - * Return: The uip_udp_conn structure for the new connection or NULL - * if no connection could be allocated. + * addr The address of the remote host. */ -struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, uint16 rport) +#ifdef CONFIG_NET_IPv6 +int uip_udpconnect(struct uip_udp_conn *conn, const struct sockaddr_in6 *addr) +#else +int uip_udpconnect(struct uip_udp_conn *conn, const struct sockaddr_in *addr) +#endif { - struct uip_udp_conn *conn; - int i; + irqstate_t flags; /* Find an unused local port number. Loop until we find a valid listen port * number that is not being used by any other connection. @@ -283,42 +343,32 @@ struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, uint16 rport) g_last_udp_port = 4096; } } - while (uip_find_udp_conn(g_last_udp_port)); - - /* Now find an available UDP connection structure */ - - conn = 0; - for (i = 0; i < UIP_UDP_CONNS; i++) - { - if (uip_udp_conns[i].lport == 0) - { - conn = &uip_udp_conns[i]; - break; - } - } - - /* Return an error if no connection is available */ - - if (conn == 0) - { - return 0; - } + while (uip_find_conn(g_last_udp_port)); /* Initialize and return the connection structure, bind it to the port number */ conn->lport = HTONS(g_last_udp_port); - conn->rport = rport; - if (ripaddr == NULL) + if (addr) { - memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t)); + conn->rport = addr->sin_port; + uip_ipaddr_copy(&conn->ripaddr, &addr->sin_addr.s_addr); } else { - uip_ipaddr_copy(&conn->ripaddr, ripaddr); - } + conn->rport = 0; + uip_ipaddr_copy(&conn->ripaddr, &all_zeroes_addr); + } + conn->ttl = UIP_TTL; + + /* Now add the connection structure to the active connectionlist. This list + * is modifiable from interrupt level, we we must diable interrupts to + * access it safely. + */ - conn->ttl = UIP_TTL; + flags = irqsave(); + dq_addlast(&conn->node, &g_active_udp_connections); + irqrestore(flags); return conn; } diff --git a/net/uip/uip.c b/net/uip/uip.c index e45e0e560fa15f73c475f230197802ff4674386b..44403af84876f8d12c8d7977b49d350540d02d11 100644 --- a/net/uip/uip.c +++ b/net/uip/uip.c @@ -17,6 +17,7 @@ * 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 @@ -587,6 +588,18 @@ static void uip_add_rcv_nxt(uint16 n) uip_conn->rcv_nxt[3] = uip_acc32[3]; } +static uip_udp_callback(void) +{ + /* Some sanity checking */ + + if (uip_udp_conn && uip_udp_conn->callback) + { + /* Perform the callback */ + + uip_udp_conn->callback(uip_udp_conn->private); + } +} + void uip_interrupt(uint8 flag) { register struct uip_conn *uip_connr = uip_conn; @@ -759,7 +772,7 @@ void uip_interrupt(uint8 flag) uip_len = uip_slen = 0; uip_flags = UIP_POLL; uip_event_signal(); - uip_interrupt_udp_event(); + up_udp_callback(); goto udp_send; } else @@ -1099,7 +1112,7 @@ void uip_interrupt(uint8 flag) uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; uip_slen = 0; uip_event_signal(); - uip_interrupt_udp_event(); + up_udp_callback(); udp_send: if (uip_slen == 0) @@ -1256,7 +1269,7 @@ found_listen: /* First allocate a new connection structure */ - uip_connr = uip_tcpalloc(); + uip_connr = uip_tcplistener(BUF); if (!uip_connr) { /* All connections are used already, we drop packet and hope that @@ -1268,33 +1281,12 @@ found_listen: UIP_LOG("tcp: found no unused connections."); goto drop; } - uip_conn = uip_connr; - /* Fill in the necessary fields for the new connection. */ - - uip_connr->rto = uip_connr->timer = UIP_RTO; - uip_connr->sa = 0; - uip_connr->sv = 4; - uip_connr->nrtx = 0; - uip_connr->lport = BUF->destport; - uip_connr->rport = BUF->srcport; - uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr); - uip_connr->tcpstateflags = UIP_SYN_RCVD; - - uip_connr->snd_nxt[0] = g_tcp_sequence[0]; - uip_connr->snd_nxt[1] = g_tcp_sequence[1]; - uip_connr->snd_nxt[2] = g_tcp_sequence[2]; - uip_connr->snd_nxt[3] = g_tcp_sequence[3]; - uip_connr->len = 1; - - /* rcv_nxt should be the seqno from the incoming packet + 1. */ - uip_connr->rcv_nxt[3] = BUF->seqno[3]; - uip_connr->rcv_nxt[2] = BUF->seqno[2]; - uip_connr->rcv_nxt[1] = BUF->seqno[1]; - uip_connr->rcv_nxt[0] = BUF->seqno[0]; uip_add_rcv_nxt(1); + uip_conn = uip_connr; /* Parse the TCP MSS option, if present. */ + if ((BUF->tcpoffset & 0xf0) > 0x50) { for (c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) @@ -1338,7 +1330,7 @@ found_listen: } /* Our response will be a SYNACK. */ - tcp_send_synack: +tcp_send_synack: BUF->flags = TCP_ACK; tcp_send_syn: diff --git a/netutils/dhcpc/dhcpc.c b/netutils/dhcpc/dhcpc.c index 1fc64cf1b234016c69a5b244d82c4e8884e11934..a2a233e937d7014c547bc23ac68970d7881c29e3 100644 --- a/netutils/dhcpc/dhcpc.c +++ b/netutils/dhcpc/dhcpc.c @@ -402,6 +402,7 @@ void dhcpc_close(void *handle) void uip_interrupt_udp_event(void) { +#error OBSOLETE if (gpdhcpc) { sem_post(&gpdhcpc->sem); diff --git a/netutils/resolv/resolv.c b/netutils/resolv/resolv.c index f149c6a8028f2c96ecf9e74bff52c9a8f127fd3b..512f1ac5999c0f79601364b3bb634e411962d6e0 100644 --- a/netutils/resolv/resolv.c +++ b/netutils/resolv/resolv.c @@ -54,7 +54,7 @@ #include <string.h> #include <debug.h> -#include <net/uip/uip.h> +#include <sys/socket.h> #include <net/uip/resolv.h> /**************************************************************************** @@ -87,11 +87,8 @@ #define DNS_FLAG2_ERR_NONE 0x00 #define DNS_FLAG2_ERR_NAME 0x03 -#define STATE_UNUSED 0 -#define STATE_NEW 1 -#define STATE_ASKING 2 -#define STATE_DONE 3 -#define STATE_ERROR 4 +#define SEND_BUFFER_SIZE 64 +#define RECV_BUFFER_SIZE 64 /**************************************************************************** * Private Types @@ -140,8 +137,13 @@ struct namemap ****************************************************************************/ static struct namemap names[RESOLV_ENTRIES]; -static uint8 seqno; -static struct uip_udp_conn *resolv_conn = NULL; +static uint8 gseqno; +static int g_sockfd = -1; +#ifdef CONFIG_NET_IPv6 +static struct sockaddr_in6 gdnsserver; +#else +static struct sockaddr_in gdnsserver; +#endif /**************************************************************************** * Private Functions @@ -171,90 +173,76 @@ static unsigned char *parse_name(unsigned char *query) * not yet been queried and, if so, sends out a query. */ -static void check_entries(void) +static int send_query(const char name) { register struct dns_hdr *hdr; - char *query, *nptr, *nameptr; + char *query; + char *nptr; + char **nameptr; static uint8 i; static uint8 n; - register struct namemap *namemapptr; + uint8 state = NEW_STATE; + uint8 seqno = gsegno++; + uint8 err; + static unsigned char endquery[] = {0,0,1,0,1}; + char buffer[SEND_BUFFER_SIZE]; - for(i = 0; i < RESOLV_ENTRIES; ++i) - { - namemapptr = &names[i]; - if (namemapptr->state == STATE_NEW || - namemapptr->state == STATE_ASKING) - { - if (namemapptr->state == STATE_ASKING) - { - if (--namemapptr->tmr == 0) - { - if (++namemapptr->retries == MAX_RETRIES) - { - namemapptr->state = STATE_ERROR; - resolv_found(namemapptr->name, NULL); - continue; - } - namemapptr->tmr = namemapptr->retries; - } - else - { - /* Its timer has not run out, so we move on to next entry. */ - continue; - } - } - else - { - namemapptr->state = STATE_ASKING; - namemapptr->tmr = 1; - namemapptr->retries = 0; - } - hdr = (struct dns_hdr *)uip_appdata; - memset(hdr, 0, sizeof(struct dns_hdr)); - hdr->id = htons(i); - hdr->flags1 = DNS_FLAG1_RD; - hdr->numquestions = HTONS(1); - query = (char *)uip_appdata + 12; - nameptr = namemapptr->name; - --nameptr; - - /* Convert hostname into suitable query format. */ - do - { - ++nameptr; - nptr = query; - ++query; - for (n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) - { - *query = *nameptr; - ++query; - ++n; - } - *nptr = n; - } - while(*nameptr != 0); - { - static unsigned char endquery[] = {0,0,1,0,1}; - memcpy(query, endquery, 5); - } - uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata)); - break; - } - } + hdr = (struct dns_hdr*)buffer; + memset(hdr, 0, sizeof(struct dns_hdr)); + hdr->id = htons(seqno); + hdr->flags1 = DNS_FLAG1_RD; + hdr->numquestions = HTONS(1); + query = buffer + 12; + + /* Convert hostname into suitable query format. */ + + nameptr = name - 1; + do + { + nameptr++; + nptr = query++; + for (n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) + { + *query = *nameptr; + ++query; + ++n; + } + *nptr = n; + } + while(*nameptr != 0); + + memcpy(query, endquery, 5); + return sendto(gsockfd, buffer, query + 5 - buffer); } /* Called when new UDP data arrives */ -static void newdata(void) +#ifdef CONFIG_NET_IPv6 +#error "Not implemented +#else +int recv_response(struct sockaddr_in *addr) +#endif + +hdr->flags2 & DNS_FLAG2_ERR_MASKstatic int (void) { unsigned char *nameptr; + char buffer[RECV_BUFFER_SIZE]; struct dns_answer *ans; struct dns_hdr *hdr; - static uint8 nquestions, nanswers; - static uint8 i; - register struct namemap *namemapptr; + uint8 nquestions; + uint8 nanswers; + uint8 i; + int ret; - hdr = (struct dns_hdr *)uip_appdata; + /* Receive the response */ + + ret = recv(g_sockfd, buffer, RECV_BUFFER_SIZE); + if (ret < 0) + { + return ret; + } + + hdr = (struct dns_hdr *)b dbg( "ID %d\n", htons(hdr->id)); dbg( "Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE); @@ -263,226 +251,123 @@ static void newdata(void) htons(hdr->numquestions), htons(hdr->numanswers), htons(hdr->numauthrr), htons(hdr->numextrarr)); - /* The ID in the DNS header should be our entry into the name - * table. - */ + /* Check for error. If so, call callback to inform */ - i = htons(hdr->id); - namemapptr = &names[i]; - if (i < RESOLV_ENTRIES && namemapptr->state == STATE_ASKING) + if ((hdr->flags2 & DNS_FLAG2_ERR_MASK) != 0) { - /* This entry is now finished */ + return ERROR; + } - namemapptr->state = STATE_DONE; - namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; + /* We only care about the question(s) and the answers. The authrr + * and the extrarr are simply discarded. + */ - /* Check for error. If so, call callback to inform */ + nquestions = htons(hdr->numquestions); + nanswers = htons(hdr->numanswers); - if (namemapptr->err != 0) - { - namemapptr->state = STATE_ERROR; - resolv_found(namemapptr->name, NULL); - return; - } + /* Skip the name in the question. XXX: This should really be + * checked agains the name in the question, to be sure that they + * match. + */ - /* We only care about the question(s) and the answers. The authrr - * and the extrarr are simply discarded. - */ - - nquestions = htons(hdr->numquestions); - nanswers = htons(hdr->numanswers); + nameptr = parse_name((unsigned char *)buffer + 12) + 4; - /* Skip the name in the question. XXX: This should really be - * checked agains the name in the question, to be sure that they - * match. + for (; nanswers > 0; nanswers--) + { + /* The first byte in the answer resource record determines if it + * is a compressed record or a normal one. */ - nameptr = parse_name((unsigned char *)uip_appdata + 12) + 4; - - while(nanswers > 0) + if (*nameptr & 0xc0) { - /* The first byte in the answer resource record determines if it - * is a compressed record or a normal one. - */ - - if (*nameptr & 0xc0) - { - /* Compressed name. */ - - nameptr +=2; - dbg("Compressed anwser\n"); - } - else - { - /* Not compressed name. */ - nameptr = parse_name(nameptr); - } - - ans = (struct dns_answer *)nameptr; - dbg("Answer: type %x, class %x, ttl %x, length %x\n", - htons(ans->type), htons(ans->class), (htons(ans->ttl[0]) << 16) | htons(ans->ttl[1]), - htons(ans->len)); - - /* Check for IP address type and Internet class. Others are discarded. */ - - if (ans->type == HTONS(1) && ans->class == HTONS(1) && ans->len == HTONS(4)) - { - dbg("IP address %d.%d.%d.%d\n", - htons(ans->ipaddr[0]) >> 8, htons(ans->ipaddr[0]) & 0xff, - htons(ans->ipaddr[1]) >> 8, htons(ans->ipaddr[1]) & 0xff); - - /* XXX: we should really check that this IP address is the one - * we want. - */ - - namemapptr->ipaddr[0] = ans->ipaddr[0]; - namemapptr->ipaddr[1] = ans->ipaddr[1]; - - resolv_found(namemapptr->name, namemapptr->ipaddr); - return; - } - else - { - nameptr = nameptr + 10 + htons(ans->len); - } - --nanswers; - } - } -} + /* Compressed name. */ -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/* This function is called by the UIP interrupt handling logic whenevent an - * event of interest occurs. - */ - -void uip_interrupt_udp_event(void) -{ - if (uip_udp_conn->rport == HTONS(53)) - { - if (uip_poll()) - { - check_entries(); + nameptr +=2; + dbg("Compressed anwser\n"); } - if (uip_newdata()) + else { - newdata(); + /* Not compressed name. */ + nameptr = parse_name(nameptr); } - } -} - -/* Queues a name so that a question for the name will be sent out. */ -void resolv_query(char *name) -{ - static uint8 i; - static uint8 lseq, lseqi; - register struct namemap *nameptr; + ans = (struct dns_answer *)nameptr; + dbg("Answer: type %x, class %x, ttl %x, length %x\n", + htons(ans->type), htons(ans->class), (htons(ans->ttl[0]) << 16) | htons(ans->ttl[1]), + htons(ans->len)); - lseq = lseqi = 0; + /* Check for IP address type and Internet class. Others are discarded. */ - for(i = 0; i < RESOLV_ENTRIES; ++i) - { - nameptr = &names[i]; - if (nameptr->state == STATE_UNUSED) + if (ans->type == HTONS(1) && ans->class == HTONS(1) && ans->len == HTONS(4)) { - break; + dbg("IP address %d.%d.%d.%d\n", + htons(ans->ipaddr[0]) >> 8, htons(ans->ipaddr[0]) & 0xff, + htons(ans->ipaddr[1]) >> 8, htons(ans->ipaddr[1]) & 0xff); + + /* XXX: we should really check that this IP address is the one + * we want. + */ + + addr->sin_addr.s_addr = ((uint32)ans->ipaddr[0] << 16) | (uint32)ans->ipaddr[1]; + return OK; } - if (seqno - nameptr->seqno > lseq) + else { - lseq = seqno - nameptr->seqno; - lseqi = i; + nameptr = nameptr + 10 + htons(ans->len); } } - - if (i == RESOLV_ENTRIES) - { - i = lseqi; - nameptr = &names[i]; - } - - dbg("Using entry %d\n", i); - - strcpy(nameptr->name, name); - nameptr->state = STATE_NEW; - nameptr->seqno = seqno; - ++seqno; } -/* Look up a hostname in the array of known hostnames. - * - * Note: This function only looks in the internal array of known - * hostnames, it does not send out a query for the hostname if none - * was found. The function resolv_query() can be used to send a query - * for a hostname. - * - * Return A pointer to a 4-byte representation of the hostname's IP - * address, or NULL if the hostname was not found in the array of - * hostnames. - */ - -uint16 *resolv_lookup(char *name) -{ - static uint8 i; - struct namemap *nameptr; +/**************************************************************************** + * Public Functions + ****************************************************************************/ - /* Walk through the list to see if the name is in there. If it is - * not, we return NULL. - */ +/* Get the binding for name. */ - for(i = 0; i < RESOLV_ENTRIES; ++i) +#ifdef CONFIG_NET_IPv6 +int resolv_query(char *name, struct sockaddr_in6 *addr) +#else +int resolv_query(char *name, struct sockaddr_in *addr) +#endif +{ + int ret = send_query(name); + if (ret == 0) { - nameptr = &names[i]; - if (nameptr->state == STATE_DONE && strcmp(name, nameptr->name) == 0) - { - return nameptr->ipaddr; - } + ret = recv_response(addr); } - return NULL; + return ret; } -/* Obtain the currently configured DNS server. - * - * Return: A pointer to a 4-byte representation of the IP address of - * the currently configured DNS server or NULL if no DNS server has - * been configured. - */ +/* Obtain the currently configured DNS server. */ -uint16 *resolv_getserver(void) +#ifdef CONFIG_NET_IPv6 +void resolv_getserver(const struct sockaddr_in6 *dnsserver) +#else +void resolv_getserver(const struct sockaddr_in *dnsserver) +#endif { - if (resolv_conn == NULL) - { - return NULL; - } - return resolv_conn->ripaddr; + memcpy(dnsserver, gdnsserver, sizeof(gdnsserver)); } -/* Configure which DNS server to use for queries. - * - * dnsserver A pointer to a 4-byte representation of the IP - * address of the DNS server to be configured. - */ +/* Configure which DNS server to use for queries */ -void resolv_conf(uint16 *dnsserver) +#ifdef CONFIG_NET_IPv6 +void resolv_conf(const struct sockaddr_in6 *dnsserver) +#else +void resolv_conf(const struct sockaddr_in *dnsserver) +#endif { - if (resolv_conn != NULL) - { - uip_udp_remove(resolv_conn); - } - - resolv_conn = uip_udp_new(dnsserver, HTONS(53)); + memcpy(&gdnsserver, dnsserver, sizeof(gdnsserver)); } /* Initalize the resolver. */ -void resolv_init(void) +int resolv_init(void) { - static uint8 i; - - for(i = 0; i < RESOLV_ENTRIES; ++i) + g_sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (g_sockfd < 0) { - names[i].state = STATE_DONE; + return ERROR; } + return OK; } diff --git a/netutils/webclient/webclient.c b/netutils/webclient/webclient.c index a89647ab5b0f1f22109e7e6ca0a028f3f7fc291e..6d0c0645b4bace26393cbcd3119f720ddf212fec 100644 --- a/netutils/webclient/webclient.c +++ b/netutils/webclient/webclient.c @@ -38,7 +38,7 @@ * * This file is part of the uIP TCP/IP stack. * - * $Id: webclient.c,v 1.2 2007-09-02 21:58:34 patacongo Exp $ + * $Id: webclient.c,v 1.3 2007-09-03 20:34:44 patacongo Exp $ * */ @@ -129,11 +129,10 @@ unsigned char webclient_get(char *host, uint16 port, char *file) ipaddr = &addr; if (uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) { - ipaddr = (uip_ipaddr_t *)resolv_lookup(host); - - if (ipaddr == NULL) { - return 0; - } + if (resolv_query(host, &ipaddr) < 0) + { + return ERROR; + } } /* Create a socket */ @@ -460,9 +459,14 @@ void uip_interrupt_event(void) } else { - if (resolv_lookup(s.host) == NULL) +#ifdef CONFIG_NET_IPv6 + struct sockaddr_in6 addr; +#else + struct sockaddr_in addr; +#endif + if (resolv_query(s.host, &addr) < 0) { - resolv_query(s.host); + return ERROR; } webclient_get(s.host, s.port, s.file); }