├── .gitignore ├── AF_UNIX ├── client.c ├── multiplexing │ └── server.c └── server.c ├── LICENSE ├── README.md ├── mps └── multi_process_server.c ├── mts └── multi_threaded_server.c ├── project └── node0.c ├── sts ├── common.h ├── mx_tcp_server.c ├── tcp_client.c └── tcp_server.c └── webserver └── TCPWebserver └── tcp_web_server.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /AF_UNIX/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define SOCKET_NAME "/tmp/DemoSocket" 10 | #define BUFFER_SIZE 128 11 | 12 | int 13 | main(int argc, char *argv[]) 14 | { 15 | struct sockaddr_un addr; 16 | int i; 17 | int ret; 18 | int data_socket; 19 | char buffer[BUFFER_SIZE]; 20 | 21 | /* Create data socket. */ 22 | 23 | data_socket = socket(AF_UNIX, SOCK_STREAM, 0); 24 | 25 | if (data_socket == -1) { 26 | perror("socket"); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | /* 31 | * For portability clear the whole structure, since some 32 | * implementations have additional (nonstandard) fields in 33 | * the structure. 34 | * */ 35 | 36 | memset(&addr, 0, sizeof(struct sockaddr_un)); 37 | 38 | /* Connect socket to socket address */ 39 | 40 | addr.sun_family = AF_UNIX; 41 | strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); 42 | 43 | ret = connect (data_socket, (const struct sockaddr *) &addr, 44 | sizeof(struct sockaddr_un)); 45 | 46 | if (ret == -1) { 47 | fprintf(stderr, "The server is down.\n"); 48 | exit(EXIT_FAILURE); 49 | } 50 | 51 | /* Send arguments. */ 52 | do{ 53 | printf("Enter number to send to server :\n"); 54 | scanf("%d", &i); 55 | ret = write(data_socket, &i, sizeof(int)); 56 | if (ret == -1) { 57 | perror("write"); 58 | break; 59 | } 60 | printf("No of bytes sent = %d, data sent = %d\n", ret, i); 61 | } while(i); 62 | 63 | /* Request result. */ 64 | 65 | memset(buffer, 0, BUFFER_SIZE); 66 | strncpy (buffer, "RES", strlen("RES")); 67 | buffer[strlen(buffer)] = '\0'; 68 | printf("buffer = %s\n", buffer); 69 | 70 | ret = write(data_socket, buffer, strlen(buffer)); 71 | if (ret == -1) { 72 | perror("write"); 73 | exit(EXIT_FAILURE); 74 | } 75 | 76 | /* Receive result. */ 77 | memset(buffer, 0, BUFFER_SIZE); 78 | 79 | ret = read(data_socket, buffer, BUFFER_SIZE); 80 | if (ret == -1) { 81 | perror("read"); 82 | exit(EXIT_FAILURE); 83 | } 84 | 85 | /* Ensure buffer is 0-terminated. */ 86 | 87 | buffer[BUFFER_SIZE - 1] = 0; 88 | 89 | printf("Result = %s\n", buffer); 90 | 91 | /* Close socket. */ 92 | 93 | close(data_socket); 94 | 95 | exit(EXIT_SUCCESS); 96 | } 97 | -------------------------------------------------------------------------------- /AF_UNIX/multiplexing/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define SOCKET_NAME "/tmp/DemoSocket" 9 | #define BUFFER_SIZE 128 10 | 11 | #define MAX_CLIENT_SUPPORTED 32 12 | 13 | /*An array of File descriptors which the server process 14 | * is maintaining in order to talk with the connected clients. 15 | * Master skt FD is also a member of this array*/ 16 | int monitored_fd_set[MAX_CLIENT_SUPPORTED]; 17 | 18 | /*Each connected client's intermediate result is 19 | * maintained in this client array.*/ 20 | int client_result[MAX_CLIENT_SUPPORTED] = {0}; 21 | 22 | /*Remove all the FDs, if any, from the the array*/ 23 | static void 24 | intitiaze_monitor_fd_set(){ 25 | 26 | int i = 0; 27 | for(; i < MAX_CLIENT_SUPPORTED; i++) 28 | monitored_fd_set[i] = -1; 29 | } 30 | 31 | /*Add a new FD to the monitored_fd_set array*/ 32 | static void 33 | add_to_monitored_fd_set(int skt_fd){ 34 | 35 | int i = 0; 36 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 37 | 38 | if(monitored_fd_set[i] != -1) 39 | continue; 40 | monitored_fd_set[i] = skt_fd; 41 | break; 42 | } 43 | } 44 | 45 | /*Remove the FD from monitored_fd_set array*/ 46 | static void 47 | remove_from_monitored_fd_set(int skt_fd){ 48 | 49 | int i = 0; 50 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 51 | 52 | if(monitored_fd_set[i] != skt_fd) 53 | continue; 54 | 55 | monitored_fd_set[i] = -1; 56 | break; 57 | } 58 | } 59 | 60 | /* Clone all the FDs in monitored_fd_set array into 61 | * fd_set Data structure*/ 62 | static void 63 | refresh_fd_set(fd_set *fd_set_ptr){ 64 | 65 | FD_ZERO(fd_set_ptr); 66 | int i = 0; 67 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 68 | if(monitored_fd_set[i] != -1){ 69 | FD_SET(monitored_fd_set[i], fd_set_ptr); 70 | } 71 | } 72 | } 73 | 74 | /*Get the numerical max value among all FDs which server 75 | * is monitoring*/ 76 | 77 | static int 78 | get_max_fd(){ 79 | 80 | int i = 0; 81 | int max = -1; 82 | 83 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 84 | if(monitored_fd_set[i] > max) 85 | max = monitored_fd_set[i]; 86 | } 87 | 88 | return max; 89 | } 90 | 91 | 92 | 93 | int 94 | main(int argc, char *argv[]) 95 | { 96 | struct sockaddr_un name; 97 | 98 | #if 0 99 | struct sockaddr_un { 100 | sa_family_t sun_family; /* AF_UNIX */ 101 | char sun_path[108]; /* pathname */ 102 | }; 103 | #endif 104 | 105 | int ret; 106 | int connection_socket; 107 | int data_socket; 108 | int result; 109 | int data; 110 | char buffer[BUFFER_SIZE]; 111 | fd_set readfds; 112 | int comm_socket_fd, i; 113 | intitiaze_monitor_fd_set(); 114 | add_to_monitored_fd_set(0); 115 | 116 | /*In case the program exited inadvertently on the last run, 117 | *remove the socket. 118 | **/ 119 | 120 | unlink(SOCKET_NAME); 121 | 122 | /* Create Master socket. */ 123 | 124 | /*SOCK_DGRAM for Datagram based communication*/ 125 | connection_socket = socket(AF_UNIX, SOCK_STREAM, 0); 126 | 127 | if (connection_socket == -1) { 128 | perror("socket"); 129 | exit(EXIT_FAILURE); 130 | } 131 | 132 | printf("Master socket created\n"); 133 | 134 | /*initialize*/ 135 | memset(&name, 0, sizeof(struct sockaddr_un)); 136 | 137 | /*Specify the socket Cridentials*/ 138 | name.sun_family = AF_UNIX; 139 | strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1); 140 | 141 | /* Bind socket to socket name.*/ 142 | /* Purpose of bind() system call is that application() dictate the underlying 143 | * operating system the criteria of recieving the data. Here, bind() system call 144 | * is telling the OS that if sender process sends the data destined to socket "/tmp/DemoSocket", 145 | * then such data needs to be delivered to this server process (the server process)*/ 146 | ret = bind(connection_socket, (const struct sockaddr *) &name, 147 | sizeof(struct sockaddr_un)); 148 | 149 | if (ret == -1) { 150 | perror("bind"); 151 | exit(EXIT_FAILURE); 152 | } 153 | 154 | printf("bind() call succeed\n"); 155 | /* 156 | * Prepare for accepting connections. The backlog size is set 157 | * to 20. So while one request is being processed other requests 158 | * can be waiting. 159 | * */ 160 | 161 | ret = listen(connection_socket, 20); 162 | if (ret == -1) { 163 | perror("listen"); 164 | exit(EXIT_FAILURE); 165 | } 166 | 167 | /*Add master socket to Monitored set of FDs*/ 168 | add_to_monitored_fd_set(connection_socket); 169 | 170 | /* This is the main loop for handling connections. */ 171 | /*All Server process usually runs 24 x 7. Good Servers should always up 172 | * and running and shold never go down. Have you ever seen Facebook Or Google 173 | * page failed to load ??*/ 174 | for (;;) { 175 | 176 | refresh_fd_set(&readfds); /*Copy the entire monitored FDs to readfds*/ 177 | /* Wait for incoming connection. */ 178 | printf("Waiting on select() sys call\n"); 179 | 180 | /* Call the select system call, server process blocks here. 181 | * Linux OS keeps this process blocked untill the connection initiation request Or 182 | * data requests arrives on any of the file Drscriptors in the 'readfds' set*/ 183 | 184 | select(get_max_fd() + 1, &readfds, NULL, NULL, NULL); 185 | 186 | if(FD_ISSET(connection_socket, &readfds)){ 187 | 188 | /*Data arrives on Master socket only when new client connects with the server (that is, 'connect' call is invoked on client side)*/ 189 | printf("New connection recieved recvd, accept the connection\n"); 190 | 191 | data_socket = accept(connection_socket, NULL, NULL); 192 | 193 | if (data_socket == -1) { 194 | perror("accept"); 195 | exit(EXIT_FAILURE); 196 | } 197 | 198 | printf("Connection accepted from client\n"); 199 | 200 | add_to_monitored_fd_set(data_socket); 201 | } 202 | else if(FD_ISSET(0, &readfds)){ 203 | memset(buffer, 0, BUFFER_SIZE); 204 | ret = read(0, buffer, BUFFER_SIZE); 205 | printf("Input read from console : %s\n", buffer); 206 | } 207 | else /* Data srrives on some other client FD*/ 208 | { 209 | /*Find the client which has send us the data request*/ 210 | i = 0, comm_socket_fd = -1; 211 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 212 | 213 | if(FD_ISSET(monitored_fd_set[i], &readfds)){ 214 | comm_socket_fd = monitored_fd_set[i]; 215 | 216 | /*Prepare the buffer to recv the data*/ 217 | memset(buffer, 0, BUFFER_SIZE); 218 | 219 | /* Wait for next data packet. */ 220 | /*Server is blocked here. Waiting for the data to arrive from client 221 | * 'read' is a blocking system call*/ 222 | printf("Waiting for data from the client\n"); 223 | ret = read(comm_socket_fd, buffer, BUFFER_SIZE); 224 | 225 | if (ret == -1) { 226 | perror("read"); 227 | exit(EXIT_FAILURE); 228 | } 229 | 230 | /* Add received summand. */ 231 | memcpy(&data, buffer, sizeof(int)); 232 | if(data == 0) { 233 | /* Send result. */ 234 | memset(buffer, 0, BUFFER_SIZE); 235 | sprintf(buffer, "Result = %d", client_result[i]); 236 | 237 | printf("sending final result back to client\n"); 238 | ret = write(comm_socket_fd, buffer, BUFFER_SIZE); 239 | if (ret == -1) { 240 | perror("write"); 241 | exit(EXIT_FAILURE); 242 | } 243 | 244 | /* Close socket. */ 245 | close(comm_socket_fd); 246 | client_result[i] = 0; 247 | remove_from_monitored_fd_set(comm_socket_fd); 248 | continue; /*go to select() and block*/ 249 | } 250 | client_result[i] += data; 251 | } 252 | } 253 | } 254 | } /*go to select() and block*/ 255 | 256 | /*close the master socket*/ 257 | close(connection_socket); 258 | remove_from_monitored_fd_set(connection_socket); 259 | printf("connection closed..\n"); 260 | 261 | /* Server should release resources before getting terminated. 262 | * Unlink the socket. */ 263 | 264 | unlink(SOCKET_NAME); 265 | exit(EXIT_SUCCESS); 266 | } 267 | -------------------------------------------------------------------------------- /AF_UNIX/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define SOCKET_NAME "/tmp/DemoSocket" 9 | #define BUFFER_SIZE 128 10 | 11 | int 12 | main(int argc, char *argv[]) 13 | { 14 | struct sockaddr_un name; 15 | 16 | #if 0 17 | struct sockaddr_un { 18 | sa_family_t sun_family; /* AF_UNIX */ 19 | char sun_path[108]; /* pathname */ 20 | }; 21 | #endif 22 | 23 | int ret; 24 | int connection_socket; 25 | int data_socket; 26 | int result; 27 | int data; 28 | char buffer[BUFFER_SIZE]; 29 | 30 | /*In case the program exited inadvertently on the last run, 31 | *remove the socket. 32 | **/ 33 | 34 | unlink(SOCKET_NAME); 35 | 36 | /* Create Master socket. */ 37 | 38 | /*SOCK_DGRAM for Datagram based communication*/ 39 | connection_socket = socket(AF_UNIX, SOCK_STREAM, 0); 40 | 41 | if (connection_socket == -1) { 42 | perror("socket"); 43 | exit(EXIT_FAILURE); 44 | } 45 | 46 | printf("Master socket created\n"); 47 | 48 | /*initialize*/ 49 | memset(&name, 0, sizeof(struct sockaddr_un)); 50 | 51 | /*Specify the socket Cridentials*/ 52 | name.sun_family = AF_UNIX; 53 | strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1); 54 | 55 | /* Bind socket to socket name.*/ 56 | /* Purpose of bind() system call is that application() dictate the underlying 57 | * operating system the criteria of recieving the data. Here, bind() system call 58 | * is telling the OS that if sender process sends the data destined to socket "/tmp/DemoSocket", 59 | * then such data needs to be delivered to this server process (the server process)*/ 60 | ret = bind(connection_socket, (const struct sockaddr *) &name, 61 | sizeof(struct sockaddr_un)); 62 | 63 | if (ret == -1) { 64 | perror("bind"); 65 | exit(EXIT_FAILURE); 66 | } 67 | 68 | printf("bind() call succeed\n"); 69 | /* 70 | * Prepare for accepting connections. The backlog size is set 71 | * to 20. So while one request is being processed other requests 72 | * can be waiting. 73 | * */ 74 | 75 | ret = listen(connection_socket, 20); 76 | if (ret == -1) { 77 | perror("listen"); 78 | exit(EXIT_FAILURE); 79 | } 80 | 81 | /* This is the main loop for handling connections. */ 82 | /*All Server process usually runs 24 x 7. Good Servers should always up 83 | * and running and shold never go down. Have you ever seen Facebook Or Google 84 | * page failed to load ??*/ 85 | for (;;) { 86 | 87 | /* Wait for incoming connection. */ 88 | printf("Waiting on accept() sys call\n"); 89 | 90 | data_socket = accept(connection_socket, NULL, NULL); 91 | 92 | if (data_socket == -1) { 93 | perror("accept"); 94 | exit(EXIT_FAILURE); 95 | } 96 | 97 | printf("Connection accepted from client\n"); 98 | 99 | result = 0; 100 | for(;;) { 101 | 102 | /*Prepare the buffer to recv the data*/ 103 | memset(buffer, 0, BUFFER_SIZE); 104 | 105 | /* Wait for next data packet. */ 106 | /*Server is blocked here. Waiting for the data to arrive from client 107 | * 'read' is a blocking system call*/ 108 | printf("Waiting for data from the client\n"); 109 | ret = read(data_socket, buffer, BUFFER_SIZE); 110 | 111 | if (ret == -1) { 112 | perror("read"); 113 | exit(EXIT_FAILURE); 114 | } 115 | 116 | /* Add received summand. */ 117 | memcpy(&data, buffer, sizeof(int)); 118 | if(data == 0) break; 119 | result += data; 120 | } 121 | 122 | /* Send result. */ 123 | memset(buffer, 0, BUFFER_SIZE); 124 | sprintf(buffer, "Result = %d", result); 125 | 126 | printf("sending final result back to client\n"); 127 | ret = write(data_socket, buffer, BUFFER_SIZE); 128 | if (ret == -1) { 129 | perror("write"); 130 | exit(EXIT_FAILURE); 131 | } 132 | 133 | /* Close socket. */ 134 | close(data_socket); 135 | } 136 | 137 | /*close the master socket*/ 138 | close(connection_socket); 139 | printf("connection closed..\n"); 140 | 141 | /* Server should release resources before getting terminated. 142 | * Unlink the socket. */ 143 | 144 | unlink(SOCKET_NAME); 145 | exit(EXIT_SUCCESS); 146 | } 147 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SerVerDesign 2 | Server Designing in C 3 | -------------------------------------------------------------------------------- /mps/multi_process_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../sts/common.h" 9 | 10 | #define SERVER_PORT 2000 /*Server process is running on this port no. Client has to send data to this port no*/ 11 | 12 | test_struct_t test_struct; 13 | result_struct_t res_struct; 14 | char data_buffer[1024]; 15 | 16 | struct client_info{ 17 | 18 | int comm_socket_fd; 19 | struct sockaddr_in client_addr; 20 | }; 21 | 22 | static void * 23 | service_client_module(void *arg){ 24 | 25 | struct client_info *client_info_t = (struct client_info *)arg; 26 | int comm_socket_fd = client_info_t->comm_socket_fd; 27 | 28 | int sent_recv_bytes = 0; 29 | 30 | struct sockaddr_in client_addr; 31 | 32 | client_addr = client_info_t->client_addr; 33 | int addr_len = sizeof(struct sockaddr_in); 34 | 35 | /*Write send and recieve client data logic here*/ 36 | while(1){ 37 | memset(data_buffer, 0, sizeof(data_buffer)); 38 | sent_recv_bytes = recvfrom(comm_socket_fd, (char *)data_buffer, sizeof(data_buffer), 0, (struct sockaddr *)&client_addr, &addr_len); 39 | 40 | printf("Server recvd %d bytes from client %s:%u\n", sent_recv_bytes, 41 | inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 42 | 43 | if(sent_recv_bytes == 0){ 44 | /*If server recvs empty msg from client, server may close the connection and wait 45 | * for fresh new connection from client - same or different*/ 46 | close(comm_socket_fd); 47 | free(client_info_t); 48 | break; /*goto step 5*/ 49 | } 50 | 51 | test_struct_t *client_data = (test_struct_t *)data_buffer; 52 | 53 | /* If the client sends a special msg to server, then server close the client connection 54 | * for forever*/ 55 | /*Step 9 */ 56 | if(client_data->a == 0 && client_data->b ==0){ 57 | 58 | close(comm_socket_fd); 59 | printf("Server closes connection with client : %s:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 60 | free(client_info_t); 61 | /*Goto state machine State 1*/ 62 | break;/*Get out of inner while loop, server is done with this client, time to check for new connection request by executing selct()*/ 63 | } 64 | 65 | result_struct_t result; 66 | result.c = client_data->a + client_data->b; 67 | 68 | /* Server replying back to client now*/ 69 | sent_recv_bytes = sendto(comm_socket_fd, (char *)&result, sizeof(result_struct_t), 0, 70 | (struct sockaddr *)&client_addr, sizeof(struct sockaddr)); 71 | 72 | printf("Server sent %d bytes in reply to client\n", sent_recv_bytes); 73 | } 74 | } 75 | 76 | 77 | void 78 | setup_tcp_server_communication(){ 79 | 80 | /*Step 1 : Initialization*/ 81 | /*Socket handle and other variables*/ 82 | int master_sock_tcp_fd = 0, /*Master socket file descriptor, used to accept new client connection only, no data exchange*/ 83 | sent_recv_bytes = 0, 84 | addr_len = 0, 85 | opt = 1; 86 | 87 | int comm_socket_fd = 0; /*client specific communication socket file descriptor, used for only data exchange/communication between client and server*/ 88 | fd_set readfds; /*Set of file descriptor on which select() polls. Select() unblocks whever data arrives on any fd present in this set*/ 89 | /*variables to hold server information*/ 90 | struct sockaddr_in server_addr, /*structure to store the server and client info*/ 91 | client_addr; 92 | 93 | /*step 2: tcp master socket creation*/ 94 | if ((master_sock_tcp_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1) 95 | { 96 | printf("socket creation failed\n"); 97 | exit(1); 98 | } 99 | 100 | /*Step 3: specify server Information*/ 101 | server_addr.sin_family = AF_INET;/*This socket will process only ipv4 network packets*/ 102 | server_addr.sin_port = SERVER_PORT;/*Server will process any data arriving on port no 2000*/ 103 | server_addr.sin_addr.s_addr = INADDR_ANY; //3232249957; //( = 192.168.56.101); /*Server's IP address, means, Linux will send all data whose destination address = address of any local interface of this machine, in this case it is 192.168.56.101*/ 104 | 105 | addr_len = sizeof(struct sockaddr); 106 | 107 | /* Bind the server. Binding means, we are telling kernel(OS) that any data 108 | * you recieve with dest ip address = 192.168.56.101, and tcp port no = 2000, pls send that data to this process 109 | * bind() is a mechnism to tell OS what kind of data server process is interested in to recieve. Remember, server machine 110 | * can run multiple server processes to process different data and service different clients. Note that, bind() is 111 | * used on server side, not on client side*/ 112 | 113 | if (bind(master_sock_tcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 114 | { 115 | printf("socket bind failed\n"); 116 | return; 117 | } 118 | 119 | /*Step 4 : Tell the Linux OS to maintain the queue of max length to Queue incoming 120 | * client connections.*/ 121 | if (listen(master_sock_tcp_fd, 5)<0) 122 | { 123 | printf("listen failed\n"); 124 | return; 125 | } 126 | 127 | while(1){ 128 | 129 | /*Step 5 : initialze and dill readfds*/ 130 | FD_ZERO(&readfds); /* Initialize the file descriptor set*/ 131 | FD_SET(master_sock_tcp_fd, &readfds); /*Add the socket to this set on which our server is running*/ 132 | 133 | printf("blocked on select System call...\n"); 134 | 135 | /*Step 6 : Wait for client connection*/ 136 | /*state Machine state 1 */ 137 | select(master_sock_tcp_fd + 1, &readfds, NULL, NULL, NULL); /*Call the select system cal, server process blocks here. Linux OS keeps this process blocked untill the data arrives on any of the file Drscriptors in the 'readfds' set*/ 138 | 139 | /*Some data on some fd present in monitored fd set has arrived, Now check on which File descriptor the data arrives, and process accordingly*/ 140 | 141 | /*If Data arrives on master socket FD*/ 142 | if (FD_ISSET(master_sock_tcp_fd, &readfds)) 143 | { 144 | /*Data arrives on Master socket only when new client connects with the server (that is, 'connect' call is invoked on client side)*/ 145 | printf("New connection recieved recvd, accept the connection. Client and Server completes TCP-3 way handshake at this point\n"); 146 | 147 | /* step 7 : accept() returns a new temporary file desriptor(fd). Server uses this 'comm_socket_fd' fd for the rest of the 148 | * life of connection with this client to send and recieve msg. Master socket is used only for accepting 149 | * new client's connection and not for data exchange with the client*/ 150 | /* state Machine state 2*/ 151 | comm_socket_fd = accept(master_sock_tcp_fd, (struct sockaddr *)&client_addr, &addr_len); 152 | if(comm_socket_fd < 0){ 153 | 154 | /* if accept failed to return a socket descriptor, display error and exit */ 155 | printf("accept error : errno = %d\n", errno); 156 | exit(0); 157 | } 158 | 159 | printf("Connection accepted from client : %s:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 160 | 161 | /* Create a new child process to service this new client*/ 162 | /* Server infinite loop for servicing the client*/ 163 | 164 | /*Fill the client info*/ 165 | struct client_info *client_info_t = calloc(1, sizeof(struct client_info)); 166 | client_info_t->comm_socket_fd = comm_socket_fd; 167 | memcpy(&client_info_t->client_addr, &client_addr, sizeof(struct sockaddr_in)); 168 | 169 | /*Finally launch the child process to service this particular client. */ 170 | /*fork() returns 0 to child process, and new child process PID to parent process. Hence below if check 171 | * will be true only for child process, therefore service_client_module() is executed only by child process*/ 172 | 173 | if(fork() == 0){ 174 | /*After fork(), child process execution flow comes here*/ 175 | printf("New child process created....\n"); 176 | service_client_module(client_info_t); 177 | printf("child process terminates\n"); 178 | exit(0); 179 | } 180 | /*After fork(), parent process execution flow directly comes here because fork returns non zero child process 181 | * id to parent*/ 182 | } 183 | 184 | }/*step 10 : wait for new client request again*/ 185 | } 186 | 187 | int 188 | main(int argc, char **argv){ 189 | 190 | setup_tcp_server_communication(); 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /mts/multi_threaded_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../sts/common.h" 9 | #include 10 | 11 | #define SERVER_PORT 2000 /*Server process is running on this port no. Client has to send data to this port no*/ 12 | 13 | test_struct_t test_struct; 14 | result_struct_t res_struct; 15 | char data_buffer[1024]; 16 | 17 | struct client_info{ 18 | 19 | int comm_socket_fd; 20 | struct sockaddr_in client_addr; 21 | }; 22 | 23 | static void * 24 | service_client_module(void *arg){ 25 | 26 | struct client_info *client_info_t = (struct client_info *)arg; 27 | int comm_socket_fd = client_info_t->comm_socket_fd; 28 | 29 | int sent_recv_bytes = 0; 30 | 31 | struct sockaddr_in client_addr; 32 | 33 | client_addr = client_info_t->client_addr; 34 | int addr_len = sizeof(struct sockaddr_in); 35 | 36 | /*Write send and recieve client data logic here*/ 37 | printf("New thread created ....\n"); 38 | while(1){ 39 | memset(data_buffer, 0, sizeof(data_buffer)); 40 | sent_recv_bytes = recvfrom(comm_socket_fd, (char *)data_buffer, sizeof(data_buffer), 0, (struct sockaddr *)&client_addr, &addr_len); 41 | 42 | printf("Server recvd %d bytes from client %s:%u\n", sent_recv_bytes, 43 | inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 44 | 45 | if(sent_recv_bytes == 0){ 46 | /*If server recvs empty msg from client, server may close the connection and wait 47 | * for fresh new connection from client - same or different*/ 48 | close(comm_socket_fd); 49 | free(client_info_t); 50 | break; 51 | } 52 | 53 | test_struct_t *client_data = (test_struct_t *)data_buffer; 54 | 55 | /* If the client sends a special msg to server, then server close the client connection 56 | * for forever*/ 57 | /*Step 9 */ 58 | if(client_data->a == 0 && client_data->b ==0){ 59 | 60 | printf("Server closes connection with client : %s:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 61 | free(client_info_t); 62 | close(comm_socket_fd); 63 | break; 64 | } 65 | 66 | result_struct_t result; 67 | result.c = client_data->a + client_data->b; 68 | 69 | /* Server replying back to client now*/ 70 | sent_recv_bytes = sendto(comm_socket_fd, (char *)&result, sizeof(result_struct_t), 0, 71 | (struct sockaddr *)&client_addr, sizeof(struct sockaddr)); 72 | 73 | printf("Server sent %d bytes in reply to client\n", sent_recv_bytes); 74 | } 75 | } 76 | 77 | 78 | void 79 | setup_tcp_server_communication(){ 80 | 81 | /*Step 1 : Initialization*/ 82 | /*Socket handle and other variables*/ 83 | int master_sock_tcp_fd = 0, /*Master socket file descriptor, used to accept new client connection only, no data exchange*/ 84 | sent_recv_bytes = 0, 85 | addr_len = 0, 86 | opt = 1; 87 | 88 | int comm_socket_fd = 0; /*client specific communication socket file descriptor, used for only data exchange/communication between client and server*/ 89 | fd_set readfds; /*Set of file descriptor on which select() polls. Select() unblocks whever data arrives on any fd present in this set*/ 90 | /*variables to hold server information*/ 91 | struct sockaddr_in server_addr, /*structure to store the server and client info*/ 92 | client_addr; 93 | 94 | /*step 2: tcp master socket creation*/ 95 | if ((master_sock_tcp_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1) 96 | { 97 | printf("socket creation failed\n"); 98 | exit(1); 99 | } 100 | 101 | /*Step 3: specify server Information*/ 102 | server_addr.sin_family = AF_INET;/*This socket will process only ipv4 network packets*/ 103 | server_addr.sin_port = SERVER_PORT;/*Server will process any data arriving on port no 2000*/ 104 | server_addr.sin_addr.s_addr = INADDR_ANY; //3232249957; //( = 192.168.56.101); /*Server's IP address, means, Linux will send all data whose destination address = address of any local interface of this machine, in this case it is 192.168.56.101*/ 105 | 106 | addr_len = sizeof(struct sockaddr); 107 | 108 | /* Bind the server. Binding means, we are telling kernel(OS) that any data 109 | * you recieve with dest ip address = 192.168.56.101, and tcp port no = 2000, pls send that data to this process 110 | * bind() is a mechnism to tell OS what kind of data server process is interested in to recieve. Remember, server machine 111 | * can run multiple server processes to process different data and service different clients. Note that, bind() is 112 | * used on server side, not on client side*/ 113 | 114 | if (bind(master_sock_tcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 115 | { 116 | printf("socket bind failed\n"); 117 | return; 118 | } 119 | 120 | /*Step 4 : Tell the Linux OS to maintain the queue of max length to Queue incoming 121 | * client connections.*/ 122 | if (listen(master_sock_tcp_fd, 5)<0) 123 | { 124 | printf("listen failed\n"); 125 | return; 126 | } 127 | 128 | while(1){ 129 | 130 | /*Step 5 : initialze and dill readfds*/ 131 | FD_ZERO(&readfds); /* Initialize the file descriptor set*/ 132 | FD_SET(master_sock_tcp_fd, &readfds); /*Add the socket to this set on which our server is running*/ 133 | 134 | printf("blocked on select System call...\n"); 135 | 136 | /*Step 6 : Wait for client connection*/ 137 | /*state Machine state 1 */ 138 | select(master_sock_tcp_fd + 1, &readfds, NULL, NULL, NULL); /*Call the select system cal, server process blocks here. Linux OS keeps this process blocked untill the data arrives on any of the file Drscriptors in the 'readfds' set*/ 139 | 140 | /*Some data on some fd present in monitored fd set has arrived, Now check on which File descriptor the data arrives, and process accordingly*/ 141 | 142 | /*If Data arrives on master socket FD*/ 143 | /*Actually no need of below check, you can presume only master_sock_tcp_fd will be activated, since it is 144 | * the only FD present in readfds set*/ 145 | if (FD_ISSET(master_sock_tcp_fd, &readfds)) 146 | { 147 | /*Data arrives on Master socket only when new client connects with the server (that is, 'connect' call is invoked on client side)*/ 148 | printf("New connection recieved recvd, accept the connection. Client and Server completes TCP-3 way handshake at this point\n"); 149 | 150 | /* step 7 : accept() returns a new temporary file desriptor(fd). Server uses this 'comm_socket_fd' fd for the rest of the 151 | * life of connection with this client to send and recieve msg. Master socket is used only for accepting 152 | * new client's connection and not for data exchange with the client*/ 153 | /* state Machine state 2*/ 154 | comm_socket_fd = accept(master_sock_tcp_fd, (struct sockaddr *)&client_addr, &addr_len); 155 | if(comm_socket_fd < 0){ 156 | 157 | /* if accept failed to return a socket descriptor, display error and exit */ 158 | printf("accept error : errno = %d\n", errno); 159 | exit(0); 160 | } 161 | 162 | printf("Connection accepted from client : %s:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 163 | 164 | /* Create a new thread to service this new client*/ 165 | /* Server infinite loop for servicing the client*/ 166 | pthread_t client_thread; 167 | pthread_attr_t attr; 168 | 169 | pthread_attr_init(&attr); 170 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 171 | 172 | /*Fill the client info*/ 173 | struct client_info *client_info_t = calloc(1, sizeof(struct client_info)); 174 | client_info_t->comm_socket_fd = comm_socket_fd; 175 | memcpy(&client_info_t->client_addr, &client_addr, sizeof(struct sockaddr_in)); 176 | 177 | /*Finally launch the thread to service this particular client. Last arg to pthread_create is the void * 178 | * which could be any structure containing information our thread need. In this case, we provide client info 179 | * which needs to be serviced by the server*/ 180 | pthread_create(&client_thread, &attr, service_client_module, (void *)client_info_t); 181 | } 182 | 183 | }/*step 10 : wait for new client request again*/ 184 | } 185 | 186 | int 187 | main(int argc, char **argv){ 188 | 189 | setup_tcp_server_communication(); 190 | return 0; 191 | } 192 | -------------------------------------------------------------------------------- /project/node0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define TRUE 1 4 | #define FALSE 0 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #if 1 16 | #define N 2 17 | #define ip1 "192.168.20.1" 18 | #define ip2 "192.168.20.2" 19 | #endif 20 | #define tablesize 100 21 | 22 | 23 | struct node 24 | { 25 | int data; 26 | struct node *link; 27 | }; 28 | int num=0; 29 | #if 0 30 | int N=2; 31 | char ip1[20]; 32 | char ip2[20]; 33 | #endif 34 | struct HTEntry 35 | { 36 | int data; 37 | struct node *link; 38 | 39 | }; 40 | 41 | struct HTEntry Htable[tablesize]; 42 | 43 | 44 | 45 | //----------------------hash table functions----------------- 46 | 47 | void initialiseHashtable() 48 | { 49 | 50 | int i=0; 51 | 52 | for(i=0;ilink!=NULL) 65 | { 66 | 67 | start=start->link; 68 | } 69 | start->link = (struct node *)malloc(sizeof(struct node)); 70 | start=start->link; 71 | start->link=NULL; 72 | start->data = data; 73 | } 74 | 75 | 76 | 77 | 78 | int addToHashtable(int key,int data) 79 | { 80 | 81 | int maxlimit_key = (tablesize-1)*N+num; 82 | int relativeIndex,returnvalue; 83 | 84 | if(key % N == num && key <= maxlimit_key && key > -1) 85 | { 86 | // Key must satisfy the eqn K % N = num then only its for current node 87 | 88 | relativeIndex = (key - num)/N; 89 | 90 | // case 1 : if hash table entry is empty 91 | 92 | if(Htable[relativeIndex].data==0) 93 | { 94 | 95 | Htable[relativeIndex].data = data; 96 | returnvalue=1; 97 | } 98 | 99 | 100 | // case 2 : if exactly one entry in particular entry of hashtable (Ist Collision) 101 | 102 | else if(Htable[relativeIndex].data!=0 && Htable[relativeIndex].link==NULL) 103 | { 104 | 105 | Htable[relativeIndex].link = (struct node *)malloc(sizeof(struct node)); 106 | Htable[relativeIndex].link->data = data; 107 | Htable[relativeIndex].link->link = NULL; 108 | returnvalue=1; 109 | } 110 | 111 | // case 3: Subsequent Collisions 112 | 113 | else 114 | { 115 | appendNode(Htable[relativeIndex].link,data); 116 | returnvalue=1; 117 | } 118 | 119 | printf("\nRESULT: AT KEY : %d, VALUE INSERTED : %d IN HASH TABLE SUCCESS\nENTER NEW GET/PUT REQUEST :",key,data); 120 | } 121 | 122 | else 123 | { 124 | printf("\nERROR:KEY = %d,VALUE = %d CANNOT ADD IN TABLE, MAX KEY LIMIT = %d\nENTER NEW GET/PUT REQUEST :",key,data,maxlimit_key); 125 | 126 | returnvalue=0; 127 | } 128 | return returnvalue; 129 | } 130 | 131 | 132 | 133 | int fetchValueFromHT(int key) //fun() to retrieve value corresponding to a key from hash table 134 | { 135 | 136 | int relativeIndex = (key-num)/N,return_value; //calculate index of key in hash table 137 | 138 | if(Htable[relativeIndex].link == NULL) //first value in the list 139 | return_value = Htable[relativeIndex].data; 140 | 141 | else 142 | { 143 | struct node *start = Htable[relativeIndex].link; 144 | while(start->link!=NULL) 145 | start = start->link; // progess pointer to last element 146 | return_value = start->data; //assign last element 147 | } 148 | return return_value; 149 | } 150 | 151 | 152 | void displayHtable() 153 | { 154 | 155 | int from_key = num,to_key = (tablesize-1)*N + num; 156 | 157 | if(from_key > to_key) 158 | { 159 | 160 | int temp = from_key; 161 | from_key = to_key; 162 | to_key = temp ; 163 | } 164 | 165 | printf("\n-----Hash Table Contents(%d--%d)------------\n",from_key,to_key); 166 | 167 | if(from_key % N == num && to_key % N == num) 168 | { 169 | 170 | int i,from=(from_key - num)/N,to = (to_key - num)/N,fetchValue,key; 171 | 172 | for(i=from;i<=to;i++) 173 | { 174 | 175 | key = i*N+num; 176 | fetchValue = fetchValueFromHT(key); 177 | if(fetchValue !=0) 178 | printf("\nkey : %d ===== value : %d\n",key,fetchValueFromHT(key)); 179 | } 180 | } 181 | else 182 | printf("invalid keys , hash table cannot be displayed\n"); 183 | 184 | printf("-----------------------------------------------------\nENTER NEW GET/PUT REQUEST:"); 185 | } 186 | 187 | 188 | 189 | 190 | //--------------------------------------- hash table functions ---------------------------------------------- 191 | 192 | 193 | struct machine_id 194 | { 195 | char *ip_address; 196 | int tcpportno; 197 | int udpportno; 198 | } 199 | node[20]; 200 | 201 | 202 | int forYou(int num,char request[]) //check whether request is for current node or not 203 | { 204 | 205 | int k; 206 | if(getOrPut(request)==1) //check whether request is get or put 207 | 208 | k = extractKeyFromGet(request); 209 | else 210 | k=extractKeyFromPut(request); 211 | 212 | if((k % N) == num) 213 | 214 | return 1; //return 1 if for current node 215 | else 216 | return 0; //return 0 if not for current node 217 | } 218 | 219 | 220 | // ----------------------- String handling functions--------------------------------- 221 | 222 | 223 | int extractKeyFromPut(char request[]) //method for extracting key from put request. 224 | { 225 | 226 | char *b = strstr(request, "("),*c = strstr(request, ","); 227 | int position = b - request,position1 = c - request,k; 228 | char to[4]; 229 | strncpy(to, request + position+1, position1 - position); //for extracting the first integer no. k of put(k,x) 230 | 231 | k = atoi(to); //converting to int 232 | fflush(stdout); 233 | return k; 234 | } 235 | 236 | int extractKeyFromGet(char request[]) //method for extracting key from get request. 237 | { 238 | 239 | char *b = strstr(request, "("),*c = strstr(request, ")"); 240 | int position = b - request,position1 = c - request,k; 241 | char to[4]; 242 | strncpy(to, request + position+1, position1 - position); //for extracting the first integer no. k of put(k,x) 243 | k = atoi(to); 244 | fflush(stdout); 245 | return k; 246 | } 247 | 248 | 249 | int extractValueFromPut(char request[]) 250 | { 251 | 252 | char *b = strstr(request, ","),*c = strstr(request, ")"); 253 | int position = b - request,position1 = c - request,k; 254 | char to[32]; 255 | memset(to, 0 , 32); 256 | strncpy(to, request + position+1, position1 - position); //for extracting the first integer no. k of put(k,x) 257 | k = atoi(to); 258 | return k; 259 | } 260 | 261 | 262 | void itoa(int n,char buff[]) 263 | { 264 | int i =0,j; 265 | 266 | if(n==0) 267 | { 268 | 269 | buff[0] = '0'; 270 | buff[1] = '\0'; 271 | i=1; 272 | } 273 | 274 | while(n>0) 275 | { 276 | 277 | int rem = n %10; 278 | n=n/10; 279 | buff[i]=rem+48; 280 | i++; 281 | } 282 | 283 | buff[i]='\0'; 284 | 285 | for(j=0;jh_addr); //host->h_addr gives address of host 403 | bzero(&(server_addr.sin_zero),8); 404 | 405 | #if 0 406 | memset(&msg, 0 , sizeof(struct msghdr)); 407 | memset(&iov, 0, sizeof(struct iovec)); 408 | msg.msg_name = (void *)&server_addr; 409 | msg.msg_namelen = sizeof(struct sockaddr_in); 410 | printf("sendString = %s\n", sendString); 411 | iov.iov_base = (void *)sendString; 412 | iov.iov_len = strlen(sendString); 413 | msg.msg_iov = &iov; 414 | printf("len = %d\n", strlen(sendString)); 415 | msg.msg_iovlen = 1; 416 | msg.msg_control = NULL; 417 | msg.msg_controllen = 0; 418 | msg.msg_flags = 0; 419 | #endif 420 | 421 | sendto(sock, sendString, strlen(sendString), 0,(struct sockaddr *)&server_addr, sizeof(struct sockaddr)); 422 | 423 | //sendto() function shall send a message through a connectionless-mode socket. 424 | printf("\nFORWARD REQUEST : '%s' has been forwarded to node ---->%d\n",sendString,destination_node); 425 | close(sock); 426 | } 427 | 428 | int getOrPut(char rec_buff[]) //method to check whether put or get request. 429 | { 430 | 431 | if(rec_buff[0] == 'g' || rec_buff[0] == 'G') 432 | return 1; 433 | else 434 | return 0; 435 | } 436 | 437 | int main() 438 | { 439 | 440 | int opt=TRUE,TransferValue = 0; 441 | int master_socket,sock_udp; 442 | struct sockaddr_in address,server_addr_udp,client_addr; 443 | int addrlen,addr_len; 444 | int new_socket,maxfd; 445 | int loop,valread; 446 | //int num; 447 | char buffer[1025],replyBuffer[1024]; //data buffer of 1K 448 | #if 0 449 | printf("Enter total number of nodes: "); 450 | scanf("%d",&N); 451 | printf("Enter the node number:"); 452 | scanf("%d",&num); 453 | printf("Enter current node IP:"); 454 | scanf("%s",ip1); 455 | printf("Enter next node IP:"); 456 | scanf("%s",ip2); 457 | #endif 458 | fd_set readfds; // Socket file descriptors we want to wake up for, using select() 459 | 460 | node[num].ip_address = ip1; 461 | node[num].tcpportno = 2000+num*2; 462 | node[num].udpportno = node[num].tcpportno+1; 463 | node[(num+1)%N].ip_address = ip2; 464 | node[(num+1)%N].tcpportno = 2000+(num+1)%N*2; 465 | node[(num+1)%N].udpportno = node[(num+1)%N].tcpportno+1; 466 | 467 | //working with UDP 468 | 469 | system("clear"); 470 | printf (" INSTRUCTIONS \n\n =================NODE %d=======================\n",num); 471 | puts(" 1.'put' request format : PUT(,)\n"); 472 | puts(" 2.'get' request format : GET()\n"); 473 | puts(" 3.To print Hash Table : 'r'\n"); 474 | puts("-----------------------------------\n\nENTER GET/PUT REQUEST :"); 475 | 476 | initialiseHashtable(); 477 | if ((sock_udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) //Creating a UDP Socket 478 | { 479 | 480 | perror("Socket"); 481 | exit(1); 482 | } 483 | //current node address 484 | server_addr_udp.sin_family = AF_INET; //AF_INET represents the address family INET for IPv4 protocol 485 | server_addr_udp.sin_port = htons(node[num].udpportno);//convert port in host byte order to N/W byte order 486 | server_addr_udp.sin_addr.s_addr = INADDR_ANY; 487 | bzero(&(server_addr_udp.sin_zero),8); //bzero() sets all values in a buffer to zero. 488 | 489 | 490 | if (setsockopt(sock_udp, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt))<0) 491 | { 492 | 493 | 494 | perror("setsockopt"); 495 | exit(EXIT_FAILURE); 496 | } 497 | if (setsockopt(sock_udp, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(opt))<0) 498 | { 499 | 500 | 501 | perror("setsockopt"); 502 | exit(EXIT_FAILURE); 503 | } 504 | #if 1 505 | if (bind(sock_udp,(struct sockaddr *)&server_addr_udp, sizeof(struct sockaddr)) == -1)//Binding UDP socket 506 | { 507 | perror("Bind"); 508 | exit(1); 509 | } 510 | #endif 511 | addr_len = sizeof(struct sockaddr); 512 | // working with TCP 513 | if ((master_socket = socket(AF_INET,SOCK_STREAM,0))==0) //Create TCP Socket 514 | { 515 | perror("Create master_socket"); 516 | exit(EXIT_FAILURE); 517 | } 518 | 519 | //set master socket to allow multiple connections 520 | if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt))<0) 521 | { 522 | 523 | 524 | perror("setsockopt"); 525 | exit(EXIT_FAILURE); 526 | } 527 | #if 1 528 | if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(opt))<0) 529 | { 530 | 531 | 532 | perror("setsockopt"); 533 | exit(EXIT_FAILURE); 534 | } 535 | #endif 536 | //current node address for tcp 537 | address.sin_family = AF_INET; 538 | address.sin_addr.s_addr = INADDR_ANY; 539 | address.sin_port = htons(node[num].tcpportno); 540 | 541 | if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0) //bind the socket to port 542 | { 543 | perror("bind"); 544 | exit(EXIT_FAILURE); 545 | } 546 | if (listen(master_socket, 5)<0) //Specify maximum of 5 pending connections for the master socket 547 | { 548 | perror("listen"); 549 | exit(EXIT_FAILURE); 550 | } 551 | 552 | 553 | 554 | while (1) { 555 | 556 | FD_ZERO(&readfds); //clears out the fd_set-readfds, so that it doesn't contain any file descriptors. 557 | 558 | 559 | FD_SET(sock_udp, &readfds); //adds file descriptor "sock_udp" to the fd_set,select will return 560 | 561 | 562 | FD_SET(master_socket, &readfds); //adds file descriptor "master_socket" to the fd_set,select will return 563 | 564 | 565 | FD_SET(0,&readfds); // to read from standard input 566 | 567 | 568 | 569 | if(master_socket > sock_udp) 570 | maxfd = master_socket; 571 | else 572 | maxfd = sock_udp; 573 | 574 | select(maxfd+1, &readfds, NULL, NULL, NULL); 575 | 576 | if (FD_ISSET(master_socket, &readfds)) 577 | { 578 | 579 | /* Open the new socket as 'new_socket' */ 580 | 581 | addrlen=sizeof(address); 582 | 583 | if ((new_socket = accept(master_socket, (struct sockaddr *)&address, &addrlen))<0) 584 | { 585 | 586 | /* if accept failed to return a socket descriptor, display error and exit */ 587 | perror("accept"); 588 | exit(EXIT_FAILURE); 589 | } 590 | 591 | /* inform user of socket number - used in send and receive commands */ 592 | 593 | if(TransferValue != 0) 594 | { // means put request was made 595 | 596 | 597 | // means put request was made on this node , and this node need to supply the value 'TransferValue' back to client 598 | 599 | itoa(TransferValue,replyBuffer);// as sooon as conection is made, TCP server send value to client 600 | send(new_socket,replyBuffer,strlen(replyBuffer), 0); 601 | read(new_socket, buffer, 1024); 602 | printf("\n%s\n",buffer); 603 | TransferValue = 0 ; 604 | close(new_socket); 605 | } 606 | else 607 | { 608 | // means get request was made and tcp server is only need to recieve value from client 609 | if ((valread = read(new_socket, buffer, 1024)) < 0) 610 | close(new_socket); 611 | 612 | else 613 | { 614 | /* set the terminating NULL byte on the end of the data read */ 615 | buffer[valread] = 0; 616 | printf("\n%s\n",buffer); //m 617 | } 618 | close(new_socket); 619 | } 620 | } 621 | 622 | if(FD_ISSET(sock_udp, &readfds)) /*Check udp_socket has data available to be read */ 623 | { 624 | char rec_buff[5000]; 625 | int len = recvfrom(sock_udp,rec_buff,5000,0,(struct sockaddr *)&client_addr, &addr_len); 626 | //recvfrom() function receives a message 627 | rec_buff[len] = '\0'; 628 | printf("\n--------\nUDP PACKET RECIEVED FROM (IP ADDRESS : %s , PORT NO : %d , NODE NO : %d) : ", 629 | inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),extractNodeno(rec_buff)); 630 | 631 | //inet_ntoa() converts a n/w address in a struct in_addr to a dots-and-numbers format string 632 | printf("%s\n",rec_buff); 633 | 634 | // Either get request is recieved or put request is recieved 635 | 636 | // Check whether the req is to be forwarded or to be processed by the current node itself 637 | 638 | if(forYou(num,rec_buff) == 0) 639 | { 640 | 641 | forwardUDP(num+1,rec_buff); // forward the request as it is to the next node 642 | puts("\n---------------------------------------\nENTER NEW GET/PUT REQUEST:"); 643 | } 644 | else 645 | { 646 | printf("\nPROCESSING THE REQUEST ON THE CURRENT NODE : \n") 647 | ; 648 | // this is the node where get/put request is to be processed, so fetching 649 | // extracting key from request 650 | 651 | int key = extractKeyFromPut(rec_buff),nodeno = extractNodeno(rec_buff); 652 | 653 | // establish TCP conectiom with server whether it is get Or put message 654 | 655 | int sock, bytes_recieved; 656 | char send_data[1024],recv_data[1024]; 657 | char flag = rec_buff[strlen(rec_buff)-2]; //extracted flag value from request 658 | struct hostent *host; 659 | struct sockaddr_in server_addr; 660 | host = gethostbyname(extractIpaddress(rec_buff,'[',','));//extracting originator IP from request 661 | 662 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 663 | { 664 | 665 | perror("Socket"); 666 | exit(1); 667 | } 668 | //To which connection is to be made 669 | server_addr.sin_family = AF_INET; 670 | server_addr.sin_port = htons(extractValueFromPut(rec_buff)); 671 | //same format put(key,value) initially 672 | //now format put(key,port) 673 | server_addr.sin_addr = *((struct in_addr *)host->h_addr); 674 | bzero(&(server_addr.sin_zero),8); 675 | 676 | if (connect(sock, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1) //Make Connec 677 | { 678 | 679 | perror("Connect"); 680 | exit(1); 681 | } 682 | if(flag == 's') //Get request and the value is to be fetched from hash table 683 | { 684 | 685 | int valuefetched = fetchValueFromHT(key); 686 | if(valuefetched !=0) 687 | { 688 | 689 | strcpy(send_data,"value = "); 690 | char valuebuff[6],nodebuff[4]; 691 | itoa(valuefetched,valuebuff); 692 | strcat(send_data,valuebuff); 693 | strcat(send_data,". Value retrieved from node no : "); 694 | itoa(num,nodebuff); 695 | strcat(send_data,nodebuff); 696 | strcat(send_data,"\n-------------------\nENTER NEW GET/PUT REQUEST:"); 697 | } 698 | else 699 | { 700 | strcpy(send_data,"RESULT: No hash entry to this key on node no : "); 701 | char nodebuff[4]; 702 | itoa(num,nodebuff); 703 | strcat(send_data,nodebuff); 704 | strcat(send_data,"\n--------------------\nENTER NEW GET/PUT REQUEST :"); 705 | 706 | } 707 | send(sock,send_data,strlen(send_data), 0); //Send the fetched value 708 | printf("\n KEY RECIEVED %d ,\nREQUEST ORIGINALLY INVOKED ON NODE %d , flag recieved = %c . VALUE SUPPLIED BACK ON TCP CONNECTION.\nENTER NEW GET/PUT REQUEST:",key,nodeno,rec_buff[strlen(rec_buff)-2]); 709 | } 710 | else 711 | { 712 | bytes_recieved=recv(sock,recv_data,1024,0); //Receiving Put value 713 | recv_data[bytes_recieved] = '\0'; 714 | printf("\n KEY RECIEVED IS: %d ,\nREQUEST ORIGINALLY INVOKED ON NODE %d , flag recieved = %c\n",key,nodeno,rec_buff[strlen(rec_buff)-2]); 715 | 716 | printf("\nVALUE RECIEVED (ON TCP CONNECTION) FROM NODE NO %d = %s " ,nodeno, recv_data); 717 | // now insert the key,value in hash table of this node and send confirmation message back to parent node 718 | // on which the request was originallly invoked by the user 719 | 720 | if(addToHashtable(key,atoi(recv_data))) 721 | strcpy(send_data,"RESULT: put operation has been done successfully. Value added on node no :"); 722 | else 723 | strcpy(send_data,"RESULT: put operation failed. Maximum key limit Exceeded on node number "); 724 | char nodebuff[4]; 725 | itoa(num,nodebuff); 726 | strcat(send_data,nodebuff); 727 | strcat(send_data,".\n------------------------------------\nENTER NEW GET/PUT REQUEST :"); 728 | send(sock,send_data,strlen(send_data), 0); 729 | 730 | } 731 | close(sock); 732 | fflush(stdout); 733 | } // else ends 734 | } 735 | 736 | 737 | // working with console 738 | 739 | 740 | if (FD_ISSET(0, &readfds)) //FD_ISSET()Returns a non-zero value if the bit for the file descriptor '0' is set in the file descriptor set pointed to by readfds, and 0 otherwise. 741 | { 742 | 743 | char rec_buff[5000]; 744 | gets(rec_buff); 745 | 746 | 747 | if(rec_buff[0] == 'r' || rec_buff[0] == 'R') 748 | { 749 | 750 | displayHtable(); 751 | } 752 | 753 | else if(forYou(num,rec_buff) == 0)//fun return 1 if for you;return 0 if not for you 754 | { 755 | char outputbuff[40],*out,flag; 756 | int i =0; 757 | 758 | if(getOrPut(rec_buff) == 0) //fun() return 1 for get, 0 for put 759 | { 760 | //value from put to be transferred at last 761 | TransferValue = extractValueFromPut(rec_buff); 762 | 763 | flag = 'r'; // indicates that last node has to receive a value 764 | } 765 | else 766 | flag = 's'; //indicates that last node will send a value 767 | 768 | out = forwardedData(rec_buff,flag); //fun() to prepare the data to be forwaded 769 | 770 | 771 | for(i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "common.h" 9 | #include 10 | 11 | 12 | #define MAX_CLIENT_SUPPORTED 32 13 | #define SERVER_PORT 2000 /*Server process is running on this port no. Client has to send data to this port no*/ 14 | 15 | test_struct_t test_struct; 16 | result_struct_t res_struct; 17 | char data_buffer[1024]; 18 | 19 | int monitored_fd_set[32]; 20 | 21 | static void 22 | intitiaze_monitor_fd_set(){ 23 | 24 | int i = 0; 25 | for(; i < MAX_CLIENT_SUPPORTED; i++) 26 | monitored_fd_set[i] = -1; 27 | } 28 | 29 | static void 30 | add_to_monitored_fd_set(int skt_fd){ 31 | 32 | int i = 0; 33 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 34 | 35 | if(monitored_fd_set[i] != -1) 36 | continue; 37 | monitored_fd_set[i] = skt_fd; 38 | break; 39 | } 40 | } 41 | 42 | static void 43 | remove_from_monitored_fd_set(int skt_fd){ 44 | 45 | int i = 0; 46 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 47 | 48 | if(monitored_fd_set[i] != skt_fd) 49 | continue; 50 | 51 | monitored_fd_set[i] = -1; 52 | break; 53 | } 54 | } 55 | 56 | static void 57 | re_init_readfds(fd_set *fd_set_ptr){ 58 | 59 | FD_ZERO(fd_set_ptr); 60 | int i = 0; 61 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 62 | if(monitored_fd_set[i] != -1){ 63 | FD_SET(monitored_fd_set[i], fd_set_ptr); 64 | } 65 | } 66 | } 67 | 68 | static int 69 | get_max_fd(){ 70 | 71 | int i = 0; 72 | int max = -1; 73 | 74 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 75 | if(monitored_fd_set[i] > max) 76 | max = monitored_fd_set[i]; 77 | } 78 | 79 | return max; 80 | } 81 | 82 | void 83 | setup_tcp_server_communication(){ 84 | 85 | /*Step 1 : Initialization*/ 86 | /*Socket handle and other variables*/ 87 | int master_sock_tcp_fd = 0, /*Master socket file descriptor, used to accept new client connection only, no data exchange*/ 88 | sent_recv_bytes = 0, 89 | addr_len = 0, 90 | opt = 1; 91 | 92 | int comm_socket_fd = 0; /*client specific communication socket file descriptor, used for only data exchange/communication between client and server*/ 93 | fd_set readfds; /*Set of file descriptor on which select() polls. Select() unblocks whever data arrives on any fd present in this set*/ 94 | /*variables to hold server information*/ 95 | struct sockaddr_in server_addr, /*structure to store the server and client info*/ 96 | client_addr; 97 | 98 | /* Just drain the array of monitored file descriptors (sockets)*/ 99 | intitiaze_monitor_fd_set(); 100 | 101 | /*step 2: tcp master socket creation*/ 102 | if ((master_sock_tcp_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1) 103 | { 104 | printf("socket creation failed\n"); 105 | exit(1); 106 | } 107 | 108 | /*Step 3: specify server Information*/ 109 | server_addr.sin_family = AF_INET;/*This socket will process only ipv4 network packets*/ 110 | server_addr.sin_port = SERVER_PORT;/*Server will process any data arriving on port no 2000*/ 111 | server_addr.sin_addr.s_addr = INADDR_ANY; //3232249957; //( = 192.168.56.101); /*Server's IP address, means, Linux will send all data whose destination address = address of any local interface of this machine, in this case it is 192.168.56.101*/ 112 | 113 | addr_len = sizeof(struct sockaddr); 114 | 115 | /* Bind the server. Binding means, we are telling kernel(OS) that any data 116 | * you recieve with dest ip address = 192.168.56.101, and tcp port no = 2000, pls send that data to this process 117 | * bind() is a mechnism to tell OS what kind of data server process is interested in to recieve. Remember, server machine 118 | * can run multiple server processes to process different data and service different clients. Note that, bind() is 119 | * used on server side, not on client side*/ 120 | 121 | if (bind(master_sock_tcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 122 | { 123 | printf("socket bind failed\n"); 124 | return; 125 | } 126 | 127 | /*Step 4 : Tell the Linux OS to maintain the queue of max length to Queue incoming 128 | * client connections.*/ 129 | if (listen(master_sock_tcp_fd, 5)<0) 130 | { 131 | printf("listen failed\n"); 132 | return; 133 | } 134 | 135 | 136 | 137 | 138 | /*Add master socket to Monitored set of FDs*/ 139 | add_to_monitored_fd_set(master_sock_tcp_fd); 140 | 141 | /* Server infinite loop for servicing the client*/ 142 | 143 | 144 | while(1){ 145 | 146 | /*Step 5 : initialze and dill readfds*/ 147 | //FD_ZERO(&readfds); /* Initialize the file descriptor set*/ 148 | re_init_readfds(&readfds); /*Copy the entire monitored FDs to readfds*/ 149 | //FD_SET(master_sock_tcp_fd, &readfds); /*Add the socket to this set on which our server is running*/ 150 | 151 | printf("blocked on select System call...\n"); 152 | 153 | /*Step 6 : Wait for client connection*/ 154 | /*state Machine state 1 */ 155 | select(get_max_fd() + 1, &readfds, NULL, NULL, NULL); /*Call the select system cal, server process blocks here. Linux OS keeps this process blocked untill the data arrives on any of the file Drscriptors in the 'readfds' set*/ 156 | 157 | /*Some data on some fd present in monitored fd set has arrived, Now check on which File descriptor the data arrives, and process accordingly*/ 158 | 159 | /*If Data arrives on master socket FD*/ 160 | if (FD_ISSET(master_sock_tcp_fd, &readfds)) 161 | { 162 | /*Data arrives on Master socket only when new client connects with the server (that is, 'connect' call is invoked on client side)*/ 163 | printf("New connection recieved recvd, accept the connection. Client and Server completes TCP-3 way handshake at this point\n"); 164 | 165 | /* step 7 : accept() returns a new temporary file desriptor(fd). Server uses this 'comm_socket_fd' fd for the rest of the 166 | * life of connection with this client to send and recieve msg. Master socket is used only for accepting 167 | * new client's connection and not for data exchange with the client*/ 168 | /* state Machine state 2*/ 169 | comm_socket_fd = accept(master_sock_tcp_fd, (struct sockaddr *)&client_addr, &addr_len); 170 | if(comm_socket_fd < 0){ 171 | 172 | /* if accept failed to return a socket descriptor, display error and exit */ 173 | printf("accept error : errno = %d\n", errno); 174 | exit(0); 175 | } 176 | 177 | add_to_monitored_fd_set(comm_socket_fd); 178 | printf("Connection accepted from client : %s:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 179 | } 180 | else /* Data srrives on some other client FD*/ 181 | { 182 | 183 | int i = 0, comm_socket_fd = -1; 184 | for(; i < MAX_CLIENT_SUPPORTED; i++){ 185 | 186 | 187 | if(FD_ISSET(monitored_fd_set[i], &readfds)){/*Find the clinet FD on which Data has arrived*/ 188 | 189 | comm_socket_fd = monitored_fd_set[i]; 190 | 191 | memset(data_buffer, 0, sizeof(data_buffer)); 192 | sent_recv_bytes = recvfrom(comm_socket_fd, (char *)data_buffer, sizeof(data_buffer), 0, (struct sockaddr *)&client_addr, &addr_len); 193 | 194 | printf("Server recvd %d bytes from client %s:%u\n", sent_recv_bytes, 195 | inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 196 | 197 | if(sent_recv_bytes == 0){ 198 | /*If server recvs empty msg from client, server may close the connection and wait 199 | * for fresh new connection from client - same or different*/ 200 | close(comm_socket_fd); 201 | remove_from_monitored_fd_set(comm_socket_fd); 202 | break; /*goto step 5*/ 203 | 204 | } 205 | 206 | 207 | test_struct_t *client_data = (test_struct_t *)data_buffer; 208 | 209 | /* If the client sends a special msg to server, then server close the client connection 210 | * for forever*/ 211 | /*Step 9 */ 212 | if(client_data->a == 0 && client_data->b ==0){ 213 | 214 | close(comm_socket_fd); 215 | remove_from_monitored_fd_set(comm_socket_fd); 216 | printf("Server closes connection with client : %s:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 217 | /*Goto state machine State 1*/ 218 | break;/*Get out of inner while loop, server is done with this client, time to check for new connection request by executing selct()*/ 219 | } 220 | 221 | result_struct_t result; 222 | result.c = client_data->a + client_data->b; 223 | 224 | /* Server replying back to client now*/ 225 | sent_recv_bytes = sendto(comm_socket_fd, (char *)&result, sizeof(result_struct_t), 0, 226 | (struct sockaddr *)&client_addr, sizeof(struct sockaddr)); 227 | 228 | printf("Server sent %d bytes in reply to client\n", sent_recv_bytes); 229 | } 230 | } 231 | } 232 | 233 | }/*step 10 : wait for new client request again*/ 234 | } 235 | 236 | int 237 | main(int argc, char **argv){ 238 | 239 | setup_tcp_server_communication(); 240 | return 0; 241 | } 242 | -------------------------------------------------------------------------------- /sts/tcp_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | #define DEST_PORT 2000 10 | #define SERVER_IP_ADDRESS "127.0.0.1" 11 | 12 | test_struct_t client_data; 13 | result_struct_t result; 14 | 15 | void 16 | setup_tcp_communication(){ 17 | 18 | /*Step 1 : Initialization*/ 19 | /*Socket handle*/ 20 | int sockfd = 0, 21 | sent_recv_bytes = 0; 22 | 23 | int addr_len = 0; 24 | 25 | addr_len = sizeof(struct sockaddr); 26 | 27 | /*to store socket addesses : ip address and port*/ 28 | struct sockaddr_in dest; 29 | 30 | /*Step 2: specify server information*/ 31 | /*Ipv4 sockets, Other values are IPv6*/ 32 | dest.sin_family = AF_INET; 33 | 34 | /*Client wants to send data to server process which is running on server machine, and listening on 35 | * port on DEST_PORT, server IP address SERVER_IP_ADDRESS. 36 | * Inform client about which server to send data to : All we need is port number, and server ip address. Pls note that 37 | * there can be many processes running on the server listening on different no of ports, 38 | * our client is interested in sending data to server process which is lisetning on PORT = DEST_PORT*/ 39 | dest.sin_port = DEST_PORT; 40 | struct hostent *host = (struct hostent *)gethostbyname(SERVER_IP_ADDRESS); 41 | dest.sin_addr = *((struct in_addr *)host->h_addr); 42 | 43 | /*Step 3 : Create a TCP socket*/ 44 | /*Create a socket finally. socket() is a system call, which asks for three paramemeters*/ 45 | sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 46 | 47 | 48 | connect(sockfd, (struct sockaddr *)&dest,sizeof(struct sockaddr)); 49 | 50 | /*Step 4 : get the data to be sent to server*/ 51 | /*Our client is now ready to send data to server. sendto() sends data to Server*/ 52 | 53 | PROMPT_USER: 54 | 55 | /*prompt the user to enter data*/ 56 | printf("Enter a : ?\n"); 57 | scanf("%u", &client_data.a); 58 | printf("Enter b : ?\n"); 59 | scanf("%u", &client_data.b); 60 | 61 | 62 | /*step 5 : send the data to server*/ 63 | sent_recv_bytes = sendto(sockfd, 64 | &client_data, 65 | sizeof(test_struct_t), 66 | 0, 67 | (struct sockaddr *)&dest, 68 | sizeof(struct sockaddr)); 69 | 70 | printf("No of bytes sent = %d\n", sent_recv_bytes); 71 | 72 | /*Step 6 : Client also want to reply from server after sending data*/ 73 | 74 | /*recvfrom is a blocking system call, meaning the client program will not run past this point 75 | * untill the data arrives on the socket from server*/ 76 | sent_recv_bytes = recvfrom(sockfd, (char *)&result, sizeof(result_struct_t), 0, 77 | (struct sockaddr *)&dest, &addr_len); 78 | 79 | printf("No of bytes recvd = %d\n", sent_recv_bytes); 80 | 81 | printf("Result recvd = %u\n", result.c); 82 | /*Step 7: Client would want to send the data again to the server, go into infinite loop*/ 83 | goto PROMPT_USER; 84 | } 85 | 86 | 87 | int 88 | main(int argc, char **argv){ 89 | 90 | setup_tcp_communication(); 91 | printf("application quits\n"); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /sts/tcp_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "common.h" 9 | 10 | /*Server process is running on this port no. Client has to send data to this port no*/ 11 | #define SERVER_PORT 2000 12 | 13 | test_struct_t test_struct; 14 | result_struct_t res_struct; 15 | char data_buffer[1024]; 16 | 17 | void 18 | setup_tcp_server_communication(){ 19 | 20 | /*Step 1 : Initialization*/ 21 | /*Socket handle and other variables*/ 22 | /*Master socket file descriptor, used to accept new client connection only, no data exchange*/ 23 | int master_sock_tcp_fd = 0, 24 | sent_recv_bytes = 0, 25 | addr_len = 0, 26 | opt = 1; 27 | 28 | /*client specific communication socket file descriptor, 29 | * used for only data exchange/communication between client and server*/ 30 | int comm_socket_fd = 0; 31 | /* Set of file descriptor on which select() polls. Select() unblocks whever data arrives on 32 | * any fd present in this set*/ 33 | fd_set readfds; 34 | /*variables to hold server information*/ 35 | struct sockaddr_in server_addr, /*structure to store the server and client info*/ 36 | client_addr; 37 | 38 | /*step 2: tcp master socket creation*/ 39 | if ((master_sock_tcp_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1) 40 | { 41 | printf("socket creation failed\n"); 42 | exit(1); 43 | } 44 | 45 | /*Step 3: specify server Information*/ 46 | server_addr.sin_family = AF_INET;/*This socket will process only ipv4 network packets*/ 47 | server_addr.sin_port = SERVER_PORT;/*Server will process any data arriving on port no 2000*/ 48 | 49 | /*3232249957; //( = 192.168.56.101); Server's IP address, 50 | //means, Linux will send all data whose destination address = address of any local interface 51 | //of this machine, in this case it is 192.168.56.101*/ 52 | server_addr.sin_addr.s_addr = INADDR_ANY; 53 | 54 | addr_len = sizeof(struct sockaddr); 55 | 56 | /* Bind the server. Binding means, we are telling kernel(OS) that any data 57 | * you recieve with dest ip address = 192.168.56.101, and tcp port no = 2000, pls send that data to this process 58 | * bind() is a mechnism to tell OS what kind of data server process is interested in to recieve. Remember, server machine 59 | * can run multiple server processes to process different data and service different clients. Note that, bind() is 60 | * used on server side, not on client side*/ 61 | 62 | if (bind(master_sock_tcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 63 | { 64 | printf("socket bind failed\n"); 65 | return; 66 | } 67 | 68 | /*Step 4 : Tell the Linux OS to maintain the queue of max length to Queue incoming 69 | * client connections.*/ 70 | if (listen(master_sock_tcp_fd, 5)<0) 71 | { 72 | printf("listen failed\n"); 73 | return; 74 | } 75 | 76 | /* Server infinite loop for servicing the client*/ 77 | 78 | while(1){ 79 | 80 | /*Step 5 : initialze and dill readfds*/ 81 | FD_ZERO(&readfds); /* Initialize the file descriptor set*/ 82 | FD_SET(master_sock_tcp_fd, &readfds); /*Add the socket to this set on which our server is running*/ 83 | 84 | printf("blocked on select System call...\n"); 85 | 86 | 87 | /*Step 6 : Wait for client connection*/ 88 | /*state Machine state 1 */ 89 | 90 | /*Call the select system call, server process blocks here. Linux OS keeps this process blocked untill the data arrives on any of the file Drscriptors in the 'readfds' set*/ 91 | select(master_sock_tcp_fd + 1, &readfds, NULL, NULL, NULL); 92 | 93 | /*Some data on some fd present in set has arrived, Now check on which File descriptor the data arrives, and process accordingly*/ 94 | if (FD_ISSET(master_sock_tcp_fd, &readfds)) 95 | { 96 | /*Data arrives on Master socket only when new client connects with the server (that is, 'connect' call is invoked on client side)*/ 97 | printf("New connection recieved recvd, accept the connection. Client and Server completes TCP-3 way handshake at this point\n"); 98 | 99 | /* step 7 : accept() returns a new temporary file desriptor(fd). Server uses this 'comm_socket_fd' fd for the rest of the 100 | * life of connection with this client to send and recieve msg. Master socket is used only for accepting 101 | * new client's connection and not for data exchange with the client*/ 102 | /* state Machine state 2*/ 103 | comm_socket_fd = accept(master_sock_tcp_fd, (struct sockaddr *)&client_addr, &addr_len); 104 | if(comm_socket_fd < 0){ 105 | 106 | /* if accept failed to return a socket descriptor, display error and exit */ 107 | printf("accept error : errno = %d\n", errno); 108 | exit(0); 109 | } 110 | 111 | printf("Connection accepted from client : %s:%u\n", 112 | inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 113 | 114 | while(1){ 115 | printf("Server ready to service client msgs.\n"); 116 | /*Drain to store client info (ip and port) when data arrives from client, sometimes, server would want to find the identity of the client sending msgs*/ 117 | memset(data_buffer, 0, sizeof(data_buffer)); 118 | 119 | /*Step 8: Server recieving the data from client. Client IP and PORT no will be stored in client_addr 120 | * by the kernel. Server will use this client_addr info to reply back to client*/ 121 | 122 | /*Like in client case, this is also a blocking system call, meaning, server process halts here untill 123 | * data arrives on this comm_socket_fd from client whose connection request has been accepted via accept()*/ 124 | /* state Machine state 3*/ 125 | sent_recv_bytes = recvfrom(comm_socket_fd, (char *)data_buffer, sizeof(data_buffer), 0, 126 | (struct sockaddr *)&client_addr, &addr_len); 127 | 128 | /* state Machine state 4*/ 129 | printf("Server recvd %d bytes from client %s:%u\n", sent_recv_bytes, 130 | inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 131 | 132 | if(sent_recv_bytes == 0){ 133 | /*If server recvs empty msg from client, server may close the connection and wait 134 | * for fresh new connection from client - same or different*/ 135 | close(comm_socket_fd); 136 | break; /*goto step 5*/ 137 | 138 | } 139 | 140 | test_struct_t *client_data = (test_struct_t *)data_buffer; 141 | 142 | /* If the client sends a special msg to server, then server close the client connection 143 | * for forever*/ 144 | /*Step 9 */ 145 | if(client_data->a == 0 && client_data->b ==0){ 146 | 147 | close(comm_socket_fd); 148 | printf("Server closes connection with client : %s:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 149 | /*Goto state machine State 1*/ 150 | break;/*Get out of inner while loop, server is done with this client, time to check for new connection request by executing selct()*/ 151 | } 152 | 153 | result_struct_t result; 154 | result.c = client_data->a + client_data->b; 155 | 156 | /* Server replying back to client now*/ 157 | sent_recv_bytes = sendto(comm_socket_fd, (char *)&result, sizeof(result_struct_t), 0, 158 | (struct sockaddr *)&client_addr, sizeof(struct sockaddr)); 159 | 160 | printf("Server sent %d bytes in reply to client\n", sent_recv_bytes); 161 | /*Goto state machine State 3*/ 162 | } 163 | } 164 | }/*step 10 : wait for new client request again*/ 165 | } 166 | 167 | int 168 | main(int argc, char **argv){ 169 | 170 | setup_tcp_server_communication(); 171 | return 0; 172 | } 173 | -------------------------------------------------------------------------------- /webserver/TCPWebserver/tcp_web_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /*Server process is running on this port no. Client has to send data to this port no*/ 10 | #define SERVER_PORT 2000 11 | 12 | char data_buffer[1024]; 13 | 14 | 15 | /*string helping functions*/ 16 | 17 | /*Remove the space from both sides of the string*/ 18 | void 19 | string_space_trim(char *string){ 20 | 21 | if(!string) 22 | return; 23 | 24 | char* ptr = string; 25 | int len = strlen(ptr); 26 | 27 | if(!len){ 28 | return; 29 | } 30 | 31 | if(!isspace(ptr[0]) && !isspace(ptr[len-1])){ 32 | return; 33 | } 34 | 35 | while(len-1 > 0 && isspace(ptr[len-1])){ 36 | ptr[--len] = 0; 37 | } 38 | 39 | while(*ptr && isspace(*ptr)){ 40 | ++ptr, --len; 41 | } 42 | 43 | memmove(string, ptr, len + 1); 44 | } 45 | 46 | typedef struct student_{ 47 | 48 | char name[32]; 49 | unsigned int roll_no; 50 | char hobby[32]; 51 | char dept[32]; 52 | } student_t; 53 | 54 | student_t student[5] = { 55 | {"Abhishek", 10305042, "Programming", "CSE"}, 56 | {"Nitin", 10305048, "Programming", "CSE"}, 57 | {"Avinash", 10305041, "Cricket", "ECE"}, 58 | {"Jack", 10305032, "Udemy Teaching", "Mechanical"}, 59 | {"Cris", 10305030, "Programming", "Electrical"}}; 60 | 61 | 62 | static char * 63 | process_GET_request(char *URL, unsigned int *response_len){ 64 | 65 | printf("%s(%u) called with URL = %s\n", __FUNCTION__, __LINE__, URL); 66 | 67 | /*Let us extract the roll no of a students from URL using 68 | * string handling 69 | *URL : /College/IIT/?dept=CSE&rollno=10305042/ 70 | * */ 71 | char delimeter[2] = {'?', '\0'}; 72 | 73 | string_space_trim(URL); 74 | char *token[5] = {0}; 75 | 76 | token[0] = strtok(URL, delimeter); 77 | token[1] = strtok(0, delimeter); 78 | /*token[1] = dept=CSE&rollno=10305042*/ 79 | delimeter[0] = '&'; 80 | 81 | token[2] = strtok(token[1], delimeter); 82 | token[3] = strtok(0, delimeter); 83 | /*token[2] = dept=CSE, token[3] = rollno=10305042*/ 84 | 85 | printf("token[0] = %s, token[1] = %s, token[2] = %s, token[3] = %s\n", 86 | token[0] , token[1], token[2], token[3]); 87 | 88 | delimeter[0] = '='; 89 | char *roll_no_str = strtok(token[3], delimeter); 90 | char *roll_no_value = strtok(0, delimeter); 91 | printf("roll_no_value = %s\n", roll_no_value); 92 | unsigned int roll_no = atoi(roll_no_value), i = 0; 93 | 94 | for(i = 0; i < 5; i++){ 95 | if(student[i].roll_no != roll_no){ 96 | continue; 97 | } 98 | break; 99 | } 100 | 101 | if(i == 5) 102 | return NULL; 103 | 104 | /*We have got the students of interest here*/ 105 | char *response = calloc(1, 1024); 106 | 107 | strcpy(response, 108 | "" 109 | "" 110 | "HTML Response" 111 | "" 115 | "" 116 | "" 117 | "" 118 | "" 119 | ""); 127 | strcat(response , 128 | "
"); 120 | 121 | strcat(response , 122 | student[i].name 123 | ); 124 | 125 | strcat(response , 126 | "
" 129 | "" 130 | ""); 131 | 132 | unsigned int content_len_str = strlen(response); 133 | 134 | /*create HTML hdr returned by server*/ 135 | char *header = calloc(1, 248 + content_len_str); 136 | strcpy(header, "HTTP/1.1 200 OK\n"); 137 | strcat(header, "Server: My Personal HTTP Server\n" ); 138 | strcat(header, "Content-Length: " ); 139 | strcat(header, "Connection: close\n" ); 140 | //strcat(header, itoa(content_len_str)); 141 | strcat(header, "2048"); 142 | strcat(header, "\n"); 143 | strcat(header, "Content-Type: text/html; charset=UTF-8\n"); 144 | strcat(header, "\n"); 145 | 146 | strcat(header, response); 147 | content_len_str = strlen(header); 148 | *response_len = content_len_str; 149 | free(response); 150 | return header; 151 | } 152 | 153 | static char * 154 | process_POST_request(char *URL, unsigned int *response_len){ 155 | 156 | return NULL; 157 | } 158 | 159 | void 160 | setup_tcp_server_communication(){ 161 | 162 | /*Step 1 : Initialization*/ 163 | /*Socket handle and other variables*/ 164 | /*Master socket file descriptor, used to accept new client connection only, no data exchange*/ 165 | int master_sock_tcp_fd = 0, 166 | sent_recv_bytes = 0, 167 | addr_len = 0, 168 | opt = 1; 169 | 170 | /*client specific communication socket file descriptor, 171 | * used for only data exchange/communication between client and server*/ 172 | int comm_socket_fd = 0; 173 | /* Set of file descriptor on which select() polls. Select() unblocks whever data arrives on 174 | * any fd present in this set*/ 175 | fd_set readfds; 176 | /*variables to hold server information*/ 177 | struct sockaddr_in server_addr, /*structure to store the server and client info*/ 178 | client_addr; 179 | 180 | /*step 2: tcp master socket creation*/ 181 | if ((master_sock_tcp_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1) 182 | { 183 | printf("socket creation failed\n"); 184 | exit(1); 185 | } 186 | 187 | //set master socket to allow multiple connections 188 | if (setsockopt(master_sock_tcp_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt))<0){ 189 | printf("TCP socket creation failed for multiple connections\n"); 190 | exit(EXIT_FAILURE); 191 | } 192 | 193 | /*Step 3: specify server Information*/ 194 | server_addr.sin_family = AF_INET;/*This socket will process only ipv4 network packets*/ 195 | server_addr.sin_port = htons(SERVER_PORT);/*Server will process any data arriving on port no 2000*/ 196 | 197 | /*3232249957; //( = 192.168.56.101); Server's IP address, 198 | //means, Linux will send all data whose destination address = address of any local interface 199 | //of this machine, in this case it is 192.168.56.101*/ 200 | server_addr.sin_addr.s_addr = INADDR_ANY; 201 | 202 | addr_len = sizeof(struct sockaddr); 203 | 204 | /* Bind the server. Binding means, we are telling kernel(OS) that any data 205 | * you recieve with dest ip address = 192.168.56.101, and tcp port no = 2000, pls send that data to this process 206 | * bind() is a mechnism to tell OS what kind of data server process is interested in to recieve. Remember, server machine 207 | * can run multiple server processes to process different data and service different clients. Note that, bind() is 208 | * used on server side, not on client side*/ 209 | 210 | if (bind(master_sock_tcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) 211 | { 212 | printf("socket bind failed\n"); 213 | return; 214 | } 215 | 216 | /*Step 4 : Tell the Linux OS to maintain the queue of max length to Queue incoming 217 | * client connections.*/ 218 | if (listen(master_sock_tcp_fd, 5)<0) 219 | { 220 | printf("listen failed\n"); 221 | return; 222 | } 223 | 224 | /* Server infinite loop for servicing the client*/ 225 | 226 | while(1){ 227 | 228 | /*Step 5 : initialze and dill readfds*/ 229 | FD_ZERO(&readfds); /* Initialize the file descriptor set*/ 230 | FD_SET(master_sock_tcp_fd, &readfds); /*Add the socket to this set on which our server is running*/ 231 | 232 | printf("blocked on select System call...\n"); 233 | 234 | 235 | /*Step 6 : Wait for client connection*/ 236 | /*state Machine state 1 */ 237 | 238 | /*Call the select system call, server process blocks here. Linux OS keeps this process blocked untill the data arrives on any of the file Drscriptors in the 'readfds' set*/ 239 | select(master_sock_tcp_fd + 1, &readfds, NULL, NULL, NULL); 240 | 241 | /*Some data on some fd present in set has arrived, Now check on which File descriptor the data arrives, and process accordingly*/ 242 | if (FD_ISSET(master_sock_tcp_fd, &readfds)) 243 | { 244 | /*Data arrives on Master socket only when new client connects with the server (that is, 'connect' call is invoked on client side)*/ 245 | printf("New connection recieved recvd, accept the connection. Client and Server completes TCP-3 way handshake at this point\n"); 246 | 247 | /* step 7 : accept() returns a new temporary file desriptor(fd). Server uses this 'comm_socket_fd' fd for the rest of the 248 | * life of connection with this client to send and recieve msg. Master socket is used only for accepting 249 | * new client's connection and not for data exchange with the client*/ 250 | /* state Machine state 2*/ 251 | comm_socket_fd = accept(master_sock_tcp_fd, (struct sockaddr *)&client_addr, &addr_len); 252 | if(comm_socket_fd < 0){ 253 | /* if accept failed to return a socket descriptor, display error and exit */ 254 | printf("accept error : errno = %d\n", errno); 255 | exit(0); 256 | } 257 | 258 | printf("Connection accepted from client : %s:%u\n", 259 | inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 260 | 261 | while(1){ 262 | printf("Server ready to service client msgs.\n"); 263 | /*Drain to store client info (ip and port) when data arrives from client, sometimes, server would want to find the identity of the client sending msgs*/ 264 | memset(data_buffer, 0, sizeof(data_buffer)); 265 | 266 | /*Step 8: Server recieving the data from client. Client IP and PORT no will be stored in client_addr 267 | * by the kernel. Server will use this client_addr info to reply back to client*/ 268 | 269 | /*Like in client case, this is also a blocking system call, meaning, server process halts here untill 270 | * data arrives on this comm_socket_fd from client whose connection request has been accepted via accept()*/ 271 | /* state Machine state 3*/ 272 | sent_recv_bytes = recvfrom(comm_socket_fd, (char *)data_buffer, sizeof(data_buffer), 0, 273 | (struct sockaddr *)&client_addr, &addr_len); 274 | 275 | /* state Machine state 4*/ 276 | printf("Server recvd %d bytes from client %s:%u\n", sent_recv_bytes, 277 | inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 278 | 279 | if(sent_recv_bytes == 0){ 280 | /* If server recvs empty msg from client, server may close the connection and wait 281 | * for fresh new connection from client - same or different*/ 282 | close(comm_socket_fd); 283 | break; /*goto step 5*/ 284 | 285 | } 286 | 287 | 288 | 289 | 290 | /****************************************************************/ 291 | /*BEGIN : Implement the HTTP request processing functionality */ 292 | /****************************************************************/ 293 | 294 | printf("Msg recieved : %s\n", data_buffer); 295 | char *request_line = NULL; 296 | char del[2] = "\n", 297 | *method = NULL, 298 | *URL = NULL; 299 | request_line = strtok(data_buffer, del); /*Extract out the request line*/ 300 | del[0] = ' '; 301 | method = strtok(request_line, del); /*Tokenize the request line on the basis of space, and extract the first word*/ 302 | URL = strtok(NULL, del); /*Extract the URL*/ 303 | printf("Method = %s\n", method); 304 | printf("URL = %s\n", URL); 305 | char *response = NULL; 306 | unsigned int response_length = 0 ; 307 | 308 | if(strncmp(method, "GET", strlen("GET")) == 0){ 309 | response = process_GET_request(URL, &response_length); 310 | } 311 | else if(strncmp(method, "POST", strlen("POST")) == 0){ 312 | response = process_POST_request(URL, &response_length); 313 | } 314 | else{ 315 | printf("Unsupported URL method request\n"); 316 | close(comm_socket_fd); 317 | break; 318 | } 319 | 320 | /****************************************************************/ 321 | /*END : Implement the HTTP request processing functionality */ 322 | /****************************************************************/ 323 | 324 | 325 | 326 | 327 | /* Server replying back to client now*/ 328 | if(response){ 329 | printf("response to be sent to client = \n%s", response); 330 | sent_recv_bytes = sendto(comm_socket_fd, response, response_length, 0, 331 | (struct sockaddr *)&client_addr, sizeof(struct sockaddr)); 332 | free(response); 333 | printf("Server sent %d bytes in reply to client\n", sent_recv_bytes); 334 | //close(comm_socket_fd); 335 | //break; 336 | } 337 | /*Goto state machine State 3*/ 338 | } 339 | } 340 | }/*step 10 : wait for new client request again*/ 341 | } 342 | 343 | int 344 | main(int argc, char **argv){ 345 | 346 | setup_tcp_server_communication(); 347 | return 0; 348 | } 349 | --------------------------------------------------------------------------------