1 | /////////////////////////////////////////////////////////////////////////////////////// |
---|
2 | // file : udp_chat.c |
---|
3 | // author : Alain Greiner |
---|
4 | // date : march 2020 |
---|
5 | /////////////////////////////////////////////////////////////////////////////////////// |
---|
6 | // This file describes an UDP based chat application. |
---|
7 | // It can be used to launch the UDP client, or the UDP server application. |
---|
8 | // The client send the first message. The server wait this first message. |
---|
9 | // The 4 command line arguments are: is_server, local_ip_addr, remote_ip_addr, port |
---|
10 | /////////////////////////////////////////////////////////////////////////////////////// |
---|
11 | |
---|
12 | #include <stdio.h> |
---|
13 | #include <stdlib.h> |
---|
14 | #include <string.h> |
---|
15 | #include <almosmkh.h> |
---|
16 | #include <unistd.h> |
---|
17 | #include <sys/socket.h> |
---|
18 | |
---|
19 | #define BUF_SIZE 256 |
---|
20 | |
---|
21 | //////////////////////////// |
---|
22 | void client_chat( int fdid ) |
---|
23 | { |
---|
24 | char buffer[BUF_SIZE]; // string buffer (for both send and receive) |
---|
25 | int size; // string length (including NUL) |
---|
26 | int nbytes; // number of characters actually sent or received |
---|
27 | |
---|
28 | while( 1 ) |
---|
29 | { |
---|
30 | //////// display client prompt to wait local client message //////// |
---|
31 | printf("\n[local client] "); |
---|
32 | |
---|
33 | // build local client message |
---|
34 | size = get_string( buffer , BUF_SIZE ); |
---|
35 | |
---|
36 | // exit chat function when client message is the "exit" string |
---|
37 | if( strncmp( "exit" , buffer , 4 ) == 0 ) |
---|
38 | { |
---|
39 | printf("\n[client_chat] local message is <exit> => return to main\n" ); |
---|
40 | return; |
---|
41 | } |
---|
42 | |
---|
43 | // send local client message |
---|
44 | nbytes = send( fdid , buffer, size, 0 ); // flags |
---|
45 | |
---|
46 | if( nbytes != size ) |
---|
47 | { |
---|
48 | printf("\n[client_chat error] cannot send => return to main\n"); |
---|
49 | return; |
---|
50 | } |
---|
51 | |
---|
52 | ///////// display server prompt to wait remote server message /////// |
---|
53 | printf("\n[remote server] "); |
---|
54 | |
---|
55 | // receive remote server message |
---|
56 | nbytes = recv( fdid , buffer , BUF_SIZE , 0 ); |
---|
57 | |
---|
58 | if( nbytes < 0 ) |
---|
59 | { |
---|
60 | printf("\n\n[client_chat error] cannot receive => return to main\n" ); |
---|
61 | return; |
---|
62 | } |
---|
63 | else if( nbytes == 0 ) |
---|
64 | { |
---|
65 | printf("\n\n[client_chat] receive EOF => return to main\n" ); |
---|
66 | return; |
---|
67 | } |
---|
68 | |
---|
69 | // display remote server message |
---|
70 | printf("%s\n", buffer ); |
---|
71 | } |
---|
72 | } // end client_chat() |
---|
73 | |
---|
74 | |
---|
75 | //////////////////////////// |
---|
76 | void server_chat( int fdid ) |
---|
77 | { |
---|
78 | char buffer[BUF_SIZE]; // string buffer (for send and receive) |
---|
79 | int size; // string length (including NUL) |
---|
80 | int nbytes; // number of characters actually sent or received |
---|
81 | |
---|
82 | while( 1 ) |
---|
83 | { |
---|
84 | //////// display client prompt to wait remote client message /////// |
---|
85 | printf("\n[remote client] "); |
---|
86 | |
---|
87 | // receive remote client message |
---|
88 | nbytes = recv( fdid , buffer , BUF_SIZE , 0 ); |
---|
89 | |
---|
90 | if( nbytes < 0 ) |
---|
91 | { |
---|
92 | printf("\n\n[server_chat error] cannot receive => return to main\n" ); |
---|
93 | return; |
---|
94 | } |
---|
95 | else if( nbytes == 0 ) |
---|
96 | { |
---|
97 | printf("\n\n[server_chat] receive EOF => return to main\n" ); |
---|
98 | return; |
---|
99 | } |
---|
100 | |
---|
101 | // display remote client message |
---|
102 | printf("%s\n", buffer ); |
---|
103 | |
---|
104 | //////// display server prompt to wait local server message ////// |
---|
105 | printf("\n[local server] "); |
---|
106 | |
---|
107 | // build local server message |
---|
108 | size = get_string( buffer , BUF_SIZE ); |
---|
109 | |
---|
110 | // exit chat function when server message is the "exit" string |
---|
111 | if( strncmp( "exit" , buffer , 4 ) == 0 ) |
---|
112 | { |
---|
113 | printf("\n[server_chat] local message is <exit> => return to main\n" ); |
---|
114 | return; |
---|
115 | } |
---|
116 | |
---|
117 | // send local server message |
---|
118 | nbytes = send( fdid , buffer , size , 0 ); |
---|
119 | |
---|
120 | if( nbytes != size ) |
---|
121 | { |
---|
122 | printf("\n[server_chat error] cannot send => return to main\n"); |
---|
123 | return; |
---|
124 | } |
---|
125 | } |
---|
126 | } // end server_chat() |
---|
127 | |
---|
128 | |
---|
129 | /////////////////////// |
---|
130 | int main( int argc, |
---|
131 | char ** argv ) |
---|
132 | { |
---|
133 | int pid; // process identifier |
---|
134 | int fdid; // file index of local socket |
---|
135 | int error; |
---|
136 | |
---|
137 | sockaddr_in_t local_sin; // local socket internet address |
---|
138 | sockaddr_in_t remote_sin; // remote socket internet address |
---|
139 | |
---|
140 | unsigned long long start_cycle; |
---|
141 | |
---|
142 | int addr_length = sizeof(sockaddr_t); |
---|
143 | |
---|
144 | // get start cycle |
---|
145 | get_cycle( &start_cycle ); |
---|
146 | |
---|
147 | // get PID |
---|
148 | pid = getpid(); |
---|
149 | |
---|
150 | // get arguments |
---|
151 | if( argc != 4 ) |
---|
152 | { |
---|
153 | printf("\n usage : udp_chat is_server local_addr remote_addr port\n"); |
---|
154 | exit( 0 ); |
---|
155 | } |
---|
156 | |
---|
157 | int is_server = atoi( argv[0] ); |
---|
158 | int local_addr = atoi( argv[1] ); |
---|
159 | int remote_addr = atoi( argv[2] ); |
---|
160 | int port = atoi( argv[3] ); |
---|
161 | |
---|
162 | if( is_server ) |
---|
163 | printf("\n[udp_chat] SERVER / pid %x / cycle %d" |
---|
164 | " local_addr %x / remote_addr %x / port %x\n", |
---|
165 | pid, (unsigned int)start_cycle, local_addr, remote_addr, port ); |
---|
166 | else |
---|
167 | printf("\n[udp_chat] CLIENT / pid %x / cycle %d" |
---|
168 | " local_addr %x / remote_addr %x / port %x\n", |
---|
169 | pid, (unsigned int)start_cycle, local_addr, remote_addr, port ); |
---|
170 | |
---|
171 | // initialize local_sin |
---|
172 | local_sin.sin_domain = HTONS( AF_INET ); |
---|
173 | local_sin.sin_addr = HTONL( local_addr ); |
---|
174 | local_sin.sin_port = HTONS( port ); |
---|
175 | |
---|
176 | // initialize remote_sin |
---|
177 | remote_sin.sin_domain = HTONS( AF_INET ); |
---|
178 | remote_sin.sin_addr = HTONL( remote_addr ); |
---|
179 | remote_sin.sin_port = HTONS( port ); |
---|
180 | |
---|
181 | // 1. create local UDP socket |
---|
182 | fdid = socket( AF_INET, |
---|
183 | SOCK_DGRAM, |
---|
184 | 0 ); |
---|
185 | |
---|
186 | if( fdid < 0 ) |
---|
187 | { |
---|
188 | printf("\n[udp_chat error] cannot create socket\n"); |
---|
189 | exit( 0 ); |
---|
190 | } |
---|
191 | else |
---|
192 | { |
---|
193 | printf("\n[udp_chat] created socket[%x,%d]\n", pid, fdid ); |
---|
194 | } |
---|
195 | |
---|
196 | // 2. bind local socket |
---|
197 | error = bind( fdid, |
---|
198 | (sockaddr_t *)(&local_sin), |
---|
199 | sizeof(sockaddr_t) ); |
---|
200 | if( error ) |
---|
201 | { |
---|
202 | printf("\n[udp_chat error] bind failure on socketi[%x,%d]\n", pid, fdid ); |
---|
203 | exit( 0 ); |
---|
204 | } |
---|
205 | else |
---|
206 | { |
---|
207 | printf("\n[udp_chat] socket[%x,%d] bound : [%x,%x]\n", |
---|
208 | pid, fdid, local_sin.sin_addr, (unsigned int)local_sin.sin_port ); |
---|
209 | } |
---|
210 | |
---|
211 | |
---|
212 | // 3. connect local socket to remote socket |
---|
213 | error = connect( fdid, |
---|
214 | (sockaddr_t *)(&remote_sin), |
---|
215 | addr_length ); |
---|
216 | if( error ) |
---|
217 | { |
---|
218 | printf("\n[server_chat error] cannot connect to remote => return to main\n" ); |
---|
219 | exit( 0 ); |
---|
220 | } |
---|
221 | else |
---|
222 | { |
---|
223 | printf("\n[server_chat] successfully connected to remote client\n"); |
---|
224 | } |
---|
225 | |
---|
226 | // 4. call chat function |
---|
227 | if( is_server ) server_chat( fdid ); |
---|
228 | else client_chat( fdid ); |
---|
229 | |
---|
230 | // 5. close local socket |
---|
231 | close( fdid ); |
---|
232 | |
---|
233 | printf("\n[udp_chat] closed socket[%x,%d]\n", pid, fdid ); |
---|
234 | |
---|
235 | exit(0); |
---|
236 | |
---|
237 | return 0; |
---|
238 | } |
---|