Advertisement
Guest User

Untitled

a guest
Jan 24th, 2017
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.75 KB | None | 0 0
  1. #include <sys/types.h>
  2. //#include <sys/wait.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <unistd.h>
  7. //#include <netdb.h>
  8. //#include <signal.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. //#include <time.h>
  13. #include <pthread.h>
  14.  
  15. #define SERVER_PORT 1234
  16. #define QUEUE_SIZE 10
  17. #define MAX_THREADS 10 //ile użytkowników
  18. #define SIZEOF_HEADER 70
  19. //rozmiar h. K->S, "TYPE=D ..."; "TYPE=U ..."; "TYPE=L FROM=abcdabcdabcdęążź ..."; "TYPE=M FROM=qwertyuiop1234567890 TO=1qazxsw23edcvfr45tgb SIZE=999999 "
  20. #define SIZEOF_MSG_HEADER 256
  21. //rozmiar h. S->K, "TYPE=U LIST=user1 user2 user3 user4 user5 user6 user7 user8 user9 user10 ..."; "TYPE=W DECI=W ..."; "TYPE=D DECI=W ..."; "TYPE=L DECI=W ..."; "TYPE=M DECI=A ..."
  22. #define SIZEOF_LOGIN 20 //rozmiar loginu bez '\0'
  23. #define SIZEOF_MSG 999999
  24. #define SIZEOF_MSG_BUFF 10
  25.  
  26. /*
  27.  
  28. dostep do pol struktury: (*th_data).pole
  29. NAGŁÓWKI STAŁEJ DŁUGOŚCI:
  30. SIZEOF_HEADER(K1->S) - po każdej istotnej wartości następuje spacja, gdy sizeof()<SIZEOF_HEADER -> ewentualne wypełnienie dowolnymi znakami
  31. SIZEOF_MSG_HEADER(S->K1) analogicznie
  32. POŁĄCZENIE:
  33. tresc headera potwierdzenia połączenia(S->K): "TYPE=C DECI=A ..."
  34. tresc headera odrzucenia połączenia(S->K): "TYPE=C DECI=W ..."
  35. WIADOMOŚCI:
  36. tresc headera wiadomosci(K->S, SIZEOF_HEADER): "TYPE=M FROM=żąęźółśćżą TOTO=abcdabcdabcdabcdabcd SIZE=999999 ..." -> przesłanie headera i wiadomości ->
  37. tresc headera potwierdzenia przesłania wiadomości(S->K): "TYPE=N DECI=A ..."
  38. tresc headera nieprawidlowego przeslania wiadomosci(S->K): "TYPE=N DECI=W ..."
  39. LOGOWANIE:
  40. tresc headera nadania loginu(K->S, SIZEOF_HEADER): "TYPE=L FROM=useruseruseręąęą ..." -> odbiór i przesłanie odpowiedzi ->
  41. tresc headera nieprawidlowego loginu(S->K): "TYPE=L DECI=W ..." -> brak dodania użytkownika do listy; powinno nastąpić ponowne odpytanie przez klienta
  42. tresc headera akceptacji loginu(S->K): "TYPE=L DECI=A ..." -> dodanie użytkownika do listy; powinno nastąpić "zalogowanie"
  43. DISCONNECT:
  44. tresc headera disconnectu(K->S, SIZEOF_HEADER): "TYPE=D ..." - brak kolejnych pakietow
  45. tresc headera nieprawidlowego disconnectu(S->K): "TYPE=D DECI=W ..." -> brak disconnecta
  46. tresc headera akceptacji disconnectu(S->K): "TYPE=D DECI=A ..." -> disconnect
  47. LISTA USERÓW:
  48. tresc headera żądania listy userow(K->S, SIZEOF_HEADER): "TYPE=U ..."
  49. tresc headera listy userow(S->K): "TYPE=U LIST=user1 user2 user3 user4 user5 user6 user7 user8 user9 user10 ..."
  50. ZŁY NAGŁÓWEK:
  51. tresc headera odpowiedzi na zly naglowek(S->K): "TYPE=W DECI=W ..." - użytkownik
  52. OGÓLNA IDEA:
  53. Użytkownik wysyłając header lub header+wiadomość zawsze czeka na odpowiedź serwera, ponieważ zawsze powinien ją otrzymać - czyli nie może wysyłać 2 wiadomości jednocześnie, bo nie będzie wiedział co odebrać - przyda się semafor czy coś.
  54. */
  55.  
  56. //struktura zawierajaca dane, które zostana przekazane do watku
  57.  
  58.  
  59. pthread_mutex_t socket_mutex[MAX_THREADS];
  60. pthread_mutex_t opened_mutex;
  61. pthread_mutex_t usernames_mutex;
  62.  
  63. struct thread_data_t {
  64. struct shared_thread_data_t *shared;
  65. int id;
  66. };
  67.  
  68. struct shared_thread_data_t {
  69. int *connection_socket_descriptor;
  70. int *opened;
  71. char **usernames;
  72. };
  73.  
  74. int minimum(int a, int b) {
  75. if (a < b) return a;
  76. return b;
  77. }
  78.  
  79. int mywrite(int desc, char* msg, size_t sizeoff){
  80. int nowsend, tosend=sizeoff;
  81. while(1) {
  82. nowsend = write(desc, msg, tosend);
  83. if(nowsend < 0) return nowsend;
  84. tosend -= nowsend;
  85. //msg cut begin
  86. msg += nowsend;
  87. if (!tosend) break;
  88. if (!nowsend) break;
  89. }
  90. return sizeoff-tosend;
  91. }
  92.  
  93. int myread(int desc, char* msg, size_t sizeoff){
  94. int nowrcv, torcv=sizeoff;
  95. while(1) {
  96. nowrcv = read(desc, msg, torcv);
  97. if(nowrcv < 0) return nowrcv;
  98. torcv-=nowrcv;
  99. //msg cut begin
  100. msg+=nowrcv;
  101. if(!torcv) break;
  102. if(!nowrcv) break;
  103. }
  104. return sizeoff-torcv;
  105. }
  106.  
  107. //OBSŁUGA USTAWIANIA LOGINU
  108. int loginheader(char* header, struct thread_data_t *th_data, int my_id){
  109. int i;
  110. char login[SIZEOF_LOGIN + 1];
  111. char msg[SIZEOF_MSG_HEADER];
  112. char *header_ptr;
  113. pthread_mutex_lock(&opened_mutex);
  114. pthread_mutex_lock(&usernames_mutex);
  115. printf("Wątek %d: Odebrano zlecenie zmiany loginu\n", my_id);
  116. memset(login, 0, sizeof(login));
  117. header_ptr = strstr(header, "FROM=");
  118. for (i = 0; header_ptr[i + 5] != ' ' && header_ptr[i+5] != '\n'; i++) { //Pobranie loginu z nagłówka
  119. login[i] = header_ptr[i + 5];
  120. }
  121. header_ptr[i + 5] = '\0';
  122. header_ptr += 5;
  123. printf("Wątek %d: Odebrano login: '%s' , len: %ld\n", my_id, login, strlen(login));
  124. for (i = 0; i < MAX_THREADS; i++) { //porównanie loginu z wszystkimi loginami w tabeli i sprawdzenie długości(strcmp dla pustych usernames[i] zwraca 0)
  125. if (th_data->shared->opened[i]) {
  126. if (!strlen(login) || strlen(login) > SIZEOF_LOGIN) break;
  127. if (!strcmp(login, th_data->shared->usernames[i]) && strlen(th_data->shared->usernames[i])) break;
  128. }
  129. }
  130. if (i == MAX_THREADS) { //PRAWIDŁOWY LOGIN -> AKTUALIZACJA LISTY UŻYTKOWNIKÓW -> WYSŁANIE A(CCEPT)
  131. strcpy(th_data->shared->usernames[my_id], header_ptr);
  132. strcpy(msg, "TYPE=L DECI=A ");
  133. pthread_mutex_lock(&socket_mutex[my_id]);
  134. mywrite(th_data->shared->connection_socket_descriptor[my_id], msg, sizeof(msg));
  135. pthread_mutex_unlock(&socket_mutex[my_id]);
  136. printf("Wątek %d: login '%s' zweryfikowany jako prawidłowy i dołączony do listy loginów, wysłano potwierdzenie dołączenia\n",
  137. my_id, login);
  138. } else { //NIEPRAWIDŁOWY LOGIN -> WYSŁANIE W(RONG)
  139. strcpy(msg, "TYPE=L DECI=W ");
  140. pthread_mutex_lock(&socket_mutex[my_id]);
  141. mywrite(th_data->shared->connection_socket_descriptor[my_id], msg, sizeof(msg));
  142. pthread_mutex_unlock(&socket_mutex[my_id]);
  143. printf("Wątek %d: login '%s' zweryfikowany jako nieprawidłowy, wysłano odrzucenie dołączenia\n", my_id,
  144. login);
  145. }
  146. pthread_mutex_unlock(&usernames_mutex);
  147. pthread_mutex_unlock(&opened_mutex);
  148. return 0;
  149. }
  150. //OBSŁUGA PRZESYŁANIA WIADOMOŚCI
  151. int messageheader(char* header, struct thread_data_t *th_data, int my_id){
  152. int i;
  153. char login[SIZEOF_LOGIN + 1];
  154. char msg[SIZEOF_MSG_HEADER];
  155. char *header_ptr;
  156. char sizestr[10];
  157. int size, right_size, received = 0;
  158. char fullmessage[SIZEOF_MSG];
  159.  
  160. printf("Wątek %d: Odebrano zlecenie przesłania wiadomości\n", my_id);
  161. memset(login, 0, sizeof(login)); //Pobranie odbiorcy z nagłówka
  162. header_ptr = strstr(header, "TO=");
  163. for (i = 0; header_ptr[i + 3] != ' '; ++i) login[i] = header_ptr[i + 3];
  164. memset(sizestr, 0, sizeof(sizestr));
  165. header_ptr = strstr(header, "SIZE=");
  166. for (i = 0; header_ptr[i + 5] != ' '; ++i) sizestr[i] = header_ptr[i + 5];
  167. size = atoi(sizestr);
  168. printf("Wątek %d: Odebrano zlecenie przesłania wiadomości do użytkownika o nazwie '%s', rozmiar wiadomości: '%d'\n", my_id, login, size);
  169. strcpy(msg, header); //Przygotowanie headera do przesłania dalej - dodanie bajtów, w celu osiągnięcia poprawnego rozmiaru nagłówka
  170. memset(fullmessage, 0, sizeof(fullmessage)); //wczytywanie wiadomosci o wielkosci size
  171. right_size = size;
  172. header_ptr = fullmessage;
  173. while (received < right_size) {
  174. size = myread(th_data->shared->connection_socket_descriptor[my_id], header_ptr, (size_t) minimum(right_size - received, SIZEOF_MSG_BUFF));
  175. header_ptr += size;
  176. received += size;
  177. if(!size) break;
  178. }
  179. printf("Wątek %d: Odebrano wiadomość o objętości: %d\n", my_id, received);
  180. pthread_mutex_lock(&usernames_mutex);
  181. for (i = 0; i < MAX_THREADS; i++) { //szukanie właściwego użytkownika
  182. if (!strncmp(login, th_data->shared->usernames[i], strlen(login))) { //JEŚLI ZNALAZŁEŚ UŻYTKOWNIKA, TO PRZEŚLIJ MU WIADOMOŚĆ
  183. pthread_mutex_lock(&socket_mutex[i]);
  184. mywrite(th_data->shared->connection_socket_descriptor[i], msg, sizeof(msg)); //wysyłanie nagłówka do odbiorcy
  185. printf("Wątek %d: Wysłano nagłówek wiadomości do użytkownika o id=%d\n", my_id, i);
  186. mywrite(th_data->shared->connection_socket_descriptor[i], fullmessage, (size_t) received); //wysyłanie wiadomości do odbiorcy
  187. printf("Wątek %d: Wysłano wiadomość do użytkownika o id=%d\n", my_id, i);
  188. pthread_mutex_unlock(&socket_mutex[i]);
  189. break;
  190. }
  191. }
  192. pthread_mutex_unlock(&usernames_mutex);
  193. if (i == MAX_THREADS) { //WIADOMOŚĆ NIE ZOSTAŁA WYSŁANA LUB BŁEDNIE WYSŁANA -> WYSŁANIE W(RONG)
  194. printf("Wątek %d: Brak właściwego odbiorcy połączonego z serwerem\n", my_id);
  195. strcpy(msg, "TYPE=N DECI=W ");
  196. pthread_mutex_lock(&socket_mutex[my_id]);
  197. mywrite(th_data->shared->connection_socket_descriptor[my_id], msg, sizeof(msg));
  198. pthread_mutex_unlock(&socket_mutex[my_id]);
  199. printf("Wątek %d: Wysłano pakiet o niepoprawnym wysłaniu wiadomości do nadawcy\n", my_id);
  200. } else { //WIADOMOŚĆ ZOSTAŁA WYSŁANA POPRAWNIE -> WYSŁANIE A(CCEPT)
  201. strcpy(msg, "TYPE=N DECI=A ");
  202. pthread_mutex_lock(&socket_mutex[my_id]);
  203. mywrite(th_data->shared->connection_socket_descriptor[my_id], msg, sizeof(msg));
  204. pthread_mutex_unlock(&socket_mutex[my_id]);
  205. printf("Wątek %d: Wysłano pakiet potwierdzający wysłanie wiadomości do nadawcy\n", my_id);
  206. }
  207. return 0;
  208. }
  209. //OBSŁUGA ŻĄDANIA LISTY UŻYTKOWNIKÓW
  210. int usersheader(char* header, struct thread_data_t *th_data, int my_id){
  211. int i;
  212. char msg[SIZEOF_MSG_HEADER];
  213.  
  214. printf("Wątek %d: Odebrano zlecenie przesłania listy użytkowników\n", my_id);
  215.  
  216. strcpy(msg, "TYPE=U LIST="); //PRZYGOTOWANIE PAKIETU DO WYSŁANIA
  217. pthread_mutex_lock(&usernames_mutex);
  218. for (i = 0; i < MAX_THREADS; i++) {
  219. if (strlen(th_data->shared->usernames[i])) {
  220. strncat(msg, th_data->shared->usernames[i], strlen(th_data->shared->usernames[i]));
  221. strcat(msg, " ");
  222. }
  223. }
  224. pthread_mutex_unlock(&usernames_mutex);
  225. printf("Wątek %d: Przygotowany pakiet: %s\n", my_id, msg);
  226. pthread_mutex_lock(&socket_mutex[my_id]);
  227. mywrite(th_data->shared->connection_socket_descriptor[my_id], msg, sizeof(msg));
  228. pthread_mutex_unlock(&socket_mutex[my_id]);
  229. printf("Wątek %d: Wysłano listę użytkowników\n", my_id);
  230. return 0;
  231. }
  232. //OBSŁUGA NIEPRAWIDŁOWEGO NAGŁÓWKA
  233. int wrongheader(char* header, struct thread_data_t *th_data, int my_id) {
  234. char msg[SIZEOF_MSG_HEADER];
  235. printf("Wątek %d: Odebrano nieprawidłowy nagłówek\n", my_id);
  236. strcpy(msg, "TYPE=W DECI=W ");
  237. pthread_mutex_lock(&socket_mutex[my_id]);
  238. mywrite(th_data->shared->connection_socket_descriptor[my_id], msg, sizeof(msg));
  239. pthread_mutex_unlock(&socket_mutex[my_id]);
  240. printf("Wątek %d: Wysłano informacje o nieprawidłowym nagłówku\n", my_id);
  241. return 0;
  242. }
  243.  
  244. //funkcja opisujaca zachowanie watku - mu// si przyjmowac argument typu (void *) i zwracac (void *)
  245. void *ThreadBehavior(void *t_data) {
  246. struct thread_data_t *th_data = (struct thread_data_t *) t_data;
  247. char header[SIZEOF_HEADER];
  248. char *header_ptr;
  249. int check;
  250. int diff = 0;
  251. int my_id = th_data->id;
  252.  
  253. printf("watek: id=%d\n", my_id);
  254. while (1) {
  255. memset(header, 0, sizeof(header));
  256. check = SIZEOF_HEADER;
  257. header_ptr = header;
  258. while (check > 0) { //WCZYTYWANIE NAGŁÓWKA DO header[]
  259. diff = (int) myread(th_data->shared->connection_socket_descriptor[my_id], header_ptr, check);
  260. check -= diff;
  261. header_ptr += diff;
  262. if (!diff) break;
  263. }
  264. if (!diff) break;
  265. printf("Wątek %d: Odebrano nagłówek o objętości: %ld\n", my_id, sizeof(header));
  266. if (!strncmp(header, "TYPE=L", 6)) { //OBSŁUGA PRZYPISANIA LOGINU
  267. if(loginheader(header, th_data, my_id) < 0) {
  268. fprintf(stderr, "serwer: Błąd przy próbie ustalenia loginu\n");
  269. exit(1);
  270. }
  271. }
  272. else if (!strncmp(header, "TYPE=M", 6)) { //OBSŁUGA PRZESYŁANIA WIADOMOŚCI
  273. if(messageheader(header, th_data, my_id) < 0) {
  274. fprintf(stderr, "serwer: Błąd przy próbie przesłania wiadomości\n");
  275. exit(1);
  276. }
  277. }
  278. else if (!strncmp(header, "TYPE=U", 6)) { //OBSŁUGA PRZESYŁANIA LISTY UŻYTKOWNIKÓW
  279. if(usersheader(header, th_data, my_id) < 0) {
  280. fprintf(stderr, "serwer: Błąd przy próbie przesłania listy\n");
  281. exit(1);
  282. }
  283. }
  284. else { //OBSŁUGA ZŁEGO NAGŁÓWKA
  285. if(wrongheader(header, th_data, my_id) < 0) {
  286. fprintf(stderr, "serwer: Błąd przy próbie obsługi złego nagłówka\n");
  287. exit(1);
  288. }
  289. }
  290. }
  291. printf("Wątek %d: Następuje rozłączenie użytkownika\n", my_id);
  292. pthread_mutex_lock(&opened_mutex);
  293. pthread_mutex_lock(&usernames_mutex);
  294. th_data->shared->opened[my_id] = 0;
  295. strcpy(th_data->shared->usernames[my_id],""); //Usunięcie użytkownika z listy
  296. close(th_data->shared->connection_socket_descriptor[my_id]);
  297. pthread_mutex_unlock(&usernames_mutex);
  298. pthread_mutex_unlock(&opened_mutex);
  299. pthread_exit(NULL);
  300. }
  301.  
  302. int main(int argc, char *argv[]) {
  303. int *opened;
  304. char **usernames;
  305. int i;
  306. int server_socket_descriptor;
  307. int create_result = 0;
  308. int *connection_socket_descriptor;
  309. int checksum;
  310. int tymczasowy_deskryptor;
  311. char msg_conn[SIZEOF_MSG_HEADER];
  312. int* tablica;
  313. tablica = malloc(MAX_THREADS * sizeof(int));
  314.  
  315. //alokacja współdzielonych struktur danych
  316.  
  317. connection_socket_descriptor = malloc(MAX_THREADS * sizeof(int));
  318. opened = malloc(MAX_THREADS * sizeof(int));
  319. usernames = (char **) malloc(MAX_THREADS * sizeof(char *));
  320. for (i = 0; i < MAX_THREADS; i++)
  321. usernames[i] = (char *) malloc((SIZEOF_LOGIN + 1) * sizeof(char));
  322. pthread_t thread[5];
  323. int bind_result;
  324. int listen_result;
  325. char reuse_addr_val = 1;
  326. struct sockaddr_in server_address;
  327.  
  328. //inicjalizacja mutexów
  329.  
  330. for (i = 0; i < MAX_THREADS; i++) {
  331. pthread_mutex_init(&socket_mutex[i], NULL);
  332. tablica[i]=i;
  333. }
  334. pthread_mutex_init(&opened_mutex, NULL);
  335. pthread_mutex_init(&usernames_mutex, NULL);
  336.  
  337. //inicjalizacja gniazda serwera
  338.  
  339. memset(&server_address, 0, sizeof(struct sockaddr));
  340. server_address.sin_family = AF_INET;
  341. server_address.sin_addr.s_addr = htonl(INADDR_ANY);
  342. server_address.sin_port = htons(SERVER_PORT);
  343.  
  344. server_socket_descriptor = socket(AF_INET, SOCK_STREAM, 0);
  345. if (server_socket_descriptor < 0) {
  346. fprintf(stderr, "%s: Błąd przy próbie utworzenia gniazda..\n", argv[0]);
  347. exit(1);
  348. }
  349. setsockopt(server_socket_descriptor, SOL_SOCKET, SO_REUSEADDR, &reuse_addr_val, sizeof(reuse_addr_val));
  350.  
  351. bind_result = bind(server_socket_descriptor, (struct sockaddr *) &server_address, sizeof(struct sockaddr));
  352. if (bind_result < 0) {
  353. fprintf(stderr, "%s: Błąd przy próbie dowiązania adresu IP i numeru portu do gniazda.\n", argv[0]);
  354. exit(1);
  355. }
  356.  
  357. listen_result = listen(server_socket_descriptor, QUEUE_SIZE);
  358. if (listen_result < 0) {
  359. fprintf(stderr, "%s: Błąd przy próbie ustawienia wielkości kolejki.\n", argv[0]);
  360. exit(1);
  361. }
  362.  
  363.  
  364. for (i = 0; i < MAX_THREADS; i++) {
  365. opened[i] = 0;
  366. }
  367.  
  368. struct shared_thread_data_t s_data;
  369. s_data.opened = opened;
  370. s_data.connection_socket_descriptor = connection_socket_descriptor;
  371. s_data.usernames = usernames;
  372.  
  373. while (1) {
  374. printf("Serwer: czekam na użytkownika\n");
  375. tymczasowy_deskryptor = accept(server_socket_descriptor, NULL, NULL);
  376. if (tymczasowy_deskryptor < 0) {
  377. fprintf(stderr, "%s: Błąd przy próbie utworzenia gniazda dla połączenia.\n", argv[0]);
  378. exit(1);
  379. }
  380. pthread_mutex_lock(&opened_mutex);
  381. checksum=0;
  382. for (i = 0; i < MAX_THREADS; i++) { //znajdz pierwszy wolny watek
  383. if (opened[i] == 0) {
  384. checksum = 1;
  385. break;
  386. }
  387. }
  388. if (checksum) { //ZNALEZIONO PUSTY SLOT
  389. struct thread_data_t *t_data;
  390. t_data = malloc(sizeof(struct thread_data_t));
  391. t_data->shared = &s_data;
  392. printf("wybrane i: %d\n", i);
  393. t_data->id = i;
  394. connection_socket_descriptor[i] = tymczasowy_deskryptor;
  395. create_result = pthread_create(&thread[i], NULL, ThreadBehavior, (void *) &t_data);
  396. if (create_result) {
  397. fprintf(stderr, "%s: Błąd przy próbie utworzenia wątku, kod błędu: %d\n", argv[0], create_result);
  398. exit(1);
  399. }
  400. opened[i] = 1;
  401. strcpy(msg_conn, "TYPE=C DECI=A ");
  402. pthread_mutex_lock(&socket_mutex[i]);
  403. mywrite(connection_socket_descriptor[i], msg_conn, sizeof(msg_conn));
  404. pthread_mutex_unlock(&socket_mutex[i]);
  405. printf("Serwer: użytkownik %d podłączył się\n", i);
  406. }
  407. else { //NIE ZNALEZIONO PUSTEGO SLOTA
  408. strcpy(msg_conn, "TYPE=C DECI=W ");
  409. mywrite(tymczasowy_deskryptor, msg_conn, sizeof(msg_conn));
  410. close(tymczasowy_deskryptor);
  411. printf("Serwer: brak miejsca dla kolejnego użytkownika\n");
  412.  
  413. }
  414. pthread_mutex_unlock(&opened_mutex);
  415. }
  416. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement