ibm-information-center/dist/eclipse/plugins/i5OS.ic.rzahz_5.4.0.1/svrpgm.htm

492 lines
16 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org">
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8">
<title>Example: Server program</title>
<LINK rel="stylesheet" type="text/css" href="../rzahg/ic.css">
</HEAD>
<body bgcolor="#FFFFFF">
<!-- Java sync-link -->
<SCRIPT LANGUAGE="Javascript" SRC="../rzahg/synch.js" TYPE="text/javascript"></SCRIPT>
<h2>Example: Server program</h2>
<pre>
/**********************************************************************/
/* */
/* Name: server.c */
/* */
/* Description: This program is a server for starting interactive */
/* qsh sessions on remote clients. The program */
/* listens for connections from clients. When a */
/* connection is accepted, it reads the user name */
/* and password of the client. It then swaps to the */
/* the specified user profile and spawns a new */
/* process running the qsh shell interpreter that */
/* handles the connection. */
/* */
/* Parameters: 1. Port number to listen for connections on. */
/* */
/* Notes: 1. The user name and password are sent as plain text */
/* from the client. */
/* 2. The user profile running this program must have */
/* authority to the QSYGETPH, QSYRLSPH, and */
/* QWTSETP APIs. */
/* 3. You will need to change the value of the NLSPATH */
/* environment variable if your system is using a */
/* different language than 2924. */
/* */
/**********************************************************************/
/**********************************************************************/
/* Includes */
/**********************************************************************/
#include &lt;stdio.h&gt; /* fopen(), vfprintf() */
#include &lt;sys/socket.h&gt; /* socket(), bind(), and so on. */
#include &lt;netinet/in.h&gt; /* sockaddr_in, INADDR_ANY, and so on */
#include &lt;arpa/inet.h&gt; /* inet_ntoa() */
#include &lt;spawn.h&gt; /* spawn() */
#include &lt;unistd.h&gt; /* close(), read(), and so on */
#include &lt;stdlib.h&gt; /* exit()*/
#include &lt;stdarg.h&gt; /* va_start(), va_end() */
#include &lt;qp0z1170.h&gt; /* Qp0zInitEnv() */
#include &lt;qsygetph.h&gt; /* QSYGETPH() */
#include &lt;qwtsetp.h&gt; /* QWTSETP() */
#include &lt;qsyrlsph.h&gt; /* QSYRLSPH() */
#include &lt;qusec.h&gt; /* Qus_EC_t */
#include &lt;pwd.h&gt; /* getpwnam() */
#include &lt;ctype.h&gt; /* toupper() */
#include &lt;time.h&gt; /* ctime(), time() */
#include &lt;except.h&gt; /* Exception and cancel handling */
#include &lt;errno.h&gt; /* errno and constants */
/**********************************************************************/
/* Constants */
/**********************************************************************/
#define DEFAULT_BUF 4096
#define DEFAULT_PORT 6042
#define NULL_PH "\0\0\0\0\0\0\0\0\0\0\0\0"
#define PH_SIZE 12
#define NAME_SIZE 11
#undef PATH_MAX
#define PATH_MAX 4096
/**********************************************************************/
/* Global Variables */
/**********************************************************************/
/* For logging errors */
FILE *log_fp;
char log_file[] = "/tmp/qsh_server.log";
char log_buffer[DEFAULT_BUF];
/**********************************************************************/
/* Function Prototypes */
/**********************************************************************/
int strtoupper(char *);
int GetString(int, char *, size_t);
void LogError(char *, ...);
void SendError(int, char *, ...);
void CleanupHandler(_CNL_Hndlr_Parms_T *);
int main(int argc, char *argv[])
{
int sfd; /* Server's listening socket */
int cfd; /* Socket connected to client */
int on=1; /* Flag for setsockopt() */
struct sockaddr_in my_addr; /* Address server binds to */
struct sockaddr_in client_addr; /* Addrress of connected client */
int client_addr_len; /* Length of client's socket address */
unsigned short port; /* Server's TCP port */
char server_ph[PH_SIZE+1] = NULL_PH; /* Server's profile handle */
char client_ph[PH_SIZE+1] = NULL_PH; /* Client's profile handle */
char profile[NAME_SIZE]; /* User profile read from client */
char password[NAME_SIZE]; /* Password read from client */
char sy_profile[NAME_SIZE]; /* User profile for i5/OS<SUP>(TM)</SUP> APIs */
char sy_password[NAME_SIZE]; /* Password for i5/OS<SUP>(TM)</SUP> APIs */
char server_profile[NAME_SIZE] = "*CURRENT ";
char no_pwd[NAME_SIZE] = "*NOPWD ";
struct passwd *cpw; /* User information for client */
Qus_EC_t error = { sizeof(Qus_EC_t), 0 }; /* Error code for SPIs */
/* Parameters for spawn() to shell process */
char qsh_pgm[] = "/QSYS.LIB/QSHELL.LIB/QZSHSH.PGM";
char *args[5]; /* Argument array */
char *envs[10]; /* Environment variable array */
int fd_count; /* Number of descriptors */
int fd_map[3]; /* Map of descriptors */
struct inheritance inherit; /* Inheritance options */
char server_dir[] = "/"; /* Default current working directory */
/* Environment variables */
char home_var[PATH_MAX+10];
char logname_var[NAME_SIZE+10];
char path_var[] = "PATH=/usr/bin:";
char stdio_var[] = "QIBM_USE_DESCRIPTOR_STDIO=I";
char terminal_type_var[] = "TERMINAL_TYPE=REMOTE";
char nlspath_var[] = "NLSPATH=/QIBM/ProdData/OS400/Shell/MRI2924/%N";
volatile _INTRPT_Hndlr_Parms_T ca; /* For exception handler */
/********************************************************************/
/* Process the input parameters. */
/********************************************************************/
/* Use the default port if one is not specified. */
if (argc &lt; 2) {
port = DEFAULT_PORT;
}
else {
port = atoi(argv[1]);
}
/********************************************************************/
/* Initialize the server environment. */
/********************************************************************/
/* Initialize for environment variables. */
Qp0zInitEnv();
/* Change to default directory. */
chdir(server_dir);
/* Initialize the server's profile handle. */
QSYGETPH(server_profile, no_pwd, server_ph, &amp;error);
if (error.Bytes_Available != 0) {
LogError("Could not get profile handle for server, "
"QSYGETPH() failed with exception %7.7s\n",
error.Exception_Id);
exit(1);
}
/********************************************************************/
/* Set up the listening socket. */
/********************************************************************/
/* Create a socket. */
if ((sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) &lt; 0) {
LogError("socket() failed, errno=%d\n", errno);
exit(1);
}
#pragma cancel_handler(CleanupHandler, sfd)
#pragma exception_handler(Cleanup, ca, _C1_ALL, _C2_ALL)
/* Allow re-use of this socket address. */
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&amp;on,
sizeof(int)) != 0) {
LogError("setsockopt() failed, errno=%d\n", errno);
exit(1);
}
/* Bind to a port. */
memset(&amp;my_addr, '\0', sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = port;
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sfd, (struct sockaddr *)&amp;my_addr, sizeof(my_addr)) != 0) {
LogError("bind() failed for port %d, errno=%d\n", port, errno);
close(sfd);
exit(1);
}
/* Make this a listening socket. */
if (listen(sfd, 10) != 0) {
LogError("listen() failed, errno=%d\n", errno);
close(sfd);
exit(1);
}
/********************************************************************/
/* Accept connections from clients. */
/********************************************************************/
while (1) {
if ((cfd = accept(sfd, NULL, 0)) &lt; 0) {
LogError("accept() failed, errno=%d\n", errno);
close(sfd);
exit(1);
}
/* Read the user profile and password from the client. The client
sends two null-terminated strings - the first one is the user
profile and the second one is the password. */
if (GetString(cfd, profile, 11) != 0) {
getpeername(cfd, (struct sockaddr *)&amp;client_addr, &amp;client_addr_len);
LogError("Could not read profile from client at %s, port %hu\n",
inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
close(cfd);
continue;
}
if (GetString(cfd, password, 11) != 0) {
getpeername(cfd, (struct sockaddr *)&amp;client_addr, &amp;client_addr_len);
LogError("Could not read password from client at %s, port %hu\n",
inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
close(cfd);
continue;
}
/* Check for the special values that turn off password checking in QSYGETPH(). */
if ((profile[0] == '*') || (password[0] == '*')) {
getpeername(cfd, (struct sockaddr *)&amp;client_addr, &amp;client_addr_len);
LogError("Invalid password sent from client at %s, port %hu\n",
inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
close(cfd);
continue;
}
/* QSYGETPH() requires that the profile be exactly ten characters,
left-aligned in the field, and padded with blanks. */
strtoupper(profile);
sprintf(sy_profile, "%-10.10s", profile);
/* Get the profile handle for the client's user profile. */
QSYGETPH(sy_profile, password, client_ph, &amp;error, strlen(password), 0);
if (error.Bytes_Available != 0) {
LogError("Could not get profile handle for profile %s, "
"QSYGETPH() failed with exception %7.7s\n",
sy_profile, error.Exception_Id);
SendError(cfd, "Could not get profile handle for profile %s\n",
sy_profile);
close(cfd);
continue;
}
/* Switch to client's user profile. */
QWTSETP(client_ph, &amp;error);
if (error.Bytes_Available != 0) {
LogError("Could not switch to profile %s, "
"QWTSETP() failed with exception %7.7s\n",
sy_profile, error.Exception_Id);
SendError(cfd, "Could not switch to profile %s\n", sy_profile);
QSYRLSPH(client_ph, NULL);
close(cfd);
continue;
}
/* Get the info for this user profile. */
if ((cpw = getpwnam(profile)) == NULL) {
/* Log error. */
LogError("Could not retrieve information for profile %s, "
"getpwnam() failed with errno=%d\n",
profile, errno);
SendError(cfd, "Could not retrieve information for profile %s\n",
profile);
/* Switch back to the server's user profile. */
QWTSETP(server_ph, &amp;error);
if (error.Bytes_Available != 0) {
LogError("Could not switch back to server's profile, "
"QWTSETP() failed with exception %7.7s\n",
error.Exception_Id);
break;
}
/* Release the client's profile handle. */
QSYRLSPH(client_ph, NULL);
if (error.Bytes_Available != 0) {
LogError("Could not release client's profile handle, "
"QSYRLSPH() failed with exception %7.7s\n",
error.Exception_Id);
break;
}
close(cfd);
continue;
}
/* Build the file descriptor map for the child. */
fd_count = 3;
fd_map[0] = cfd;
fd_map[1] = cfd;
fd_map[2] = cfd;
/* Build the argv array for the child. */
args[0] = qsh_pgm;
args[1] = "-login"; /* Do login processing */
args[2] = "-s"; /* Take input from stdin */
args[3] = "-i"; /* Run as an interactive shell */
args[4] = NULL;
/* Build the environ array for the child. */
sprintf(home_var, "HOME=%s", cpw-&gt;pw_dir);
sprintf(logname_var, "LOGNAME=%s", cpw-&gt;pw_name);
envs[0] = home_var;
envs[1] = logname_var;
envs[2] = path_var;
envs[3] = stdio_var;
envs[4] = terminal_type_var;
envs[5] = nlspath_var;
envs[6] = NULL;
/* Set up the inheritance structure. */
memset(&amp;inherit, '\0', sizeof(struct inheritance));
inherit.flags = SPAWN_SETTHREAD_NP;
inherit.pgroup = SPAWN_NEWPGROUP;
/* Change to the home directory for the client. The child process
inherits this as its current working directory. */
chdir(cpw-&gt;pw_dir);
/* Start a child process running the shell interpreter. */
if (spawn(args[0], fd_count, fd_map, &amp;inherit, args, envs) &lt; 0) {
LogError("Could not start qsh process, spawn() failed with "
"errno=%d\n", errno);
SendError(cfd, "Could not start qsh process\n");
}
/* Clean up for the next connection. */
chdir(server_dir);
close(cfd);
/* Switch back to server's user profile. */
QWTSETP(server_ph, &amp;error);
if (error.Bytes_Available != 0) {
LogError("Could not switch back to server's profile, "
"QWTSETP() failed with exception %7.7s\n",
error.Exception_Id);
break;
}
/* Release the client's profile handle. */
QSYRLSPH(client_ph, &amp;error);
if (error.Bytes_Available != 0) {
LogError("Could not release client's profile handle, "
"QSYRLSPH() failed with exception %7.7s\n",
error.Exception_Id);
break;
}
} /* End of while */
/* Clean up. */
close(sfd);
#pragma disable_handler /* Exception handler */
#pragma disable_handler /* Cancel handler */
exit(0);
return 0;
/* Exception handler */
Cleanup:
LogError("Unexpected exception %7.7s\n", ca.Msg_Id);
close(sfd);
exit(1);
} /* End of main() */
/*
* Convert a string to uppercase.
*/
int
strtoupper(char *string)
{
for ( ; *string != '\0'; ++string)
*string = toupper(*string);
return 0;
} /* End of strtoupper() */
/*
* Read a string from a socket.
*/
int
GetString(int fd, char *buffer, size_t nbytes)
{
char c;
do {
if (read(fd, &amp;c, 1) != 1) {
return -1;
}
*buffer++ = c;
if (--nbytes == 0) {
return 0;
}
} while (c != '\0');
return 0;
} /* End of GetString() */
/*
* Write an error message to the log file.
*/
void LogError(char *format, ...)
{
va_list ap;
time_t now; /* Time stamp */
/* If needed, open the log file. */
if (log_fp == NULL) {
log_fp = fopen(log_file, "w");
if (log_fp == NULL) {
return;
}
}
/* Write timestamp to the log file. */
now=time(NULL);
fprintf(log_fp, "\n%s", ctime(&amp;now));
/* Write the formatted string to the log file. */
va_start(ap, format);
vfprintf(log_fp, format, ap);
va_end(ap);
/* Flush output to log file. */
fflush(log_fp);
return;
} /* End of LogError() */
/*
* Send an error message to the client.
*/
void SendError(int fd, char *format, ...)
{
va_list ap;
/* Build the formatted string. */
va_start(ap, format);
vsprintf(log_buffer, format, ap);
va_end(ap);
/* Write the formatted string. */
write(fd, log_buffer, strlen(log_buffer));
return;
} /* End of SendError() */
/*
* Handler to clean up when the program is canceled.
*/
void CleanupHandler(_CNL_Hndlr_Parms_T *cancel_info)
{
int sfd;
sfd = *((int *)cancel_info-&gt;Com_Area);
close(sfd);
} /* End of CleanupHandler() */
</pre>
<p><strong>Note:</strong> By using the code examples, you agree to the terms of the <a href="codedisclaimer.htm">Code license and disclaimer information</a>.</p>
</body>
</html>