# System Calls Below are the system calls that can be used to access network functionality. * **getaddrinfo()** : * Purpose : It helps set up the structs, specifically **struct addrinfo**. It does all the dirty work like DNS and service name lookup and fill up the structs with all the relevant information based on the parameters passed. * Function prototye ``` int getaddrinfo(const char *node, // e.g. "www.example.com" or IP const char *service, // e.g. "http" or port number const struct addrinfo *hints, struct addrinfo **res); ``` 1. node : Type : `const char *` Value : Domain name or IP in form of string. Purpose : To help find the host computer IP address for connection. 2. service : Type : `const char *` Value : Service/Protocol or Port in form of string. Purpose : To help specify the port number in the host computer. 3. hints : Type : `const struct addrinfo *` Value : Pointer to *struct addrinfo*. Purpose : To guide how it should fetch relevent data and store it to `struct addrinfo **res`. 4. res : Type : `struct addrinfo **` Value : Pointer to linked list of *struct addrinfo \** * Return Type : Non-zero value in case of error or zero, otherwise. **Code Snippet** ``` int status; struct addrinfo hints; struct addrinfo *servinfo; // will point to the results memset(&hints, 0, sizeof hints); // make sure the struct is // garbage free hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; // TCP stream sockets hints.ai_flags = AI_PASSIVE; // fill in my IP(my host) for me if ((status = getaddrinfo(NULL, "3490", &hints, &servinfo)) != 0){ fprintf(stderr, "getaddrinfo erro: %s\n", gai_strerror(status)); exit(1); } // servinfo now points to a linked list of 1 or more struct // addrinfos // ... do everything until you don't need servinfo anymore ... freeaddrinfo(servinfo); // free the linked list ``` * **socket() :** * Purpose : Assign a *file descriptor* for accessing OS resources to access network. Defines the type connection it would make to other host. * Function Prototype : ``` #include #include int socket(int domain, int type, int protocol); ``` 1. domain : Type : `int` Value : `PF_INET` or `PF_INET6` Purpose : Used to specify the Protocol family we would like to use. > [!IMPORTANT] > The value of `PF_INET` and `AF_INET` are same and they are used > interchangably. **PF** stands for *Protocol family* and **AF** stands > stands for *Address family*. 2. type : Type : `int` Value : `SOCK_STREAM` or `SOCK_DGRAM` Purpose : Used to signify type of socket we want to create. (Connection or Connection-less). 3. protocol : Type : `int` Purpose : Signifies either `TCP` or `UDP` protocol is being used for communication. * Return Type : Returns' an integer which signify an `fd` or -1 on error and global variable *errno* is set to the error's value . * **Code Snippet** ``` int s; struct addrinfo hints, *res; // do the lookup // [pretend we already filled out the "hints" struct] getaddrinfo("www.example.com", "http", &hints, &res); // remember, do the error-checking on getaddrinfo(), // walk the "res" linked list for valid entries. s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); ``` * **bind() :** * Purpose : It's used for connecting socket fd with port of local machine. * Function prototype : ``` #include #include int bind(int sockfd, struct sockaddr *my_addr, int addrlen); ``` 1. sockfd : Type : `int` Value : integer value representing socket fd. Purpose : sockfd to bind to a port. 2. my_addr : Type : `struct sockaddr *` Value : Holding port number information. Purpose : port number to bind to sockfd. 3. addrlen : Type : `int` Value : length of the `struct sockaddr`. * Return Type : returns -1 on error and sets **errno** to the error's value. >[!IMPORTANT] > The below code snippet is w.r.t old way of using bind function. > The new way of doing the same is to use `getaddrinfo()` for ease. ``` // !!! THIS IS THE OLD WAY !!! int sockfd; struct sockaddr_in my_addr; sockfd = socket(PF_INET, SOCK_STREAM, 0); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(MYPORT); // short, network byte order my_addr.sin_addr.s_addr = inet_addr("10.12.110.57"); memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr); ``` >[!NOTE] > Sometimes binding to a port maybe fail due to its live bond with a free > socket and can lead to error. To avoid this below code snippet can be > userful. > > ``` > int yes = 1; > // char yes = '1'; // Solaris people use this > > // lose the pesky "Address already in use" error message > if( setsockopt(listener,SOL_SOCKET, > SO_REUSEADDR, &yes, sizeof yes) == -1){ > perror("setsockopt"); > exit(1); > } > ``` * **connect() :** * Purpose : To connect to a remote host. * Function prototype : ``` #include #include int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); ``` 1. sockfd : Type : `int` Value : socket fd, as returned by the `socket()` call. 2. serv_addr : Type : `struct sockaddr *` Value : containing destination port and IP address. 3. addrlen : Type : `int` Value : length `struct sockaddr` in bytes. * Return : It'll return -1 on error and set the variable `errno`. * Code snippet : ``` struct addrinfo hints, *res; int sockfd; // first, load up address structs with getaddrinfo(): memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; getaddrinfo("www.example.com", "3490", &hints, &res); // make a socket: sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); // connect! connect(sockfd, res->ai_addr, res->ai_addrlen); ``` * **listen() :** * Purpose : Connect to incoming connection from remote host computers. * Function prototype : ``` int listen(int sockfd, int backlog); ``` 1. sockfd : Type : `int` Value : socket fd, as returned by the `socket()` call. 2. backlog : Type : `int` Value : number of connection allowed on the incoming queue. * Return : It'll return -1 on error and set the variable `errno`. * Code Snippet : ``` getaddrinfo(); socket(); bind(); listen(); /* accept() goes here */ ``` * **accept() :** * Purpose : Accept connection request pending in the waiting queue. * Function Prototype : ``` #include #include int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); ``` 1. sockfd : Types : `int` Value : *sockfd* is the listening socket descriptor. 2. addr : Type : `struct sockaddr *` Value : pointer to a local `struct sockaddr_storage`. This is where the information about the incoming connection will go(and with it we can determine which host is calling us from which port). 3. addrlen : Type : `int` Value : equal to value sizeof(struct sockaddr_storage). accept() will not put more than that many bytes into addr. If it puts fewer in, it'll change the value of addrlen to reflect that. * Return value : returns -1 and set `errno` if error occurs. * Code Snippet : ``` #include #include #include #include #define MYPORT "3490" // the port users will be connecting to #define BACKLOG 10 // how many pending connections queue will hold int main(){ struct sockaddr_storage their_addr; socklen_t addr_size; struct addrinfo hints, *res; int sockfd, new_fd; // !! don't forget your error checking for these calls !! // first, load up address structs with getaddrinfo(); memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // fill in my IP for me getaddrinfo(NULL, MYPORT, &hints, &res); // make a socket, bind it, and listen on it: sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); bind(sockfd, res->ai_addr, res->ai_addrlen); listen(sockfd, BACKLOG); // now accept an incoming connection: addr_size = sizeof their_addr; new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size); // ready to communicate on socket descriptor new_fd! } ``` >[!NOTE] > new_fd will be used for send() and recv() calls. * **send() :** * Purpose : Used for communication between two connections. The communication can over stream sockets or connected datagram sockets. * Function Prototype : ``` int send(int socfd, const void *msg, int len, int flags); ``` 1. sockfd : Type : `int` Value : *sockfd* is the socket descriptor you want to send data to(whether it's the one returned by socket() or the one you got with accept()). 2. msg : Type : `const void *` Value : pointer to data we want to send in form of byte array. 3. len : Type : `int` Value : Length of byte array. 4. flag : Type : `int` Value : set to 0. * Return type: returns the number of bytes actually sent out - *this might be less than the number you told it to send!*. Again, -1 is returned on error, and `errno` is set to the error number. * Code Snippet : ``` char *msg = "Beej was here!"; int len, bytes_sent; len = strlen(msg); bytes_sent = send(sockfd, msg, len, 0); ``` * **recv() :** * Purpose : To receive data from the remote machine, which may attempt to send data. * Function prototype : ``` int recv(int sockfd, void *buf, int len, int flags); ``` 1. sockfd : Type : `int` Value : Socket desriptor to read from. 2. buf : Type : `void *` Value : buffer to read the information into. 3. len : Type : `int` Value : maximum length of buffer specified. 4. flags : Type : `int` Value : set to 0. * Return type : Number of bytes actually read into the buffer or -1 on error. recv() can return 0 when the remote side has closed the connection. * **sendto() :** * Purpose : To send data to remote connection without forming any connection beforehand. * Function Prototype : ``` int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, socklen_t tolen); ``` 1. sockfd : Type : `int` Value : fd which maintain connection with remote machine. 2. msg : Type : `const void*` Value : buffer which stores the data which need to be transferred. 3. len : Type : `int` Value : Length of the buffer 4. flags : Type : `int` Value : set it to zero 5. to : Type : `struct sockaddr *` Value : Containing the address we want the send data to. 6. tolen : Type : `socklen_t` Value : `int` deep down, is equal to sizeof(struct sockaddr_storage). * **recvfrom() :** * Purpose : It receive data by remote machine which choose udp mode of communication. * Function Prototype : ``` int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen); ``` 1. sockfd : Type : `int` Value : fd which maintain connection with remote machine. 2. buf : Type : `void *` Value : buffer which will stores the data that would be received. 3. len : Type : `int` Value : Length of the buffer 4. flags : Type : `int` Value : set it to zero 5. from : Type : `struct sockaddr *` Value : contains the address of sending machine. 6. fromlen : Type : `int` Value : equal to sizeof(struct sockaddr_storage) * Returns : returns number of bytes received, or -1 on error and set `errno`. * **close() :** * Purpose : To close the socket and prevent any further communication. * Function Prototype : ``` close(sockfd); ``` * **shutdown() :** * Purpose : It gives more control over how the socket closes. It allows you to cut off communication in a certain direction, or both ways. If applied on unconnected datagram sockets, it will simply make socket unavailable to use. * Function Prototype : ``` int shutdown(int sockfd, int how); ``` 1. sockfd : which socket to close. 2. how : how can have following value :- * 0 - Further receives are disallowed. * 1 - Further sends are disallowed. * 2 - Further sends and receives are disallowed(like close()). * Returns: returns 0 on success or -1 on failure. > [!NOTE] > `shutdown()` doesn't actually close the file descriptor -- it just > changes its usability. To free socket descriptor, you need to use > `close()`. * **getpeername() :** * Purpose : It tells us who is at the other end of a connected stream socket. * Function Prototype : ``` #include int getpeername(int sockfd, struct sockaddr *addr, int *addrlen); ``` 1. sockfd : Descriptor of connected stream socket. 2. addr : Holds the address of the remote connection. 3. addrlen : Equal to the sizeof(struct sockaddr). * Returns : Returns -1 on error and sets errno accordingly. * **gethostname() :** * Purpose : Gets name of the computer that running our program. * Function Prototype : ``` #include int gethostname(char *hostname, size_t size); ``` 1. hostname : buffer to contain the hostname. 2. size : size of the buffer.