-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtransmitter.c
190 lines (166 loc) · 5.55 KB
/
transmitter.c
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
/* File : transmitter.c */
#include "List/list2.h"
/* NETWORKS */
int sockfd, port; // sock file descriptor and port number
struct hostent *server;
struct sockaddr_in receiverAddr; // receiver host information
int receiverAddrLen = sizeof(receiverAddr);
/* FILE AND BUFFERS */
FILE *tFile; // file descriptor
char buf[BUFMAX]; // buffer for read characters
/* WINDOW */
MESGB rxbuf[WINDOWSIZE];
QTYPE trmq = { 0, 0, 0, WINDOWSIZE, rxbuf};
QTYPE *rxq = &trmq;
/* SEND WINDOW */
MESGB rxsend[WINDOWSIZE];
QTYPE trsend = { 0, 0, 0, WINDOWSIZE, rxsend};
QTYPE *rxnd = &trsend;
/* QTEMP */
List temp;
List *ptemp = &temp;
/* FLAGS */
int isSocketOpen; // flag to indicate if connection from socket is done
/* VOIDS */
void *firstChild(void *threadid);
void *secondChild(void *threadid);
void receiveACK(QTYPE *queue,QTYPE *qsend,List *temp);
void sendFrame(QTYPE *queue,QTYPE *qsend);
int main(int argc, char *argv[]) {
pthread_t thread[2];
if (argc < 4) {
// case if arguments are less than specified
printf("Please use the program with arguments: %s <target-ip> <port> <filename>\n", argv[0]);
return 0;
}
if ((server = gethostbyname(argv[1])) == NULL)
error("ERROR: Receiver Address is Unknown or Wrong.\n");
// creating IPv4 data stream socket
printf("Creating socket to %s Port %s...\n", argv[1], argv[2]);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
error("ERROR: Create socket failed.\n");
// flag set to 1 (connection is established)
isSocketOpen = 1;
// initializing the socket host information
memset(&receiverAddr, 0, sizeof(receiverAddr));
receiverAddr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&receiverAddr.sin_addr.s_addr, server->h_length);
receiverAddr.sin_port = htons(atoi(argv[2]));
// open the text file
tFile = fopen(argv[argc-1], "r");
if(tFile == NULL)
error("ERROR: File text not Found.\n");
// sending frame thread
if(pthread_create(&thread[0], NULL, firstChild, 0) != 0)
error("ERROR: Failed to create thread for child. Please free some space.\n");
// receiving ack thread
CreateList(ptemp); //make list for collecting ack
if(pthread_create(&thread[1], NULL, secondChild, 0) != 0)
error("ERROR: Failed to create thread for child. Please free some space.\n");
// parent process
int counter = 0;
while(1) {
int i=0;
do {
buf[i++] = fgetc(tFile);
} while(i<BUFMAX && buf[0]!=EOF);
MESGB msg = { .soh = SOH, .stx = STX, .etx = ETX, .checksum = 0, .msgno = counter++};
strcpy(msg.data, buf);
while(trmq.count==WINDOWSIZE); /*wait for sending process */
trmq.window[trmq.rear] = msg;
trmq.rear++;
if(trmq.rear==WINDOWSIZE) trmq.rear=0;
trmq.count++;
//adding to queue send
while(trsend.count==WINDOWSIZE);
trsend.window[trsend.rear] = msg;
trsend.rear++;
if(trsend.rear>WINDOWSIZE) trsend.rear=0;
trsend.count++;
sleep(DELAY);
if(buf[0]==EOF) break;
}
// sending endfile to receiver, marking the end of data transfer
printf("Sending EOF");
fclose(tFile);
printf("Frame sending done! Closing sockets...\n");
close(sockfd);
isSocketOpen = 0;
printf("Socket Closed!\n");
return 0;
}
void error(const char *message) {
perror(message);
exit(1);
}
void *firstChild(void *threadid) {
//this thread used for sending frame process
while(1) {
sendFrame(rxq,rxnd);
sleep(DELAY);
}
pthread_exit(NULL);
}
void sendFrame(QTYPE *queue,QTYPE *qsend) {
//child process for sending frame
int time=0;
while(qsend->count==0 && (++time)<1500) {
usleep(DELAY);
if(!time%800) printf("waiting for ACK,\n");
}
if(time==1500) {
//adding to queue send
printf("recv timeout, resending HEAD\n");
while(qsend->count==WINDOWSIZE);
qsend->window[qsend->rear] = queue->window[queue->front];
qsend->rear++;
if(qsend->rear>WINDOWSIZE) qsend->rear=0;
qsend->count++;
}
char string[128];
printf("Sending frame no. %d: \'%c\'\n",qsend->window[qsend->front].msgno,qsend->window[qsend->front].data[0]);
memcpy(string,&qsend->window[qsend->front],sizeof(MESGB));
if(sendto(sockfd, string, sizeof(MESGB), 0, (const struct sockaddr *) &receiverAddr, receiverAddrLen) > sizeof(MESGB))
error("ERROR: sendto() sent frame with size more than expected.\n");
qsend->front++;
if(qsend->front>WINDOWSIZE) qsend->front=0;
qsend->count--;
}
void *secondChild(void *threadid) {
//this thread used for receiving ack process
while(1) {
receiveACK(rxq,rxnd,ptemp);
sleep(DELAY);
}
pthread_exit(NULL);
}
void receiveACK(QTYPE *queue,QTYPE *qsend, List *temp) {
//child process for receiving ack
struct sockaddr_in srcAddr;
int srcLen = sizeof(srcAddr);
char string[128];
RESPL *rsp = (RESPL *) malloc(sizeof(RESPL));
int wait = 1;
if(recvfrom(sockfd, string, sizeof(RESPL), 0, (struct sockaddr *) &srcAddr, &srcLen) <= sizeof(RESPL)) {
memcpy(rsp,string,sizeof(RESPL));
InsVFirst(ptemp,rsp);
address P = Search(*ptemp,rsp->msgno);
if(P!=Nil) { //if ack with same msgno found in ptemp
if(Info(P)->ack == ACK) {
queue->front++; //inc *queue head
if(queue->front == WINDOWSIZE) queue->front = 0;
queue->count--;
}
else { //we have to resend the frame
while(qsend->count==WINDOWSIZE);
qsend->window[qsend->rear] = queue->window[queue->front]; //add it to send queue
qsend->rear++;
if(qsend->rear==WINDOWSIZE) qsend->rear=0;
qsend->count++;
}
address Pdel;
DelAfter(ptemp,&Pdel,Prev(P));
}
}
else error("Cant receive nothing.\n");
}