Archive

Posts Tagged ‘APUE2e’

APUE2e Exercise 10.6 – Solution C

February 16th, 2012 No comments

Using Standard I/O Library to read and write the file. Rather than using signal function, I used sigaction. Thus don’t need to call TELL_WAIT in the for body.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/**   
 * apue-chap10: exercise10-6c.c
 *
 * Description: Standard I/O Library + sigaction
 *
 * Created On: Feb 16, 2012 
 *
 * @author: Huang Zhu
 *
 * @email: zhuhuang.zp@gmail.com
 */
 
#include <apueerr.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
 
#define __USE_POSIX199309	1
 
static volatile sig_atomic_t sigflag;
static sigset_t newmask, oldmask, zeromask;
 
struct sigaction act, oact1, oact2;
 
static void sig_usr(int signo)
{
	sigflag = 1;
}
 
void TELL_WAIT(void)
{
	act.sa_handler = sig_usr;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
 
	if(sigaction(SIGUSR1, &act, &oact1) < 0)
		err_sys("sigaction SIGUSR1 error");
 
	if(sigaction(SIGUSR2, &act, &oact2) < 0)
		err_sys("sigaction SIGUSR2 error");
 
	sigemptyset(&zeromask);
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGUSR1);
	sigaddset(&newmask, SIGUSR2);
 
	//block SIGUSR1 and SIGUSR2, and save current signal mask
	if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
		perror("SIG_BLOCK error");
}
 
void TELL_PARENT(pid_t pid)
{
	kill(pid, SIGUSR2);
}
 
void TELL_CHILD(pid_t pid)
{
	kill(pid, SIGUSR1);
}
 
void WAIT_PARENT(void)
{
	while(sigflag == 0)
		sigsuspend(&zeromask);  //set mask and sleep and wait
	sigflag = 0;
 
	if(sigprocmask(SIG_SETMASK, &oldmask,  NULL) < 0)
		perror("SIG_SETMASK error");
}
 
void WAIT_CHILD(void)
{
	while(sigflag == 0)
		sigsuspend(&zeromask);  //set mask and sleep and wait
	sigflag = 0;
 
	if(sigprocmask(SIG_SETMASK, &oldmask,  NULL) < 0)
		perror("SIG_SETMASK error");
}
 
int main(void)
{
	int fd, pid, ppid, counter, round = 5;
	FILE* fp;
	char *filename = "counter.file";
	int i, j;
 
	if((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
		err_sys("open error");
 
	if((fp = fdopen(fd, "r+")) == NULL )
		err_sys("fdopen error");
 
	if(fputc(0, fp) != EOF){
		printf("Writing initial value of the counter: 0\n");
		fflush(fp); //if fflush is not used, the change of counter cannot be seen instantly by other readers.
	}
 
	if(ferror(fp))
		err_sys("fputc error");
 
	TELL_WAIT();
 
	if((pid = fork()) < 0){
		err_sys("fork error");
	}else if(pid == 0){ //child
		ppid = getppid();
 
		for(i = 0;  i < round; i++){
			printf("\nChild: round %d\n", i+1);
			counter = -1;
 
			rewind(fp);
			counter = fgetc(fp);
			printf("Child: read counter from the file: %d\n", counter);
 
			counter++;
			printf("Child: increase counter to: %d\n", counter);
 
			rewind(fp);
			if(fputc(counter, fp) != EOF){
				printf("Child: Write counter to the file: %d\n", counter);
				fflush(fp);
			}
			if(ferror(fp))
				err_sys("Child: fputc error");
 
			TELL_PARENT(ppid);
 
			WAIT_PARENT();
		}
 
		counter = -1;
		rewind(fp);
		counter = fgetc(fp);
		printf("\nChild: read counter from the file: %d\n", counter);
 
		exit(0);
	}else{ //parent
		for(j = 0; j < round; j++){
			WAIT_CHILD();
			printf("\nParent: round %d\n", j+1);
			counter = -1;
 
			rewind(fp);
			counter = fgetc(fp);
			printf("Parent: read counter from the file: %d\n", counter);
 
			counter++;
			printf("Parent: increase counter to: %d\n", counter);
 
			rewind(fp);
			if(fputc(counter, fp) != EOF){
				printf("Parent: Write counter to the file: %d\n", counter);
				fflush(fp);
			}
			if(ferror(fp))
				err_sys("Parent: fputc error");
 
			TELL_CHILD(pid);
		}
	}
 
	fclose(fp);
	close(fd);
	return 0;
}

APUE2e Exercise 10.6 – Solution B

February 16th, 2012 No comments

Using Standard I/O Library to read and write the file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/**   
 * apue-chap10: exercise10-6b.c
 *
 * Description: Standard I/O Library
 *
 * Created On: Feb 16, 2012 
 *
 * @author: Huang Zhu
 *
 * @email: zhuhuang.zp@gmail.com
 */
 
 
#include <apueerr.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
 
static volatile sig_atomic_t sigflag;
static sigset_t newmask, oldmask, zeromask;
 
static void sig_usr(int signo)
{
	sigflag = 1;
}
 
void TELL_WAIT(void)
{
	if(signal(SIGUSR1, sig_usr) == SIG_ERR)
		perror("signal(SIGUSR1) error");
	if(signal(SIGUSR2, sig_usr) == SIG_ERR)
		perror("signal(SIGUSR2) error");
	sigemptyset(&zeromask);
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGUSR1);
	sigaddset(&newmask, SIGUSR2);
 
	//block SIGUSR1 and SIGUSR2, and save current signal mask
	if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
		perror("SIG_BLOCK error");
}
 
void TELL_PARENT(pid_t pid)
{
	kill(pid, SIGUSR2);
}
 
void TELL_CHILD(pid_t pid)
{
	kill(pid, SIGUSR1);
}
 
void WAIT_PARENT(void)
{
	while(sigflag == 0)
		sigsuspend(&zeromask);  //set mask and sleep and wait
	sigflag = 0;
 
	if(sigprocmask(SIG_SETMASK, &oldmask,  NULL) < 0)
		perror("SIG_SETMASK error");
}
 
void WAIT_CHILD(void)
{
	while(sigflag == 0)
		sigsuspend(&zeromask);  //set mask and sleep and wait
	sigflag = 0;
 
	if(sigprocmask(SIG_SETMASK, &oldmask,  NULL) < 0)
		perror("SIG_SETMASK error");
}
 
int main(void)
{
	int fd, pid, ppid, counter, round = 5;
	FILE* fp;
	char *filename = "counter.file";
	int i, j;
 
	if((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
		err_sys("open error");
 
	if((fp = fdopen(fd, "r+")) == NULL )
		err_sys("fdopen error");
 
	if(fputc(0, fp) != EOF){
		printf("Writing initial value of the counter: 0\n");
		fflush(fp); //if fflush is not used, the change of counter cannot be seen instantly by other readers.
	}
 
	if(ferror(fp))
		err_sys("fputc error");
 
	if((pid = fork()) < 0){
		err_sys("fork error");
	}else if(pid == 0){ //child
		ppid = getppid();
 
		for(i = 0;  i < round; i++){
			printf("\nChild: round %d\n", i+1);
 
			TELL_WAIT();
 
			counter = -1;
 
			rewind(fp);
			counter = fgetc(fp);
			printf("Child: read counter from the file: %d\n", counter);
 
			counter++;
			printf("Child: increase counter to: %d\n", counter);
 
			rewind(fp);
			if(fputc(counter, fp) != EOF){
				printf("Child: Write counter to the file: %d\n", counter);
				fflush(fp);
			}
			if(ferror(fp))
				err_sys("Child: fputc error");
 
			TELL_PARENT(ppid);
 
			WAIT_PARENT();
		}
 
		counter = -1;
		rewind(fp);
		counter = fgetc(fp);
		printf("\nChild: read counter from the file: %d\n", counter);
 
		exit(0);
	}else{ //parent
		for(j = 0; j < round; j++){
			TELL_WAIT(); //set up signal handler
 
			WAIT_CHILD();
			printf("\nParent: round %d\n", j+1);
			counter = -1;
 
			rewind(fp);
			counter = fgetc(fp);
			printf("Parent: read counter from the file: %d\n", counter);
 
			counter++;
			printf("Parent: increase counter to: %d\n", counter);
 
			rewind(fp);
			if(fputc(counter, fp) != EOF){
				printf("Parent: Write counter to the file: %d\n", counter);
				fflush(fp);
			}
			if(ferror(fp))
				err_sys("Parent: fputc error");
 
			TELL_CHILD(pid);
		}
	}
 
	fclose(fp);
	close(fd);
	return 0;
}

APUE2e Exercise 10.6 – Solution A

February 16th, 2012 No comments

Using File I/O to read and write the file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/**   
 * apue-chap10: exercise10-6a.c
 *
 * Description: FILE I/O
 *
 * Created On: Feb 15, 2012 
 *
 * @author: Huang Zhu
 *
 * @email: zhuhuang.zp@gmail.com
 */
 
#include <apueerr.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
 
static volatile sig_atomic_t sigflag;
static sigset_t newmask, oldmask, zeromask;
 
static void sig_usr(int signo)
{
	sigflag = 1;
}
 
void TELL_WAIT(void)
{
	if(signal(SIGUSR1, sig_usr) == SIG_ERR)
		perror("signal(SIGUSR1) error");
	if(signal(SIGUSR2, sig_usr) == SIG_ERR)
		perror("signal(SIGUSR2) error");
	sigemptyset(&zeromask);
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGUSR1);
	sigaddset(&newmask, SIGUSR2);
 
	//block SIGUSR1 and SIGUSR2, and save current signal mask
	if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
		perror("SIG_BLOCK error");
}
 
void TELL_PARENT(pid_t pid)
{
	kill(pid, SIGUSR2);
}
 
void TELL_CHILD(pid_t pid)
{
	kill(pid, SIGUSR1);
}
 
void WAIT_PARENT(void)
{
	while(sigflag == 0)
		sigsuspend(&zeromask);  //set mask and sleep and wait
	sigflag = 0;
 
	if(sigprocmask(SIG_SETMASK, &oldmask,  NULL) < 0)
		perror("SIG_SETMASK error");
}
 
void WAIT_CHILD(void)
{
	while(sigflag == 0)
		sigsuspend(&zeromask);  //set mask and sleep and wait
	sigflag = 0;
 
	if(sigprocmask(SIG_SETMASK, &oldmask,  NULL) < 0)
		perror("SIG_SETMASK error");
}
 
int main(void)
{
	int fd, pid, ppid, counter, round = 5;
	char *filename = "counter.file";
	char *rbuf, *wbuf;
	int i, j;
 
	rbuf = (char *)malloc(sizeof(int));
	wbuf = (char *)malloc(sizeof(int));
 
	if((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
		err_sys("open error");
 
	if(sprintf(wbuf, "%d", 0) < 0)
		err_sys("sprintf error");
 
	if(write(fd, wbuf, sizeof(int)) > 0 ){
		printf("Writing initial value of the counter: %s\n", wbuf);
		fsync(fd);
	}
 
	if((pid = fork()) < 0){
		err_sys("fork error");
	}else if(pid == 0){ //child
		ppid = getppid();
 
		for(i = 0;  i < round; i++){
			printf("\nChild: round %d\n", i+1);
 
			TELL_WAIT(); //set up signal handler
 
			counter = -1;
 
			if(lseek(fd, 0, SEEK_SET) != 0)
				err_sys("Child: lseek error");
			if(read(fd, rbuf, sizeof(int)) < 0)
				err_sys("Child: read error");
			if(sscanf(rbuf, "%d", &counter) == EOF)
				err_sys("Child: sscanf error");
			printf("Child: read counter from the file: %d\n", counter);
 
			counter++;
			printf("Child: increase counter to: %d\n", counter);
 
			if(lseek(fd, 0, SEEK_SET) != 0)
				err_sys("Child: lseek error");
			if(sprintf(wbuf, "%d", counter) < 0)
				err_sys("Child: sprintf error");
 
			if(write(fd, wbuf, sizeof(int)) > 0 ){
				printf("Child: Write counter to the file: %s\n", wbuf);
				fsync(fd);
			}
 
			TELL_PARENT(ppid);
 
			WAIT_PARENT();
		}
 
		counter = -1;
		if(lseek(fd, 0, SEEK_SET) != 0)
			err_sys("Child: lseek error");
		if(read(fd, rbuf, sizeof(int)) < 0)
			err_sys("Child: read error");
		if(sscanf(rbuf, "%d", &counter) == EOF)
			err_sys("Child: sscanf error");
		printf("\nChild: read counter from the file: %d\n", counter);
 
		close(fd);
		exit(0);
	}else{ //parent
		for(j = 0; j < round; j++){
			TELL_WAIT(); //set up signal handler
 
			WAIT_CHILD();
			printf("\nParent: round %d\n", j+1);
			counter = -1;
 
			if(lseek(fd, 0, SEEK_SET) != 0)
				err_sys("Parent: lseek error");
			if(read(fd, rbuf, sizeof(int)) < 0)
				err_sys("Parent: read error");
			if(sscanf(rbuf, "%d", &counter) == EOF)
				err_sys("Parent: sscanf error");
			printf("Parent: read counter from the file: %d\n", counter);
 
			counter++;
			printf("Parent: increase counter to: %d\n", counter);
 
			if(lseek(fd, 0, SEEK_SET) != 0)
				err_sys("Parent: lseek error");
			if(sprintf(wbuf, "%d", counter) < 0)
				err_sys("Parent: sprintf error");
 
			if(write(fd, wbuf, sizeof(int)) > 0 ){
				printf("Parent: Write counter to the file: %s\n", wbuf);
				fsync(fd);
			}
 
			TELL_CHILD(pid);
		}
	}
 
	close(fd);
	return 0;
}

APUE2e Exercise 16.3 – Solution B

January 11th, 2012 2 comments

Code for client side is in Figure 16.14 in APUE2e, Page 568.

To compile the program, check this post: posix thread相关函数的编译(undefined reference to `pthread_create’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/**   
 * apue-chap16: exercise16-3B.c
 *
 * Description: multiple threads, multiple endpoint to provide "ruptime" service
 *
 * Created On: Jan 11, 2012 
 *
 * @author: Huang Zhu
 *
 * @email: zhuhuang.zp@gmail.com
 */
 
 
#include <apueerr.h>
#include <pthread.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <sys/select.h>
 
 
#define BUFLEN 128
#define QLEN 10
 
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif
 
typedef struct Server_FD
{
    int fd;
    struct addrinfo addr;
} Server_FD;
 
int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
{
	int sockfd, err;
	int reuse = 1;
 
	if((sockfd = socket(addr->sa_family, type, 0)) < 0)
		return(-1);
 
	if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0){
		err = errno;
		goto errout;
	}
	if(bind(sockfd, addr, alen) < 0){
		err = errno;
		goto errout;
	}
	if(type == SOCK_STREAM || type == SOCK_SEQPACKET){
		if(listen(sockfd, qlen) < 0){
			err = errno;
			goto errout;
		}
	}
	return(sockfd);
 
	errout:
	close(sockfd);
	errno = err;
	return(-1);
}
 
void
daemonize(const char *cmd)
{
	int					i, fd0, fd1, fd2;
	pid_t				pid;
	struct rlimit		rl;
	struct sigaction	sa;
 
	/*
	 * Clear file creation mask.
	 */
	umask(0);
 
	/*
	 * Get maximum number of file descriptors.
	 */
	if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
		err_quit("%s: can't get file limit", cmd);
 
	/*
	 * Become a session leader to lose controlling TTY.
	 */
	if ((pid = fork()) < 0)
		err_quit("%s: can't fork", cmd);
	else if (pid != 0) /* parent */
		exit(0);
	setsid();
 
	/*
	 * Ensure future opens won't allocate controlling TTYs.
	 */
	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (sigaction(SIGHUP, &sa, NULL) < 0)
		err_quit("%s: can't ignore SIGHUP");
	if ((pid = fork()) < 0)
		err_quit("%s: can't fork", cmd);
	else if (pid != 0) /* parent */
		exit(0);
 
	/*
	 * Change the current working directory to the root so
	 * we won't prevent file systems from being unmounted.
	 */
	if (chdir("/") < 0)
		err_quit("%s: can't change directory to /");
 
	/*
	 * Close all open file descriptors.
	 */
	if (rl.rlim_max == RLIM_INFINITY)
		rl.rlim_max = 1024;
	for (i = 0; i < rl.rlim_max; i++)
		close(i);
 
	/*
	 * Attach file descriptors 0, 1, and 2 to /dev/null.
	 */
	fd0 = open("/dev/null", O_RDWR);
	fd1 = dup(0);
	fd2 = dup(0);
 
	/*
	 * Initialize the log file.
	 */
	openlog(cmd, LOG_CONS, LOG_DAEMON);
	if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
		syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
		  fd0, fd1, fd2);
		exit(1);
	}
}
 
void* serve_client(void* fd)
{
	int clientfd;
	int sockfd;
	FILE *fp;
	char buf[BUFLEN];
	pthread_t tid;
 
	tid = pthread_self();
 
	sockfd = (int)fd;
	clientfd = accept(sockfd, NULL, NULL); //we don't care about client's identity
	if(clientfd < 0){
		syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));
		exit(1);
	}
 
	//popen, pclose: apue2e, page 503
	if((fp = popen("/usr/bin/uptime", "r")) == NULL){
		sprintf(buf, "error: %s\n", strerror(errno));
		send(clientfd, buf, strlen(buf), 0);
	}else{
		while(fgets(buf, BUFLEN, fp) != NULL)
			send(clientfd, buf, strlen(buf), 0);
 
		//prove that the thread works
		sprintf(buf, " thread id: %ld\n", tid);
		send(clientfd, buf, strlen(buf), 0);
 
		pclose(fp);
	}
	close(clientfd);
 
	return((void*)0);
}
 
void serve(fd_set *set, int maxfd, Server_FD *fdarray, int maxindex)
{
	int serverfd;
	int ready;
	int i;
 
	pthread_t tid;
	int err;
 
	for(;;){
		if((ready = select(maxfd+1, set, NULL, NULL, NULL)) > 0){
			for(i = 0; i < maxindex; i++)
			{
				serverfd = fdarray[i].fd;
				if(FD_ISSET(serverfd, set)){
					err = pthread_create(&tid, NULL, serve_client, (void *)serverfd);
					if(err != 0){
						syslog(LOG_ERR, "ruptimed: pthread_create error: %s", strerror(err));
					}
				}
			}
		}
	}
}
 
int main(int argc, char *argv[])
{
	struct addrinfo *ailist, *aip;
	struct addrinfo hint;
	int sockfd, err, n;
	char *host;
	fd_set sockset; //read sets
	int maxfd = -1; //maximum socket descriptor
	Server_FD fdarray[FD_SETSIZE]; //array to store server sockets waiting for connection requests
	int maxindex = 0; //the index past the last effective element in array fdarray
 
	if(argc != 1)
		err_quit("usage: ruptimed");
#ifdef _SC_HOST_NAME_MAX
	n = sysconf(_SC_HOST_NAME_MAX);
	if(n < 0)
#endif
		n = HOST_NAME_MAX;
	host = malloc(n);
	if(host == NULL)
		err_sys("malloc error");
	if(gethostname(host, n) < 0)
		err_sys("gethostname error");
 
	printf("Host Name: %s\n", host);
 
	daemonize("ruptimed");
 
	hint.ai_flags = AI_CANONNAME;
	hint.ai_family = 0;
	hint.ai_socktype = SOCK_STREAM;
	hint.ai_protocol = 0;
	hint.ai_addrlen = 0;
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;
	if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0){
		syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", gai_strerror(err));
		exit(1);
	}
 
	FD_ZERO(&sockset);
 
	for(aip = ailist; aip != NULL; aip = aip->ai_next){
		if((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN)) >= 0){
			if(sockfd > maxfd)
				maxfd = sockfd;
 
			//add the socket to fd_set sockset
			FD_SET(sockfd, &sockset);
 
			//add the socket and corresponding address to array fdarray
			fdarray[maxindex].fd = sockfd;
			fdarray[maxindex].addr = *aip;
			maxindex++;
		}
	}
 
	if(maxfd >=0)
		serve(&sockset, maxfd, fdarray, maxindex);
 
	exit(1);
}

APUE2e Exercise 16.3 – Solution A

January 11th, 2012 No comments

Below is the code for the server side. Code for client side is in Figure 16.14 in APUE2e, Page 568.

To compile the program, check this post: posix thread相关函数的编译(undefined reference to `pthread_create’)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/**   
 * apue-chap16: exercise16-3A.c
 *
 * Description: single thread, multiple endpoint to provide "ruptime" service
 *
 * Created On: Jan 11, 2012 
 *
 * @author: Huang Zhu
 *
 * @email: zhuhuang.zp@gmail.com
 */
 
 
#include <apueerr.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <sys/select.h>
 
#define BUFLEN 128
#define QLEN 10
 
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif
 
 
typedef struct Server_FD
{
    int fd;
    struct addrinfo addr;
} Server_FD;
 
 
int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
{
	int sockfd, err;
	int reuse = 1;
 
	if((sockfd = socket(addr->sa_family, type, 0)) < 0)
		return(-1);
 
	if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0){
		err = errno;
		goto errout;
	}
	if(bind(sockfd, addr, alen) < 0){
		err = errno;
		goto errout;
	}
	if(type == SOCK_STREAM || type == SOCK_SEQPACKET){
		if(listen(sockfd, qlen) < 0){
			err = errno;
			goto errout;
		}
	}
	return(sockfd);
 
	errout:
	close(sockfd);
	errno = err;
	return(-1);
}
 
 
void daemonize(const char *cmd)
{
	int					i, fd0, fd1, fd2;
	pid_t				pid;
	struct rlimit		rl;
	struct sigaction	sa;
 
	/*
	 * Clear file creation mask.
	 */
	umask(0);
 
	/*
	 * Get maximum number of file descriptors.
	 */
	if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
		err_quit("%s: can't get file limit", cmd);
 
	/*
	 * Become a session leader to lose controlling TTY.
	 */
	if ((pid = fork()) < 0)
		err_quit("%s: can't fork", cmd);
	else if (pid != 0) /* parent */
		exit(0);
	setsid();
 
	/*
	 * Ensure future opens won't allocate controlling TTYs.
	 */
	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (sigaction(SIGHUP, &sa, NULL) < 0)
		err_quit("%s: can't ignore SIGHUP");
	if ((pid = fork()) < 0)
		err_quit("%s: can't fork", cmd);
	else if (pid != 0) /* parent */
		exit(0);
 
	/*
	 * Change the current working directory to the root so
	 * we won't prevent file systems from being unmounted.
	 */
	if (chdir("/") < 0)
		err_quit("%s: can't change directory to /");
 
	/*
	 * Close all open file descriptors.
	 */
	if (rl.rlim_max == RLIM_INFINITY)
		rl.rlim_max = 1024;
	for (i = 0; i < rl.rlim_max; i++)
		close(i);
 
	/*
	 * Attach file descriptors 0, 1, and 2 to /dev/null.
	 */
	fd0 = open("/dev/null", O_RDWR);
	fd1 = dup(0);
	fd2 = dup(0);
 
	/*
	 * Initialize the log file.
	 */
	openlog(cmd, LOG_CONS, LOG_DAEMON);
	if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
		syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
		  fd0, fd1, fd2);
		exit(1);
	}
}
 
 
void serve(fd_set *set, int maxfd, Server_FD *fdarray, int maxindex)
{
	int clientfd;
	int serverfd;
	int ready;
	FILE *fp;
	char buf[BUFLEN];
	int i;
 
	for(;;){
		//A socket with pending connect requests will appear to be readable. Use only read sets for select.
		if((ready = select(maxfd+1, set, NULL, NULL, NULL)) > 0){
			for(i = 0; i < maxindex; i++)
			{
				serverfd = fdarray[i].fd;
				if(FD_ISSET(serverfd, set)){
					clientfd = accept(serverfd, NULL, NULL); //we don't care about client's identity
					if(clientfd < 0){
						syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));
						exit(1);
					}
 
					//popen, pclose: apue2e, page 503
					if((fp = popen("/usr/bin/uptime", "r")) == NULL){
						sprintf(buf, "error: %s\n", strerror(errno));
						send(clientfd, buf, strlen(buf), 0);
					}else{
						while(fgets(buf, BUFLEN, fp) != NULL)
							send(clientfd, buf, strlen(buf), 0);
						pclose(fp);
					}
					close(clientfd);
				}
			}
		}
	}
}
 
 
int main(int argc, char *argv[])
{
	struct addrinfo *ailist, *aip;
	struct addrinfo hint;
	int sockfd, err, n;
	char *host;
	fd_set sockset; //read sets
	int maxfd = -1; //maximum socket descriptor
	Server_FD fdarray[FD_SETSIZE]; //array to store server sockets waiting for connection requests
	int maxindex = 0; //the index past the last effective element in array fdarray
 
	if(argc != 1)
		err_quit("usage: ruptimed");
#ifdef _SC_HOST_NAME_MAX
	n = sysconf(_SC_HOST_NAME_MAX);
	if(n < 0)
#endif
		n = HOST_NAME_MAX;
	host = malloc(n);
	if(host == NULL)
		err_sys("malloc error");
	if(gethostname(host, n) < 0)
		err_sys("gethostname error");
 
	printf("Host Name: %s\n", host);
 
	daemonize("ruptimed");
 
	hint.ai_flags = AI_CANONNAME;
	hint.ai_family = 0;
	hint.ai_socktype = SOCK_STREAM;
	hint.ai_protocol = 0;
	hint.ai_addrlen = 0;
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;
	if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0){
		syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", gai_strerror(err));
		exit(1);
	}
 
	FD_ZERO(&sockset);
	for(aip = ailist; aip != NULL; aip = aip->ai_next){
		if((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN)) >= 0){
			if(sockfd > maxfd)
				maxfd = sockfd;
 
			//add the socket to fd_set sockset
			FD_SET(sockfd, &sockset);
 
			//add the socket and corresponding address to array fdarray
			fdarray[maxindex].fd = sockfd;
			fdarray[maxindex].addr = *aip;
			maxindex++;
		}
	}
 
	if(maxfd >=0)
		serve(&sockset, maxfd, fdarray, maxindex);
 
	exit(1);
}

posix thread相关函数的编译(undefined reference to `pthread_create’)

January 11th, 2012 2 comments

在解APUE2e Exercise 16.3的问题时,尝试着用thread来应答client请求(代码见exercise16-3b.c)。当发现server的某个socket有请求到达时(select函数),创建一个thread,让这个thread accept客户端的请求,然后发送相应的信息。在eclipse上写完程序后,准备编译,却得到undefined reference to `pthread_create’的错误。本以为是参数写错了,查了多遍,都没有问题。然后尝试着用gcc编译,也得到一样的错误信息。Google一下才知道,pthread所在的library并不在编译路径里,需要先链接对应的library才行。

解决办法:
eclipse:
Project Properties -> C/C++ Build -> Settings -> Tool Setting -> GCC C Linker -> Libraries -> Add ‘pthread’,如下图所示。

add build library for pthread

gcc:
加入编译选项lpthread,比如: gcc -o ruptimed exercise16-3b.c -lpthread。

signal function, signal handler, and signal mask on Ubuntu

December 16th, 2011 No comments

When I was trying to run the program in Figure 10.23 in APUE2e using Ubuntu command line, after I typed Ctrl+C twice, the program terminated, which meant that the second SIGINT signal generated was not caught by the signal handler (sig_int) installed previously. This was different from the book’s running results. So I added a checking line in sig_int to check whether the signal handler of SIGINT was changed after sig_int was called. The running result revealed that the signal handler of SIGINT has been set to default SIG_DFL, which meant the handler installed previously was called only one time. To make the program catch the SIGINT signal continuously, an additional call to signal had to be called in sig_int: signal(SIGINT, sig_int). I checked the Ubuntu manual for signal function and it said that:

If the disposition is set to a function, then first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum. If invocation of the handler caused the signal to be blocked, then the signal is unblocked upon return from the handler.

Read more…

APUE2e Exercise 8.7: close-on-exec flag

November 11th, 2011 No comments
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
 * exercise8-7.c
 *
 *  Created on: Nov 11, 2011
 *      Author: zhuhuang
 */
 
 
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
 
int main(void)
{
	DIR *dir;
	int filedes1, filedes2;
	int fdflag1, fdflag2;
	struct dirent *direntry;
 
	filedes1 = open("/", O_RDONLY);
 
	//file descriptor flag before calling opendir. it is off.
	fdflag1 = fcntl(filedes1, F_GETFD);
	if(fdflag1 & FD_CLOEXEC)
		printf("filedes1: close-on-exec flag is onn");
	else
		printf("filedes1: close-on-exec flag is offn");
 
	//See Page 234 on APUE2e, opendir function will set the close-on-exec flag for the descriptor filedes
	dir = fdopendir(filedes1);
	while((direntry = readdir(dir)) != NULL)
	{
		printf("%sn", direntry->d_name);
	}
 
	//file descriptor flag after calling opendir. it is on now.
	fdflag1 = fcntl(filedes1, F_GETFD);
	if(fdflag1 & FD_CLOEXEC)
		printf("filedes1: close-on-exec flag is onn");
	else
		printf("filedes1: close-on-exec flag is offn");
 
	//set close-on-exec flag operation on filedes1 won't affect filedes2
	filedes2 = open("/", O_RDONLY);
	fdflag2 = fcntl(filedes2, F_GETFD);
	if(fdflag2 & FD_CLOEXEC)
		printf("filedes2: close-on-exec flag is onn");
	else
		printf("filedes2: close-on-exec flag is offn");
}

APUE2e Exercise 8.2: vfork v.s. fork

November 10th, 2011 No comments
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
 * exercise8-2.c
 *
 *  Created on: Nov 10, 2011
 *      Author: zhuhuang
 */
 
#include <apueerr.h>
 
int glob = 6;
 
int callvfork(void)
{
	int var=88;
	pid_t pid;
 
	//compare the running results using vfork and fork
 
	/* Using fork
	in main first:4656
	before callvfork
	in callvfork parent:4656
	glob: 6, var: 88
	in main second:4656
	after callvfork
	before anothercall
	in anothercall:4656
	after anothercall
	in callvfork child:4661
	in main second:4661
	after callvfork
	before anothercall
	in anothercall:4661
	after anothercall
	*/
 
	/* Using vfork
	in main first:4608
	before callvfork
	in callvfork child:4613
	in main second:4613
	after callvfork
	before anothercall
	in anothercall:4613
	after anothercall
	in callvfork parent:4608
	glob: 7, var: 2077184
	*/
 
	if((pid = fork()) < 0){
		err_sys("vfork error");
	}else if(pid == 0){
		//the increasing of the variables done by the child changes the values in the parent
		glob++;
		printf("in callvfork child:%dn", getpid());
		return 0;
	}
 
	printf("in callvfork parent:%dn", getpid());
	printf("glob: %d, var: %dn", glob, var);  //var is
}
 
int anothercall(void)
{
	int i;
	int buf[100];
 
	for(i=0;i<100;i++)
		buf[i]=1;
 
	printf("in anothercall:%dn", getpid());
}
 
int main(void)
{
	printf("in main first:%dn", getpid());
 
	printf("before callvforkn");
	callvfork();
 
	//Using vfork: child process continues to execute the following code. But parent process doesn't.
	//Using fork: both child and parent processes execute the following code.
	printf("in main second:%dn", getpid());
 
	printf("after callvforkn");
	printf("before anothercalln");
	anothercall();
	printf("after anothercalln");
 
	exit(0);
}
Categories: 书山有路 Tags: , ,

APUE2e Exercise3.2

September 11th, 2011 2 comments

My implementation for APUE2e Exercise3.2: implement my own dup2 function that performs the same service as the dup2 function. Based on a little testing, it seems to work and behave as the provided dup2 function. I used the dup function to implement mydup2 function. However, I didn’t work on the error handling part, just succeed or fail.
Read more…

Categories: 书山有路 Tags: , ,