Archive

Archive for the ‘书山有路’ Category

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。

2011年买的书

January 2nd, 2012 1 comment

到目前为止,2011年应该是我买书最多的一年,不管从价钱上,还是从数量上看。翻了一下,有以下这些:

小说类:

  1. 《His Dark Materials》三部曲:《The Golden Compass》,《The Subtle Knife》,《The Amber Spyglass》。这三本都看完了。
  2. 《Kingkiller Chronicles》两部:《The Name of the Wind》,《The Wise Man’s Fear》。没看。

技术类:

  1. 《The Design of The Unix Operating System》。看了一遍,有时间的话,想再看一遍。
  2. 《A Practical Guide to Linux Commands, Editors, and Shell Programming》。看了一些。今年会继续看,要把它完成。
  3. 《Understanding the Linux Kernel》。看了三章。今天会继续看,先把感兴趣的部分看了。
  4. 《Understanding Linux Network Internals》。没看。今年若有时间,会开始看的。优先级比较低。
  5. 《Introduction to Algorithms》。没看。今年打算认真看一遍。
  6. 《Programming Windows Phone 7 – Microsoft Silverlight Edition》。没看,刚买的。为了WP7开发而买的,作为参考书用。
  7. 《The C# Programming Language》。没看,刚买的。也是为了WP7开发买的,没学过C#,最近就会开始读。

面试类:

  1. 《Cracking the Coding Interview: 150 Programming Questions and Solutions》。看了大部分。剩下的最近会看完。
  2. 《The Google Resume》。没有看。

 

读书方面,今年读的也算比较多,不限于以上这些书,比如用手机和kindle就看了好几部小说和自传,《明朝那些事儿》,韩寒的作品,李开复和罗永浩的自传等等。技术方面的书,出来以上列的,还看了《Advanced Programming in the Unix Environment》和《C++ Primer》。APUE这书算是看第二遍,第一遍看的比较匆忙,没有练书上的代码,所以有了第二遍。第二遍还没有完成,过了一半吧,今年上半年要完成它。《C++ Primer》完整地看了一遍,并为了准备面试浏览了两遍。这书主要是理论,要记得的东西太多。

 

列一下2012要读的书,包括已读的,在读的,未读的:

  • 《Advanced Programming in the Unix Environment》
  • 《A Practical Guide to Linux Commands, Editors, and Shell Programming》
  • 《Understanding the Linux Kernel》
  • 《Understanding Linux Network Internals》
  • 《Introduction to Algorithms》
  • 《Programming Windows Phone 7 – Microsoft Silverlight Edition》
  • 《The C# Programming Language》
  • 《Cracking the Coding Interview: 150 Programming Questions and Solutions》

任务很艰巨。

革命尚未成功,同志仍需努力。

人生就是不停的战斗。

Categories: 书山有路 Tags:

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: , ,