masz pare ladnych problemow.. przede wszystkim to ze klienci pozniej sie nie moga podlaczyc jest efektem tego, ze socket na ktorym serve_main slucha zostaje zamkniety. dosc znaczacy fakt, ze Ty nigdzie w kodzie go nie zamykasz ;) tak wiec proces serve_main musial zdechnac. za ktoryms odpaleniem serwer wyplul z siebie informacje informacje z glibc ze free() chcialo zdealokowac nieprawidlowy wskaznik - masz problem.. obawiam sie ze tego akurat nie znajde. z cala pewnoscia masz tez blad w owym sighandlerze czyszczacym zombie po procesach klientow - przeciez ta funkcja zawiesza wykonanie na tak dlugo jak istnieja dzieci! i to watek systemowy zawiesza.. takze send i recv sa wykonywane w sposob budzacy watpliwosci.. ale to Ci komentarz w kodzie zostawilem
co do crash'a serve_main: rzecz dzieje sie w if(buf[0]==CMD_QUIT). po odpaleniu serwera i jednego klienta na raz - wszystko jest ok. po odpaleniu serwera i dwoch klientow: jak pierwszy klient sie wyloguje, to jakis watek zawisa na sighandlerze i ten ifik w ogóle sie nie wykonuje. po wylogowaniu sie drugiego klienta, inny watek wchodzi w sighandler, zwalnia ostatnie dziecko, przez co oba watki wychodza i if sie wykonuje. wskazuje to na fakt, ze ten pierwszy watek byl glownym watkiem procesu serve_main ktory siedzial sobie w jakiejs funkcji systemowej i zostal uzyty do wywolania sygnalu.. a ten drugi watek (najprawdopodobniej byl to caly czas ten sam, zablokowany w wait()). tak wiec jak 'drugi' watek odblokowal wszystko, to ow 'pierwszy' sie zwolnil, powrocil do wykonywania kodu tego ifika i dotarl do SendToAll() i ... juz z niego nie wyszedl. dalsze sledzenie pokazuje, ze proces wchodzi do SendToAll, przechodzi przez if'a sprawdzajacego liste (btw: a to tlumaczy czemu dla jednego usera dziala: lista jest pusta i nie wchodzi w tego if'a), dochodzi do send i sie na nim wywala. wniosek: albo send sie wewnetrzenie wywala z jakeigos powodu dziwnego, albo tmp, albo buf jest walniety. niestety, oba sa ustawione na nie-zero i maja prawidlowa zawartosc. stad wniosek ze musial sie wywalic send jakos wewnetrznie. strzelilem ze chodzi o to blokowanie watkow w sighandlerze - "poprawilem" go i ot niespodzianka, juz mozna sie logowac i wylogowywac dowoli.. przynajmniej na moim kompie :) kod Ci wysylam mailem, tylko serwer.c bo tylko on sie zmienil. generalnie jako dobra regule pamietaj, aby nigdy nie blokowac watkow jesli nie musisz. a juz przenigdy - jesli nie wiesz co to jest za watek, a tak to wlasnie jest z sygnalami ktore przylaza w losowych momentach i aktualnie wykonywany watek je odbiera.. ogolnie rzecz biorac musisz duuuzooo poprawic.. klient tez mi segfaulty wywalal wedlug swojego widzimisie..
btw: musisz to pisac w C? przejdz na C++, uporzadkuj.. zreszta, mozesz byc w C, ale uporzadkuj koniecznie, funkcje jakies powydzielaj i powywalaj do innych plikow, zeby bloki kodu byly krotsze.. w tej chwili kod ma przejrzystosc moze nie makaronu ale porzadnie zabielonej pomidorowej, a powinien byc klarowny bulion :)
Wspomne jeszcze tylko nachalnie o tym recv/send:
One zwracaja ilosc bajtow ktore rzeczywiscie zostaja wyslane/odebrane. To ze dasz recv(sock, buf, 30, 0); wcale-a-wcale nie oznacza ze musi sie wyslac te 30 bajtow. Recv moze Ci zwrocic np. 5 i to bedzie oznaczac ze pozostalych 25 bajtow NIE WYSLAL i powinies odpalic: recv(sock, buf+5, 30-5, 0);. Specjalnie tak pisze zeby bylo jasne jak wokol tego petle zrobic :) Send dziala w identyczny sposob. Poza tym obie moga zwrocic wartosc -1 oznaczajaca blad - np. zerwanie polaczenia. To tez nalezy sprawdzac, zwlazcza jak sobie zapetlisz jak wspomnialem przed chwila, bo dodawanie -1 do aktualnej pozycji w buforze to nie dobry pomysl, a i jak bedzie -1 nalezaloby przerwac operacje i sie jakos wydostac, a przynajmniej logmsga zapisac..
a propoS logow.. zapomnialem dodac ze to bardzo dobrze ze je robisz. niestety dzialaja tylko i wylacznie te w procesie glownym, tzn serve_main. logowanie w procesach obslugujacych klientow nie dziala. Najprawdopodobniej dlatego, ze aby zakonczyc owe proces uzywasz radosnie exit(0) ani nie flushujac, ani nie zamykajac pliku. I caly outbuffer leci w hiperprzestrzen zamiast na dysk.