Lecture 15 Overview Network API • Application Programming Interface – Services that provide the interface between application and protocol software • often by the operating system Application Network API Protocol A CPE 401/601 Lecture 15 : Socket Programming Protocol B Protocol C 2 Network API wish list • Generic Programming Interface – Support multiple communication protocol suites (families) – Address (endpoint) representation independence – Provide special services for Client and Server? • Support for message oriented and connection oriented communication • Work with existing I/O services – when this makes sense • Operating System independence CPE 401/601 Lecture 15 : Socket Programming 3 Socket • A socket is an abstract representation of a communication endpoint • Sockets work with Unix I/O services just like files, pipes & FIFOs • Sockets needs to – establishing a connection – specifying communication endpoint addresses CPE 401/601 Lecture 15 : Socket Programming 4 Creating a Socket int socket(int family, int type, int proto); • family specifies the protocol family – PF_INET for TCP/IP • type specifies the type of service – SOCK_STREAM, SOCK_DGRAM • protocol specifies the specific protocol – usually 0, which means the default CPE 401/601 Lecture 15 : Socket Programming 5 socket() • The socket() system call returns a socket descriptor (small integer) or -1 on error • socket() allocates resources needed for a communication endpoint – but it does not deal with endpoint addressing CPE 401/601 Lecture 15 : Socket Programming 6 Specifying an Endpoint Address • Sockets API is generic • There must be a generic way to specify endpoint addresses • TCP/IP requires an IP address and a port number for each endpoint address • Other protocol suites (families) may use other schemes CPE 401/601 Lecture 15 : Socket Programming 7 sockaddr sockaddr_in6 length AF_INET6 port sockaddr sa_len sa_family sockaddr_in length AF_INET port addr Flow-label sa_data addr zero Scope ID variable 16 bytes 28 bytes CPE 401/601 Lecture 15 : Socket Programming 8 struct sockaddr_in (IPv4) Length of struct sockaddr_in { structure (16) uint8_t sin_len; AF_INET sa_family_t sin_family; in_port_t sin_port; 16 bit Port number struct in_addr sin_addr; char sin_zero[8]; Make structure }; 16 bytes struct in_addr { in_addr_t s_addr; 32 bit IPv4 address }; CPE 401/601 Lecture 15 : Socket Programming 9 struct sockaddr_in (IPv6) struct sockaddr_in6 { Length of structure (28) uint8_t sin6_len; AF_INET6 sa_family_t sin6_family; in_port_t sin6_port; Port number uint32_t sin6_flowinfo; Flow label struct in6_addr sin6_addr; Scope of uint32_t sin6_scope_id; address }; struct in6_addr { 128 bit uint8_t s6_addr[16]; IPv6 address 10 CPE 401/601 Lecture 15 : Socket Programming }; Network Byte Order • All values stored in a sockaddr_in must be in network byte order. – sin_port a TCP/IP port number – sin_addr an IP address • • • • uint16_t uint16_t uint32_t uint32_t htons(uint16_t); ntohs(uint_16_t); htonl(uint32_t); ntohl(uint32_t); CPE 401/601 Lecture 15 : Socket Programming 11 TCP/IP Addresses • We don’t need to deal with sockaddr structures since we will only deal with a real protocol family. • We can use sockaddr_in structures • BUT: The C functions that make up the sockets API expect structures of type sockaddr CPE 401/601 Lecture 15 : Socket Programming 12 Assigning an address to a socket • The bind() system call is used to assign an address to an existing socket. int bind( int sockfd, const struct sockaddr *myaddr, int addrlen); • You can give bind() a sockaddr_in structure: int bind( mysock, (struct sockaddr*) &myaddr, sizeof(myaddr) ); CPE 401/601 Lecture 15 : Socket Programming 13 bind() Example int mysock,err; struct sockaddr_in myaddr; mysock = socket(PF_INET,SOCK_STREAM,0); myaddr.sin_family = AF_INET; myaddr.sin_port = htons( portnum ); myaddr.sin_addr = htonl( ipaddress); err=bind(mysock, (sockaddr *) &myaddr, sizeof(myaddr)); CPE 401/601 Lecture 15 : Socket Programming 14 Port schmort - who cares ? • Clients typically don’t care what port they are assigned • When you call bind you can tell it to assign you any available port: – myaddr.port = htons(0); CPE 401/601 Lecture 15 : Socket Programming 15 What is my IP address ? • How can you find out what your IP address is so you can tell bind() ? • There is no realistic way for you to know the right IP address to give bind() – what if the computer has multiple network interfaces? • specify the IP address as: INADDR_ANY, this tells the OS to take care of things. CPE 401/601 Lecture 15 : Socket Programming 16 IPv4 Address Conversion int inet_aton(char *, struct in_addr *); – Convert ASCII dotted-decimal IP address to network byte ordered 32 bit value. – Returns 1 on success, 0 on failure. char *inet_ntoa(struct in_addr); – Convert network byte ordered value to ASCII dotted-decimal (a string). CPE 401/601 Lecture 15 : Socket Programming 17 IPv4 & IPv6 Address Conversion int inet_pton(int, const char*, void*); – (family, string_ptr, address_ptr) – Convert IP address string to network byte ordered 32 or 128 bit value – 1 on success, -1 on failure, 0 on invalid input char *inet_ntop(int, const void*, char*, size_t); – (family, address_ptr, string_ptr, length) – Convert network byte ordered value to IP address string • x:x:x:x:x:x:x:x or x:x:x:x:x:x:a.b.c.d CPE 401/601 Lecture 15 : Socket Programming 18 Other socket system calls • General Use – read() – write() – close() • Connection-oriented (TCP) – connect() – listen() – accept() • Connectionless (UDP) – send() – recv() CPE 401/601 Lecture 15 : Socket Programming 19 Lecture 16 TCP and UDP Sockets CPE 401 / 601 Computer Network Systems slides modified from Dave Hollinger slides are are modified from Dave Hollinger TCP Sockets Programming • Creating a passive mode (server) socket • Establishing an application-level connection • send/receive data • Terminating a connection CPE 401/601 Lecture 16 : TCP Socket Programming 21 TCP state diagram Creating a TCP socket int socket(int family,int type,int proto); – family: AF_INET, AF_INET6, AF_LOCAL, … – type: SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW – protocol: IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP int sock; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock<0) { /* ERROR */ } CPE 401/601 Lecture 16 : TCP Socket Programming 23 Binding to well known address int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen); int mysock; struct sockaddr_in myaddr; mysock = socket(PF_INET,SOCK_STREAM,0); myaddr.sin_family = AF_INET; myaddr.sin_port = htons( 80 ); myaddr.sin_addr = htonl( INADDR_ANY ); bind(mysock, (sockaddr *) &myaddr, sizeof(myaddr)); CPE 401/601 Lecture 16 : TCP Socket Programming 24 Establishing a passive mode TCP socket • Passive mode: – Address already determined • Tell the kernel to accept incoming connection requests directed at the socket address – 3-way handshake • Tell the kernel to queue incoming connections for us CPE 401/601 Lecture 16 : TCP Socket Programming 25 listen() int listen(int sockfd, int backlog); • sockfd is the TCP socket – already bound to an address • backlog is the number of incoming connections the kernel should be able to keep track of (queue for us) – Sum of incomplete and completed queues CPE 401/601 Lecture 16 : TCP Socket Programming 26 Accepting an incoming connection • Once we call listen(), the O.S. will queue incoming connections – Handles the 3-way handshake – Queues up multiple connections • When our application is ready to handle a new connection – we need to ask the O.S. for the next connection CPE 401/601 Lecture 16 : TCP Socket Programming 27 accept() int accept( int sockfd, struct sockaddr* cliaddr, socklen_t *addrlen); • sockfd is the passive mode TCP socket – initiated by socket(), bind(), and listen() • cliaddr is a pointer to allocated space • addrlen is a value-result argument – must be set to the size of cliaddr – on return, will be set to be the number of used bytes in cliaddr CPE 401/601 Lecture 16 : TCP Socket Programming 28 accept() return value • accept() returns a new socket descriptor (small positive integer) or -1 on error • After accept returns a new socket descriptor, I/O can be done using the read() and write() system calls • read() and write() operate a little differently on sockets! – vs. file operation! CPE 401/601 Lecture 16 : TCP Socket Programming 29 Terminating a TCP connection int close(int sockfd); • Either end of the connection can call the close() system call • What if there is data being sent? • If the other end has closed the connection, and there is no buffered data, reading from a TCP socket returns 0 to indicate EOF. CPE 401/601 Lecture 16 : TCP Socket Programming 30 Client Code • TCP clients can call connect() which: – takes care of establishing an endpoint address for the client socket – Attempts to establish a connection to the specified server • 3-way handshake • no need to call bind first, the O.S. will take care of assigning the local endpoint address – TCP port number, IP address CPE 401/601 Lecture 16 : TCP Socket Programming 31 connect() int connect( int sockfd, const struct sockaddr *server, socklen_t addrlen); • sockfd is an already created TCP socket • server contains the address of the server • connect() returns 0 if OK, -1 on error – No response to SYN segment (3 trials) – RST signal – ICMP destination unreachable (3 trials) CPE 401/601 Lecture 16 : TCP Socket Programming 32 Reading from a TCP socket int read(int fd, char *buf, int max); • By default read() will block until data is available • reading from a TCP socket may return less than max bytes – whatever is available • You must be prepared to read data 1 byte at a time! CPE 401/601 Lecture 16 : TCP Socket Programming 33 Writing to a TCP socket int write(int fd, char *buf, int num); • write might not be able to write all num bytes on a nonblocking socket • readn(), writen() and readline() functions CPE 401/601 Lecture 16 : TCP Socket Programming 34 Metaphor for Good Relationships • To succeed in relationships*: – you need to establish your own identity. – you need to be open & accepting. – you need to establish contacts. – you need to take things as they come, not as you expect them. – you need to handle problems as they arise. *Copyright Dr. Laura’s Network Programming Corp. CPE 401/601 Lecture 16 : TCP Socket Programming 35 UDP Sockets UDP Sockets Programming • Creating UDP sockets – Client – Server • Sending data • Receiving data • Connected Mode CPE 401/601 Lecture 16 : UDP Socket Programming 37 Creating a UDP socket int socket(int family, int type, int proto); int sock; sock = socket(PF_INET, SOCK_DGRAM, 0); if (sock<0) { /* ERROR */ } CPE 401/601 Lecture 16 : UDP Socket Programming 38 Binding to well known address • typically done by server only int mysock; struct sockaddr_in myaddr; Mysock=socket(PF_INET,SOCK_DGRAM,0); myaddr.sin_family = AF_INET; myaddr.sin_port = htons(1234); myaddr.sin_addr = htonl(INADDR_ANY); bind(mysock, &myaddr, sizeof(myaddr)); CPE 401/601 Lecture 16 : UDP Socket Programming 39 Sending UDP Datagrams ssize_t sendto( int sockfd, void *buff, size_t nbytes, int flags, const struct sockaddr* to, socklen_t addrlen); • • • • sockfd is a UDP socket buff is the address of the data (nbytes long) to is the destination address Return value is the number of bytes sent, – or -1 on error. CPE 401/601 Lecture 16 : UDP Socket Programming 40 sendto() • The return value of sendto() indicates how much data was accepted by the O.S. for sending as a datagram – not how much data made it to the destination. • There is no error condition that indicates that the destination did not get the data!!! • You can send 0 bytes of data! CPE 401/601 Lecture 16 : UDP Socket Programming 41 Receiving UDP Datagrams ssize_t recvfrom( int sockfd, void *buff, size_t nbytes, int flags, struct sockaddr* from, socklen_t *fromaddrlen); • • • • sockfd is a UDP socket buff is the address of a buffer (nbytes long) from is the address of a sockaddr Return value is the number of bytes received and put into buff, or -1 on error CPE 401/601 Lecture 16 : UDP Socket Programming 42 recvfrom() • If buff is not large enough, any extra data is lost forever... • You can receive 0 bytes of data! • The sockaddr at from is filled in with the address of the sender CPE 401/601 Lecture 16 : UDP Socket Programming 43 More recvfrom() • recvfrom doesn’t return until there is a datagram available, – unless you do something special • You should set fromaddrlen before calling • If from and fromaddrlen are NULL we don’t find out who sent the data CPE 401/601 Lecture 16 : UDP Socket Programming 44 Typical UDP client code • Create UDP socket • Create sockaddr with address of server • Call sendto(), sending request to the server – No call to bind() is necessary! • Possibly call recvfrom() – if we need a reply CPE 401/601 Lecture 16 : UDP Socket Programming 45 Typical UDP Server code • Create UDP socket and bind to well known address • Call recvfrom() to get a request, noting the address of the client • Process request and send reply back with sendto() CPE 401/601 Lecture 16 : UDP Socket Programming 46 Typical UDP Communication CPE 401/601 Lecture 16 : UDP Socket Programming 47 UDP Echo Server int mysock; struct sockaddr_in myaddr, cliaddr; char msgbuf[MAXLEN]; socklen_t clilen; int msglen; mysock = socket(PF_INET,SOCK_DGRAM,0); myaddr.sin_family = AF_INET; myaddr.sin_port = htons( S_PORT ); myaddr.sin_addr = htonl( INADDR_ANY ); bind(mysock, &myaddr, sizeof(myaddr)); while (1) { clilen=sizeof(cliaddr); msglen=recvfrom(mysock,msgbuf,MAXLEN,0, cliaddr,&clilen); sendto(mysock,msgbuf,msglen,0,cliaddr,clilen); } CPE 401/601 Lecture 16 : UDP Socket Programming 48 Debugging • Debugging UDP can be difficult • Write routines to print out sockaddrs • Use trace, strace, ptrace, truss, etc • Include code that can handle unexpected situations CPE 401/601 Lecture 16 : UDP Socket Programming 49 Timeout when calling recvfrom() • It might be nice to have each call to recvfrom() return after a specified period of time even if there is no incoming datagram • We can do this by using SIGALRM and wrapping each call to recvfrom() with a call to alarm() CPE 401/601 Lecture 16 : UDP Socket Programming 50 recvfrom()and alarm() signal(SIGALRM, sig_alrm); alarm(max_time_to_wait); if (recvfrom(…)<0) if (errno==EINTR) /* timed out */ else /* some other error */ else /* no error or time out - turn off alarm */ There are some other alarm(0); (better) ways to do this CPE 401/601 Lecture 16 : UDP Socket Programming 51 Connected mode • A UDP socket can be used in a call to connect() • This simply tells the O.S. the address of the peer • No handshake is made to establish that the peer exists • No data of any kind is sent on the network as a result of calling connect() on a UDP socket CPE 401/601 Lecture 16 : UDP Socket Programming 52 Connected UDP • Once a UDP socket is connected: – can use sendto() with a null dest address – can use write() and send() – can use read() and recv() • only datagrams from the peer will be returned – Asynchronous errors will be returned to the process OS Specific, some won’t do this! CPE 401/601 Lecture 16 : UDP Socket Programming 53 Asynchronous Errors • What happens if a client sends data to a server that is not running? – ICMP “port unreachable” error is generated by receiving host and sent to sending host – The ICMP error may reach the sending host after sendto() has already returned! – The next call dealing with the socket could return the error CPE 401/601 Lecture 16 : UDP Socket Programming 54 Back to UDP connect() • Connect() is typically used with UDP when communication is with a single peer only. • It is possible to disconnect and connect the same socket to a new peer – More efficient to send multiple datagrams to the same user • Many UDP clients use connect() • Some servers (TFTP) CPE 401/601 Lecture 16 : UDP Socket Programming 55