 | RL-ARM User's Guide |  |
|
|
| Multiple UDP ConnectionsIt is often required for the server applications to be able to accept several UDP connections from clients on the same port. Such application is for example a TFTP server. The multiplex handling must be implemented in the session layer of the user application. Because UDP socket is a connectionless service, it is able to accept several concurrent connections from different remote hosts. The packet multiplexing must be done in user application. The framework of the user application shall contain the following basic functions: - The user_init() function to initialize all user application sessions at startup.
void user_init () {
USER_INFO *user_s;
int i;
for (i = 0; i < user_num_sess; i++) {
user_s = &user_session[i];
mem_set (user_s->RemIp, 0, IP_ADRLEN);
user_s->RemPort = 0;
user_s->Flags = 0;
user_s->Retries = 0;
user_s->Tout = 0;
user_s->File = NULL;
user_s->State = USER_STATE_IDLE;
}
/* Allocate one UDP socket for all sessions. */
user_Socket = udp_get_socket (0, UDP_OPT_SEND_CS | UDP_OPT_CHK_CS,
user_listener);
if (user_Socket != 0) {
udp_open (user_Socket, USER_SERVER_PORT);
}
}
All user sessions are now initialized. A common UDP socket is opened for communication on selected USER_SERVER_PORT port. - The user_listener() callback function for UDP socket.
static U16 user_listener (U8 socket, U8 *remip, U16 port,
U8 *buf, U16 len) {
USER_INFO *user_s;
U8 session;
int i;
if (socket != user_Socket)) {
return (__FALSE);
}
session = user_map_session (remip, port);
if (session == 0) {
return (__FALSE);
}
user_s = &user_session[session-1];
switch (user_s->State) {
case USER_STATE_IDLE:
/* A new connection established. */
..
user_s->State = USER_STATE_ACTIVE;
break;
case USER_STATE_ACTIVE:
/* Process UDP data. */
..
break;
}
return (__TRUE);
}
- The user_map_session() function to map the UDP packet, which has generated a callback event, to it's owner session.
static U8 user_map_session (U8 *remip, U16 port) {
USER_INFO *user_s;
int i;
/* Check if this is an existing connection. */
for (i = 1; i <= user_num_sess; i++) {
user_s = &user_session[i-1];
if ((user_s->State > USER_STATE_IDLE) &&
(mem_comp (remip, user_s->RemIp, IP_ADRLEN) == __TRUE) &&
(port == user_s->RemPort)) {
return (i);
}
}
/* Check if this is a new connection. */
for (i = 1; i <= user_num_sess; i++) {
user_s = &user_session[i-1];
if (user_s->State == USER_STATE_IDLE) {
mem_copy (user_s->RemIp, remip, IP_ADRLEN);
user_s->RemPort = port;
return (i);
}
}
return (0);
}
- The user_kill_session() function to initialize the session to a default state, close any eventually opened files and release any eventually allocated buffers.
static void user_kill_session (USER_INFO *user_s) {
user_s->State = USER_STATE_IDLE;
if (user_s->File != NULL) {
user_fclose (user_s->File);
user_s->File = NULL;
}
mem_set (user_s->RemIp, 0, IP_ADRLEN);
user_s->RemPort = 0;
user_s->Flags = 0;
user_s->Retries = 0;
user_s->Tout = 0;
}
- The user_run_server() function to maintain the application jobs, timeouts, etc. This function shall be frequently called from the main loop.
void user_run_server () {
USER_INFO *user_s;
int i;
for (i = 0; i < user_num_sess; i++) {
user_s = &user_session[i];
switch (user_s->State) {
case USER_STATE_ACTIVE:
if (sec_tick == __TRUE) {
if (--user_s->Tout == 0) {
/* A timeout expired. */
user_kill_session (user_s);
}
}
break;
}
}
}
Note - There is only one socket used for all user sessions.
|
|