Skip to content

ZOld Assignment: 1. Basics ‒ socket(), open(), getsockname()

Sue Moon edited this page Sep 28, 2021 · 1 revision

The POSIX APIs for socket() and bind() are as follows:

#include <sys/socket.h>
int socket(int domain, int type, int protocol);
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr,
         socklen_t addrlen);
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

Corresponding APIs in KENS would be implemented in systemCallback:

void TCPAssignment::systemCallback(UUID syscallUUID, int pid,
                                   const SystemCallParameter &param) {


  switch (param.syscallNumber) {
  case SOCKET:
    // this->syscall_socket(syscallUUID, pid, param.param1_int,
    // param.param2_int, param.param3_int);
    break;

...

  case BIND:
    // this->syscall_bind(syscallUUID, pid, param.param1_int,
    //		static_cast<struct sockaddr *>(param.param2_ptr),
    //		(socklen_t) param.param3_int);
    break;

...

  case GETSOCKNAME:
    // this->syscall_getsockname(syscallUUID, pid, param.param1_int,
    //		static_cast<struct sockaddr *>(param.param2_ptr),
    //		static_cast<socklen_t*>(param.param3_ptr));
    break;

...

 }
}

This assignment is to build the bare minimum of the transport layer, namely create data structures, assign parameter values to the correct data structure fields, and return correct values. The testing code will call those APIs and check to see the return values are correct. It is not easy to check if the internals of your code are correct. They will be tested more rigorously in part 3 and 4. So we recommend you to take a look at the test code in part 3 and 4 in advance and design your data structures accordingly.

In part 1 and 2, you build your own TCP layer below the socket API. You will implement the functions listed above. The skeletal code is in TCPAssignment.cpp.

The goal here is to implement the following parts in TCPAssignment.cpp and run testopen.cpp and testbind.cpp successfully.

Socket Function

  case SOCKET:
    // this->syscall_socket(syscallUUID, pid, param.param1_int,
    // param.param2_int, param.param3_int);
    break;

The socket() call receives 3 parameters from the application layer. Now it should create a file descriptor and store the domain and the protocol in the data structure indexed by the file descriptor. It returns the file descriptor. More details about the socket call are described at: https://man7.org/linux/man-pages/man2/socket.2.html and https://man7.org/linux/man-pages/man3/socket.3p.html . In KENS, you need to implement only domain AF_INET, type SOCK_STREAM, and protocol IPPROTO_TCP.

The testing code in testopen.cpp calls socket() many times and checks if the return values are correct.

Caution

You have to implement a very simple close()call to pass testopen. The close() removes its file descriptor and the latter socket()call would return the descriptor’s value .

Bind Function

  case BIND:
    // this->syscall_bind(syscallUUID, pid, param.param1_int,
    //		static_cast<struct sockaddr *>(param.param2_ptr),
    //		(socklen_t) param.param3_int);
    break;

The bind() call receives 3 parameters from the application layer. Now it should assign an address to the socket. More details about the socket call are described https://man7.org/linux/man-pages/man2/bind.2.html and https://man7.org/linux/man-pages/man3/bind.3p.html . In KENS, you need to implement only sockaddr_in type for sockaddr.

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */
};

/* Internet address. */
struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};

The only value you should assign to sin_family is AF_INET. The two fields, sin_port and sin_addr, must follow the network byte order. The sin_addr field must be either an IP address or INADDR_ANY. You should implement both cases.

GetSockName Function

  case GETSOCKNAME:
    // this->syscall_getsockname(syscallUUID, pid, param.param1_int,
    //		static_cast<struct sockaddr *>(param.param2_ptr),
    //		static_cast<socklen_t*>(param.param3_ptr));
    break;

The getsockname() call receives 3 parameters from the application layer. It should return the current address to which the socket is bound. More details about the socket call are described https://man7.org/linux/man-pages/man2/getsockname.2.html and https://man7.org/linux/man-pages/man3/getsockname.3p.html . As in the case of bind(), you need to implement only the sockaddr_in type for sockaddr.

Tips